Skip to content

Commit 5f6130f

Browse files
Lai Jiangshanpaulmck
authored andcommitted
tiny_rcu: Directly force QS when call_rcu_[bh|sched]() on idle_task
For RCU in UP, context-switch = QS = GP, thus we can force a context-switch when any call_rcu_[bh|sched]() is happened on idle_task. After doing so, rcu_idle/irq_enter/exit() are useless, so we can simply make these functions empty. More important, this change does not change the functionality logically. Note: raise_softirq(RCU_SOFTIRQ)/rcu_sched_qs() in rcu_idle_enter() and outmost rcu_irq_exit() will have to wake up the ksoftirqd (due to in_interrupt() == 0). Before this patch After this patch: call_rcu_sched() in idle; call_rcu_sched() in idle set resched do other stuffs; do other stuffs outmost rcu_irq_exit() outmost rcu_irq_exit() (empty function) (or rcu_idle_enter()) (or rcu_idle_enter(), also empty function) start to resched. (see above) rcu_sched_qs() rcu_sched_qs() QS,and GP and advance cb QS,and GP and advance cb wake up the ksoftirqd wake up the ksoftirqd set resched resched to ksoftirqd (or other) resched to ksoftirqd (or other) These two code patches are almost the same. Size changed after patched: size kernel/rcu/tiny-old.o kernel/rcu/tiny-patched.o text data bss dec hex filename 3449 206 8 3663 e4f kernel/rcu/tiny-old.o 2406 144 8 2558 9fe kernel/rcu/tiny-patched.o Signed-off-by: Lai Jiangshan <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]>
1 parent ac59853 commit 5f6130f

File tree

4 files changed

+14
-99
lines changed

4 files changed

+14
-99
lines changed

kernel/rcu/rcu.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,10 @@ int rcu_jiffies_till_stall_check(void);
137137

138138
void rcu_early_boot_tests(void);
139139

140+
/*
141+
* This function really isn't for public consumption, but RCU is special in
142+
* that context switches can allow the state machine to make progress.
143+
*/
144+
extern void resched_cpu(int cpu);
145+
140146
#endif /* __LINUX_RCU_H */

kernel/rcu/tiny.c

Lines changed: 7 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -47,54 +47,14 @@ static void __call_rcu(struct rcu_head *head,
4747
void (*func)(struct rcu_head *rcu),
4848
struct rcu_ctrlblk *rcp);
4949

50-
static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
51-
5250
#include "tiny_plugin.h"
5351

54-
/* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcu/tree.c. */
55-
static void rcu_idle_enter_common(long long newval)
56-
{
57-
if (newval) {
58-
RCU_TRACE(trace_rcu_dyntick(TPS("--="),
59-
rcu_dynticks_nesting, newval));
60-
rcu_dynticks_nesting = newval;
61-
return;
62-
}
63-
RCU_TRACE(trace_rcu_dyntick(TPS("Start"),
64-
rcu_dynticks_nesting, newval));
65-
if (IS_ENABLED(CONFIG_RCU_TRACE) && !is_idle_task(current)) {
66-
struct task_struct *idle __maybe_unused = idle_task(smp_processor_id());
67-
68-
RCU_TRACE(trace_rcu_dyntick(TPS("Entry error: not idle task"),
69-
rcu_dynticks_nesting, newval));
70-
ftrace_dump(DUMP_ALL);
71-
WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s",
72-
current->pid, current->comm,
73-
idle->pid, idle->comm); /* must be idle task! */
74-
}
75-
rcu_sched_qs(); /* implies rcu_bh_inc() */
76-
barrier();
77-
rcu_dynticks_nesting = newval;
78-
}
79-
8052
/*
8153
* Enter idle, which is an extended quiescent state if we have fully
82-
* entered that mode (i.e., if the new value of dynticks_nesting is zero).
54+
* entered that mode.
8355
*/
8456
void rcu_idle_enter(void)
8557
{
86-
unsigned long flags;
87-
long long newval;
88-
89-
local_irq_save(flags);
90-
WARN_ON_ONCE((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) == 0);
91-
if ((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) ==
92-
DYNTICK_TASK_NEST_VALUE)
93-
newval = 0;
94-
else
95-
newval = rcu_dynticks_nesting - DYNTICK_TASK_NEST_VALUE;
96-
rcu_idle_enter_common(newval);
97-
local_irq_restore(flags);
9858
}
9959
EXPORT_SYMBOL_GPL(rcu_idle_enter);
10060

@@ -103,55 +63,14 @@ EXPORT_SYMBOL_GPL(rcu_idle_enter);
10363
*/
10464
void rcu_irq_exit(void)
10565
{
106-
unsigned long flags;
107-
long long newval;
108-
109-
local_irq_save(flags);
110-
newval = rcu_dynticks_nesting - 1;
111-
WARN_ON_ONCE(newval < 0);
112-
rcu_idle_enter_common(newval);
113-
local_irq_restore(flags);
11466
}
11567
EXPORT_SYMBOL_GPL(rcu_irq_exit);
11668

117-
/* Common code for rcu_idle_exit() and rcu_irq_enter(), see kernel/rcu/tree.c. */
118-
static void rcu_idle_exit_common(long long oldval)
119-
{
120-
if (oldval) {
121-
RCU_TRACE(trace_rcu_dyntick(TPS("++="),
122-
oldval, rcu_dynticks_nesting));
123-
return;
124-
}
125-
RCU_TRACE(trace_rcu_dyntick(TPS("End"), oldval, rcu_dynticks_nesting));
126-
if (IS_ENABLED(CONFIG_RCU_TRACE) && !is_idle_task(current)) {
127-
struct task_struct *idle __maybe_unused = idle_task(smp_processor_id());
128-
129-
RCU_TRACE(trace_rcu_dyntick(TPS("Exit error: not idle task"),
130-
oldval, rcu_dynticks_nesting));
131-
ftrace_dump(DUMP_ALL);
132-
WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s",
133-
current->pid, current->comm,
134-
idle->pid, idle->comm); /* must be idle task! */
135-
}
136-
}
137-
13869
/*
13970
* Exit idle, so that we are no longer in an extended quiescent state.
14071
*/
14172
void rcu_idle_exit(void)
14273
{
143-
unsigned long flags;
144-
long long oldval;
145-
146-
local_irq_save(flags);
147-
oldval = rcu_dynticks_nesting;
148-
WARN_ON_ONCE(rcu_dynticks_nesting < 0);
149-
if (rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK)
150-
rcu_dynticks_nesting += DYNTICK_TASK_NEST_VALUE;
151-
else
152-
rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
153-
rcu_idle_exit_common(oldval);
154-
local_irq_restore(flags);
15574
}
15675
EXPORT_SYMBOL_GPL(rcu_idle_exit);
15776

@@ -160,15 +79,6 @@ EXPORT_SYMBOL_GPL(rcu_idle_exit);
16079
*/
16180
void rcu_irq_enter(void)
16281
{
163-
unsigned long flags;
164-
long long oldval;
165-
166-
local_irq_save(flags);
167-
oldval = rcu_dynticks_nesting;
168-
rcu_dynticks_nesting++;
169-
WARN_ON_ONCE(rcu_dynticks_nesting == 0);
170-
rcu_idle_exit_common(oldval);
171-
local_irq_restore(flags);
17282
}
17383
EXPORT_SYMBOL_GPL(rcu_irq_enter);
17484

@@ -179,7 +89,7 @@ EXPORT_SYMBOL_GPL(rcu_irq_enter);
17989
*/
18090
bool notrace __rcu_is_watching(void)
18191
{
182-
return rcu_dynticks_nesting;
92+
return true;
18393
}
18494
EXPORT_SYMBOL(__rcu_is_watching);
18595

@@ -347,6 +257,11 @@ static void __call_rcu(struct rcu_head *head,
347257
rcp->curtail = &head->next;
348258
RCU_TRACE(rcp->qlen++);
349259
local_irq_restore(flags);
260+
261+
if (unlikely(is_idle_task(current))) {
262+
/* force scheduling for rcu_sched_qs() */
263+
resched_cpu(0);
264+
}
350265
}
351266

352267
/*

kernel/rcu/tiny_plugin.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ static void check_cpu_stall(struct rcu_ctrlblk *rcp)
147147
js = ACCESS_ONCE(rcp->jiffies_stall);
148148
if (*rcp->curtail && ULONG_CMP_GE(j, js)) {
149149
pr_err("INFO: %s stall on CPU (%lu ticks this GP) idle=%llx (t=%lu jiffies q=%ld)\n",
150-
rcp->name, rcp->ticks_this_gp, rcu_dynticks_nesting,
150+
rcp->name, rcp->ticks_this_gp, DYNTICK_TASK_EXIT_IDLE,
151151
jiffies - rcp->gp_start, rcp->qlen);
152152
dump_stack();
153153
}

kernel/rcu/tree.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -934,12 +934,6 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp,
934934
}
935935
}
936936

937-
/*
938-
* This function really isn't for public consumption, but RCU is special in
939-
* that context switches can allow the state machine to make progress.
940-
*/
941-
extern void resched_cpu(int cpu);
942-
943937
/*
944938
* Return true if the specified CPU has passed through a quiescent
945939
* state by virtue of being in or having passed through an dynticks

0 commit comments

Comments
 (0)