[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 1/3] xen: RCU: let the RCU idle timer handler run
If stop_timer() is called between when the RCU idle timer's interrupt arrives (and TIMER_SOFTIRQ is raised) and when softirqs are checked and handled, the timer is deactivated, and the handler never runs. This happens to the RCU idle timer because stop_timer() is called on it during the wakeup from idle (e.g., C-states, on x86) path. To fix that, we avoid calling stop_timer(), in case we see that the timer itself is: - still active, - expired (i.e., it's expiry time is in the past). In fact, that indicates (for this particular timer) that it has fired, and we are just about to handle the TIMER_SOFTIRQ (which will perform the timer deactivation and run its handler). Signed-off-by: Dario Faggioli <dario.faggioli@xxxxxxxxxx> --- Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Cc: George Dunlap <George.Dunlap@xxxxxxxxxxxxx> Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx> Cc: Julien Grall <julien.grall@xxxxxxx> Cc: Tim Deegan <tim@xxxxxxx> --- Changes from v2: - improved comment in rcu_idle_timer_stop(); - introduce a more generic timer_expires_before() function, and make timer_is_expired() a macro which does not take any time parameter. Changes from v1: - logic changed completely: instead of avoiding deactivate_timer() in stop_timer(), we avoid stop_timer() in rcu_idle_timer_stop() (if appropriate, of course). --- xen/common/rcupdate.c | 19 ++++++++++++++++++- xen/common/timer.c | 17 +++++++++++++++++ xen/include/xen/timer.h | 5 +++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/xen/common/rcupdate.c b/xen/common/rcupdate.c index 871936f..252e01b 100644 --- a/xen/common/rcupdate.c +++ b/xen/common/rcupdate.c @@ -465,7 +465,24 @@ void rcu_idle_timer_stop() return; rdp->idle_timer_active = false; - stop_timer(&rdp->idle_timer); + + /* + * In general, as the CPU is becoming active again, we don't need the + * idle timer, and so we want to stop it. + * + * However, in case we are here because idle_timer has (just) fired and + * has woken up the CPU, we skip stop_timer() now. In fact, when a CPU + * wakes up from idle, this code always runs before do_softirq() has the + * chance to check and deal with TIMER_SOFTIRQ. And if we stop the timer + * now, the TIMER_SOFTIRQ handler will see it as inactive, and will not + * call rcu_idle_timer_handler(). + * + * Therefore, if we see that the timer is expired already, we leave it + * alone. The TIMER_SOFTIRQ handler will then run the timer routine, and + * deactivate it. + */ + if ( !timer_is_expired(&rdp->idle_timer) ) + stop_timer(&rdp->idle_timer); } static void rcu_idle_timer_handler(void* data) diff --git a/xen/common/timer.c b/xen/common/timer.c index d9ff669..fa45db2 100644 --- a/xen/common/timer.c +++ b/xen/common/timer.c @@ -332,6 +332,23 @@ void stop_timer(struct timer *timer) } +bool timer_expires_before(struct timer *timer, s_time_t t) +{ + unsigned long flags; + bool ret = false; + + if ( !timer_lock_irqsave(timer, flags) ) + return ret; + + if ( active_timer(timer) && timer->expires <= t ) + ret = true; + + timer_unlock_irqrestore(timer, flags); + + return ret; +} + + void migrate_timer(struct timer *timer, unsigned int new_cpu) { unsigned int old_cpu; diff --git a/xen/include/xen/timer.h b/xen/include/xen/timer.h index 9531800..4513260 100644 --- a/xen/include/xen/timer.h +++ b/xen/include/xen/timer.h @@ -70,6 +70,11 @@ void set_timer(struct timer *timer, s_time_t expires); */ void stop_timer(struct timer *timer); +/* True if a timer is active, and its expiry time is earlier than t. */ +bool timer_expires_before(struct timer *timer, s_time_t t); + +#define timer_is_expired(t) timer_expires_before(t, NOW()) + /* Migrate a timer to a different CPU. The timer may be currently active. */ void migrate_timer(struct timer *timer, unsigned int new_cpu); _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |