|
@@ -245,6 +245,13 @@ static void show_tiny_preempt_stats(struct seq_file *m)
|
|
|
|
|
|
#include "rtmutex_common.h"
|
|
|
|
|
|
+#define RCU_BOOST_PRIO CONFIG_RCU_BOOST_PRIO
|
|
|
+
|
|
|
+/* Controls for rcu_kthread() kthread. */
|
|
|
+static struct task_struct *rcu_kthread_task;
|
|
|
+static DECLARE_WAIT_QUEUE_HEAD(rcu_kthread_wq);
|
|
|
+static unsigned long have_rcu_kthread_work;
|
|
|
+
|
|
|
/*
|
|
|
* Carry out RCU priority boosting on the task indicated by ->boost_tasks,
|
|
|
* and advance ->boost_tasks to the next task in the ->blkd_tasks list.
|
|
@@ -332,7 +339,7 @@ static int rcu_initiate_boost(void)
|
|
|
if (rcu_preempt_ctrlblk.exp_tasks == NULL)
|
|
|
rcu_preempt_ctrlblk.boost_tasks =
|
|
|
rcu_preempt_ctrlblk.gp_tasks;
|
|
|
- invoke_rcu_kthread();
|
|
|
+ invoke_rcu_callbacks();
|
|
|
} else
|
|
|
RCU_TRACE(rcu_initiate_boost_trace());
|
|
|
return 1;
|
|
@@ -350,14 +357,6 @@ static void rcu_preempt_boost_start_gp(void)
|
|
|
|
|
|
#else /* #ifdef CONFIG_RCU_BOOST */
|
|
|
|
|
|
-/*
|
|
|
- * If there is no RCU priority boosting, we don't boost.
|
|
|
- */
|
|
|
-static int rcu_boost(void)
|
|
|
-{
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* If there is no RCU priority boosting, we don't initiate boosting,
|
|
|
* but we do indicate whether there are blocked readers blocking the
|
|
@@ -425,7 +424,7 @@ static void rcu_preempt_cpu_qs(void)
|
|
|
|
|
|
/* If there are done callbacks, cause them to be invoked. */
|
|
|
if (*rcu_preempt_ctrlblk.rcb.donetail != NULL)
|
|
|
- invoke_rcu_kthread();
|
|
|
+ invoke_rcu_callbacks();
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -646,7 +645,7 @@ static void rcu_preempt_check_callbacks(void)
|
|
|
rcu_preempt_cpu_qs();
|
|
|
if (&rcu_preempt_ctrlblk.rcb.rcucblist !=
|
|
|
rcu_preempt_ctrlblk.rcb.donetail)
|
|
|
- invoke_rcu_kthread();
|
|
|
+ invoke_rcu_callbacks();
|
|
|
if (rcu_preempt_gp_in_progress() &&
|
|
|
rcu_cpu_blocking_cur_gp() &&
|
|
|
rcu_preempt_running_reader())
|
|
@@ -672,7 +671,7 @@ static void rcu_preempt_remove_callbacks(struct rcu_ctrlblk *rcp)
|
|
|
*/
|
|
|
static void rcu_preempt_process_callbacks(void)
|
|
|
{
|
|
|
- rcu_process_callbacks(&rcu_preempt_ctrlblk.rcb);
|
|
|
+ __rcu_process_callbacks(&rcu_preempt_ctrlblk.rcb);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -847,15 +846,6 @@ static void show_tiny_preempt_stats(struct seq_file *m)
|
|
|
|
|
|
#endif /* #ifdef CONFIG_RCU_TRACE */
|
|
|
|
|
|
-/*
|
|
|
- * Because preemptible RCU does not exist, it is never necessary to
|
|
|
- * boost preempted RCU readers.
|
|
|
- */
|
|
|
-static int rcu_boost(void)
|
|
|
-{
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Because preemptible RCU does not exist, it never has any callbacks
|
|
|
* to check.
|
|
@@ -882,6 +872,78 @@ static void rcu_preempt_process_callbacks(void)
|
|
|
|
|
|
#endif /* #else #ifdef CONFIG_TINY_PREEMPT_RCU */
|
|
|
|
|
|
+#ifdef CONFIG_RCU_BOOST
|
|
|
+
|
|
|
+/*
|
|
|
+ * Wake up rcu_kthread() to process callbacks now eligible for invocation
|
|
|
+ * or to boost readers.
|
|
|
+ */
|
|
|
+static void invoke_rcu_callbacks(void)
|
|
|
+{
|
|
|
+ have_rcu_kthread_work = 1;
|
|
|
+ wake_up(&rcu_kthread_wq);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * This kthread invokes RCU callbacks whose grace periods have
|
|
|
+ * elapsed. It is awakened as needed, and takes the place of the
|
|
|
+ * RCU_SOFTIRQ that is used for this purpose when boosting is disabled.
|
|
|
+ * This is a kthread, but it is never stopped, at least not until
|
|
|
+ * the system goes down.
|
|
|
+ */
|
|
|
+static int rcu_kthread(void *arg)
|
|
|
+{
|
|
|
+ unsigned long work;
|
|
|
+ unsigned long morework;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ wait_event_interruptible(rcu_kthread_wq,
|
|
|
+ have_rcu_kthread_work != 0);
|
|
|
+ morework = rcu_boost();
|
|
|
+ local_irq_save(flags);
|
|
|
+ work = have_rcu_kthread_work;
|
|
|
+ have_rcu_kthread_work = morework;
|
|
|
+ local_irq_restore(flags);
|
|
|
+ if (work)
|
|
|
+ rcu_process_callbacks(NULL);
|
|
|
+ schedule_timeout_interruptible(1); /* Leave CPU for others. */
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0; /* Not reached, but needed to shut gcc up. */
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Spawn the kthread that invokes RCU callbacks.
|
|
|
+ */
|
|
|
+static int __init rcu_spawn_kthreads(void)
|
|
|
+{
|
|
|
+ struct sched_param sp;
|
|
|
+
|
|
|
+ rcu_kthread_task = kthread_run(rcu_kthread, NULL, "rcu_kthread");
|
|
|
+ sp.sched_priority = RCU_BOOST_PRIO;
|
|
|
+ sched_setscheduler_nocheck(rcu_kthread_task, SCHED_FIFO, &sp);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+early_initcall(rcu_spawn_kthreads);
|
|
|
+
|
|
|
+#else /* #ifdef CONFIG_RCU_BOOST */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Start up softirq processing of callbacks.
|
|
|
+ */
|
|
|
+void invoke_rcu_callbacks(void)
|
|
|
+{
|
|
|
+ raise_softirq(RCU_SOFTIRQ);
|
|
|
+}
|
|
|
+
|
|
|
+void rcu_init(void)
|
|
|
+{
|
|
|
+ open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* #else #ifdef CONFIG_RCU_BOOST */
|
|
|
+
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
|
#include <linux/kernel_stat.h>
|
|
|
|
|
@@ -897,12 +959,6 @@ void __init rcu_scheduler_starting(void)
|
|
|
|
|
|
#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
|
|
|
|
|
|
-#ifdef CONFIG_RCU_BOOST
|
|
|
-#define RCU_BOOST_PRIO CONFIG_RCU_BOOST_PRIO
|
|
|
-#else /* #ifdef CONFIG_RCU_BOOST */
|
|
|
-#define RCU_BOOST_PRIO 1
|
|
|
-#endif /* #else #ifdef CONFIG_RCU_BOOST */
|
|
|
-
|
|
|
#ifdef CONFIG_RCU_TRACE
|
|
|
|
|
|
#ifdef CONFIG_RCU_BOOST
|