int cpu;
struct rcu_head barrier;
long last_rs_qlen; /* qlen during the last resched */
+
+ /* 3) idle CPUs handling */
+ struct timer idle_timer;
+ bool idle_timer_active;
};
+/*
+ * If a CPU with RCU callbacks queued goes idle, when the grace period is
+ * not finished yet, how can we make sure that the callbacks will eventually
+ * be executed? In Linux (2.6.21, the first "tickless idle" Linux kernel),
+ * the periodic timer tick would not be stopped for such CPU. Here in Xen,
+ * we (may) don't even have a periodic timer tick, so we need to use a
+ * special purpose timer.
+ *
+ * Such timer:
+ * 1) is armed only when a CPU with an RCU callback(s) queued goes idle
+ * before the end of the current grace period (_not_ for any CPUs that
+ * go idle!);
+ * 2) when it fires, it is only re-armed if the grace period is still
+ * running;
+ * 3) it is stopped immediately, if the CPU wakes up from idle and
+ * resumes 'normal' execution.
+ *
+ * About how far in the future the timer should be programmed each time,
+ * it's hard to tell (guess!!). Since this mimics Linux's periodic timer
+ * tick, take values used there as an indication. In Linux 2.6.21, tick
+ * period can be 10ms, 4ms, 3.33ms or 1ms. Let's use 10ms, to enable
+ * at least some power saving on the CPU that is going idle.
+ */
+#define RCU_IDLE_TIMER_PERIOD MILLISECS(10)
+
static DEFINE_PER_CPU(struct rcu_data, rcu_data);
static int blimit = 10;
{
struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
- return (!!rdp->curlist || rcu_pending(cpu));
+ return (rdp->curlist && !rdp->idle_timer_active) || rcu_pending(cpu);
+}
+
+/*
+ * Timer for making sure the CPU where a callback is queued does
+ * periodically poke rcu_pedning(), so that it will invoke the callback
+ * not too late after the end of the grace period.
+ */
+void rcu_idle_timer_start()
+{
+ struct rcu_data *rdp = &this_cpu(rcu_data);
+
+ /*
+ * Note that we don't check rcu_pending() here. In fact, we don't want
+ * the timer armed on CPUs that are in the process of quiescing while
+ * going idle, unless they really are the ones with a queued callback.
+ */
+ if (likely(!rdp->curlist))
+ return;
+
+ set_timer(&rdp->idle_timer, NOW() + RCU_IDLE_TIMER_PERIOD);
+ rdp->idle_timer_active = true;
+}
+
+void rcu_idle_timer_stop()
+{
+ struct rcu_data *rdp = &this_cpu(rcu_data);
+
+ if (likely(!rdp->idle_timer_active))
+ return;
+
+ rdp->idle_timer_active = false;
+ stop_timer(&rdp->idle_timer);
+}
+
+static void rcu_idle_timer_handler(void* data)
+{
+ /* Nothing, really... Just count the number of times we fire */
+ perfc_incr(rcu_idle_timer);
}
void rcu_check_callbacks(int cpu)
static void rcu_offline_cpu(struct rcu_data *this_rdp,
struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
{
+ kill_timer(&rdp->idle_timer);
+
/* If the cpu going offline owns the grace period we can block
* indefinitely waiting for it, so flush it here.
*/
rdp->qs_pending = 0;
rdp->cpu = cpu;
rdp->blimit = blimit;
+ init_timer(&rdp->idle_timer, rcu_idle_timer_handler, rdp, cpu);
}
static int cpu_callback(