aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutiny.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/rcutiny.c')
-rw-r--r--kernel/rcutiny.c66
1 files changed, 26 insertions, 40 deletions
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index 86eef29cdfb2..93d166582cbb 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -36,38 +36,16 @@
36#include <linux/time.h> 36#include <linux/time.h>
37#include <linux/cpu.h> 37#include <linux/cpu.h>
38 38
39/* Global control variables for rcupdate callback mechanism. */ 39/* Controls for rcu_kthread() kthread, replacing RCU_SOFTIRQ used previously. */
40struct rcu_ctrlblk { 40static struct task_struct *rcu_kthread_task;
41 struct rcu_head *rcucblist; /* List of pending callbacks (CBs). */ 41static DECLARE_WAIT_QUEUE_HEAD(rcu_kthread_wq);
42 struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ 42static unsigned long have_rcu_kthread_work;
43 struct rcu_head **curtail; /* ->next pointer of last CB. */ 43static void invoke_rcu_kthread(void);
44};
45
46/* Definition for rcupdate control block. */
47static struct rcu_ctrlblk rcu_sched_ctrlblk = {
48 .donetail = &rcu_sched_ctrlblk.rcucblist,
49 .curtail = &rcu_sched_ctrlblk.rcucblist,
50};
51
52static struct rcu_ctrlblk rcu_bh_ctrlblk = {
53 .donetail = &rcu_bh_ctrlblk.rcucblist,
54 .curtail = &rcu_bh_ctrlblk.rcucblist,
55};
56
57#ifdef CONFIG_DEBUG_LOCK_ALLOC
58int rcu_scheduler_active __read_mostly;
59EXPORT_SYMBOL_GPL(rcu_scheduler_active);
60#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
61
62/* Controls for rcu_cbs() kthread, replacing RCU_SOFTIRQ used previously. */
63static struct task_struct *rcu_cbs_task;
64static DECLARE_WAIT_QUEUE_HEAD(rcu_cbs_wq);
65static unsigned long have_rcu_cbs;
66static void invoke_rcu_cbs(void);
67 44
68/* Forward declarations for rcutiny_plugin.h. */ 45/* Forward declarations for rcutiny_plugin.h. */
46struct rcu_ctrlblk;
69static void rcu_process_callbacks(struct rcu_ctrlblk *rcp); 47static void rcu_process_callbacks(struct rcu_ctrlblk *rcp);
70static int rcu_cbs(void *arg); 48static int rcu_kthread(void *arg);
71static void __call_rcu(struct rcu_head *head, 49static void __call_rcu(struct rcu_head *head,
72 void (*func)(struct rcu_head *rcu), 50 void (*func)(struct rcu_head *rcu),
73 struct rcu_ctrlblk *rcp); 51 struct rcu_ctrlblk *rcp);
@@ -130,7 +108,7 @@ void rcu_sched_qs(int cpu)
130{ 108{
131 if (rcu_qsctr_help(&rcu_sched_ctrlblk) + 109 if (rcu_qsctr_help(&rcu_sched_ctrlblk) +
132 rcu_qsctr_help(&rcu_bh_ctrlblk)) 110 rcu_qsctr_help(&rcu_bh_ctrlblk))
133 invoke_rcu_cbs(); 111 invoke_rcu_kthread();
134} 112}
135 113
136/* 114/*
@@ -139,7 +117,7 @@ void rcu_sched_qs(int cpu)
139void rcu_bh_qs(int cpu) 117void rcu_bh_qs(int cpu)
140{ 118{
141 if (rcu_qsctr_help(&rcu_bh_ctrlblk)) 119 if (rcu_qsctr_help(&rcu_bh_ctrlblk))
142 invoke_rcu_cbs(); 120 invoke_rcu_kthread();
143} 121}
144 122
145/* 123/*
@@ -201,37 +179,41 @@ static void rcu_process_callbacks(struct rcu_ctrlblk *rcp)
201 * This is a kthread, but it is never stopped, at least not until 179 * This is a kthread, but it is never stopped, at least not until
202 * the system goes down. 180 * the system goes down.
203 */ 181 */
204static int rcu_cbs(void *arg) 182static int rcu_kthread(void *arg)
205{ 183{
206 unsigned long work; 184 unsigned long work;
185 unsigned long morework;
207 unsigned long flags; 186 unsigned long flags;
208 187
209 for (;;) { 188 for (;;) {
210 wait_event(rcu_cbs_wq, have_rcu_cbs != 0); 189 wait_event(rcu_kthread_wq, have_rcu_kthread_work != 0);
190 morework = rcu_boost();
211 local_irq_save(flags); 191 local_irq_save(flags);
212 work = have_rcu_cbs; 192 work = have_rcu_kthread_work;
213 have_rcu_cbs = 0; 193 have_rcu_kthread_work = morework;
214 local_irq_restore(flags); 194 local_irq_restore(flags);
215 if (work) { 195 if (work) {
216 rcu_process_callbacks(&rcu_sched_ctrlblk); 196 rcu_process_callbacks(&rcu_sched_ctrlblk);
217 rcu_process_callbacks(&rcu_bh_ctrlblk); 197 rcu_process_callbacks(&rcu_bh_ctrlblk);
218 rcu_preempt_process_callbacks(); 198 rcu_preempt_process_callbacks();
219 } 199 }
200 schedule_timeout_interruptible(1); /* Leave CPU for others. */
220 } 201 }
221 202
222 return 0; /* Not reached, but needed to shut gcc up. */ 203 return 0; /* Not reached, but needed to shut gcc up. */
223} 204}
224 205
225/* 206/*
226 * Wake up rcu_cbs() to process callbacks now eligible for invocation. 207 * Wake up rcu_kthread() to process callbacks now eligible for invocation
208 * or to boost readers.
227 */ 209 */
228static void invoke_rcu_cbs(void) 210static void invoke_rcu_kthread(void)
229{ 211{
230 unsigned long flags; 212 unsigned long flags;
231 213
232 local_irq_save(flags); 214 local_irq_save(flags);
233 have_rcu_cbs = 1; 215 have_rcu_kthread_work = 1;
234 wake_up(&rcu_cbs_wq); 216 wake_up(&rcu_kthread_wq);
235 local_irq_restore(flags); 217 local_irq_restore(flags);
236} 218}
237 219
@@ -327,7 +309,11 @@ EXPORT_SYMBOL_GPL(rcu_barrier_sched);
327 */ 309 */
328static int __init rcu_spawn_kthreads(void) 310static int __init rcu_spawn_kthreads(void)
329{ 311{
330 rcu_cbs_task = kthread_run(rcu_cbs, NULL, "rcu_cbs"); 312 struct sched_param sp;
313
314 rcu_kthread_task = kthread_run(rcu_kthread, NULL, "rcu_kthread");
315 sp.sched_priority = RCU_BOOST_PRIO;
316 sched_setscheduler_nocheck(rcu_kthread_task, SCHED_FIFO, &sp);
331 return 0; 317 return 0;
332} 318}
333early_initcall(rcu_spawn_kthreads); 319early_initcall(rcu_spawn_kthreads);