aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutiny.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/rcutiny.c')
-rw-r--r--kernel/rcutiny.c71
1 files changed, 58 insertions, 13 deletions
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index d806735342ac..86eef29cdfb2 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -59,8 +59,15 @@ int rcu_scheduler_active __read_mostly;
59EXPORT_SYMBOL_GPL(rcu_scheduler_active); 59EXPORT_SYMBOL_GPL(rcu_scheduler_active);
60#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ 60#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
61 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
62/* Forward declarations for rcutiny_plugin.h. */ 68/* Forward declarations for rcutiny_plugin.h. */
63static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp); 69static void rcu_process_callbacks(struct rcu_ctrlblk *rcp);
70static int rcu_cbs(void *arg);
64static void __call_rcu(struct rcu_head *head, 71static void __call_rcu(struct rcu_head *head,
65 void (*func)(struct rcu_head *rcu), 72 void (*func)(struct rcu_head *rcu),
66 struct rcu_ctrlblk *rcp); 73 struct rcu_ctrlblk *rcp);
@@ -123,7 +130,7 @@ void rcu_sched_qs(int cpu)
123{ 130{
124 if (rcu_qsctr_help(&rcu_sched_ctrlblk) + 131 if (rcu_qsctr_help(&rcu_sched_ctrlblk) +
125 rcu_qsctr_help(&rcu_bh_ctrlblk)) 132 rcu_qsctr_help(&rcu_bh_ctrlblk))
126 raise_softirq(RCU_SOFTIRQ); 133 invoke_rcu_cbs();
127} 134}
128 135
129/* 136/*
@@ -132,7 +139,7 @@ void rcu_sched_qs(int cpu)
132void rcu_bh_qs(int cpu) 139void rcu_bh_qs(int cpu)
133{ 140{
134 if (rcu_qsctr_help(&rcu_bh_ctrlblk)) 141 if (rcu_qsctr_help(&rcu_bh_ctrlblk))
135 raise_softirq(RCU_SOFTIRQ); 142 invoke_rcu_cbs();
136} 143}
137 144
138/* 145/*
@@ -152,10 +159,10 @@ void rcu_check_callbacks(int cpu, int user)
152} 159}
153 160
154/* 161/*
155 * Helper function for rcu_process_callbacks() that operates on the 162 * Invoke the RCU callbacks on the specified rcu_ctrlkblk structure
156 * specified rcu_ctrlkblk structure. 163 * whose grace period has elapsed.
157 */ 164 */
158static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) 165static void rcu_process_callbacks(struct rcu_ctrlblk *rcp)
159{ 166{
160 struct rcu_head *next, *list; 167 struct rcu_head *next, *list;
161 unsigned long flags; 168 unsigned long flags;
@@ -180,19 +187,52 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
180 next = list->next; 187 next = list->next;
181 prefetch(next); 188 prefetch(next);
182 debug_rcu_head_unqueue(list); 189 debug_rcu_head_unqueue(list);
190 local_bh_disable();
183 list->func(list); 191 list->func(list);
192 local_bh_enable();
184 list = next; 193 list = next;
185 } 194 }
186} 195}
187 196
188/* 197/*
189 * Invoke any callbacks whose grace period has completed. 198 * This kthread invokes RCU callbacks whose grace periods have
199 * elapsed. It is awakened as needed, and takes the place of the
200 * RCU_SOFTIRQ that was used previously for this purpose.
201 * This is a kthread, but it is never stopped, at least not until
202 * the system goes down.
203 */
204static int rcu_cbs(void *arg)
205{
206 unsigned long work;
207 unsigned long flags;
208
209 for (;;) {
210 wait_event(rcu_cbs_wq, have_rcu_cbs != 0);
211 local_irq_save(flags);
212 work = have_rcu_cbs;
213 have_rcu_cbs = 0;
214 local_irq_restore(flags);
215 if (work) {
216 rcu_process_callbacks(&rcu_sched_ctrlblk);
217 rcu_process_callbacks(&rcu_bh_ctrlblk);
218 rcu_preempt_process_callbacks();
219 }
220 }
221
222 return 0; /* Not reached, but needed to shut gcc up. */
223}
224
225/*
226 * Wake up rcu_cbs() to process callbacks now eligible for invocation.
190 */ 227 */
191static void rcu_process_callbacks(struct softirq_action *unused) 228static void invoke_rcu_cbs(void)
192{ 229{
193 __rcu_process_callbacks(&rcu_sched_ctrlblk); 230 unsigned long flags;
194 __rcu_process_callbacks(&rcu_bh_ctrlblk); 231
195 rcu_preempt_process_callbacks(); 232 local_irq_save(flags);
233 have_rcu_cbs = 1;
234 wake_up(&rcu_cbs_wq);
235 local_irq_restore(flags);
196} 236}
197 237
198/* 238/*
@@ -282,7 +322,12 @@ void rcu_barrier_sched(void)
282} 322}
283EXPORT_SYMBOL_GPL(rcu_barrier_sched); 323EXPORT_SYMBOL_GPL(rcu_barrier_sched);
284 324
285void __init rcu_init(void) 325/*
326 * Spawn the kthread that invokes RCU callbacks.
327 */
328static int __init rcu_spawn_kthreads(void)
286{ 329{
287 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); 330 rcu_cbs_task = kthread_run(rcu_cbs, NULL, "rcu_cbs");
331 return 0;
288} 332}
333early_initcall(rcu_spawn_kthreads);