[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] RCU: let the RCU idle timer handler run
commit 9e0a3a2a9143c17319660e22dcf4b7a59fa9473e Author: Dario Faggioli <dario.faggioli@xxxxxxxxxx> AuthorDate: Mon Oct 9 13:22:07 2017 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Mon Oct 9 13:22:07 2017 +0200 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> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx> --- xen/common/rcupdate.c | 19 ++++++++++++++++++- xen/common/timer.c | 14 ++++++++++++++ xen/include/xen/timer.h | 5 +++++ 3 files changed, 37 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..376581b 100644 --- a/xen/common/timer.c +++ b/xen/common/timer.c @@ -331,6 +331,20 @@ void stop_timer(struct timer *timer) timer_unlock_irqrestore(timer, flags); } +bool timer_expires_before(struct timer *timer, s_time_t t) +{ + unsigned long flags; + bool ret; + + if ( !timer_lock_irqsave(timer, flags) ) + return false; + + ret = active_timer(timer) && timer->expires <= t; + + timer_unlock_irqrestore(timer, flags); + + return ret; +} void migrate_timer(struct timer *timer, unsigned int new_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); -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |