If stop_timer() is called between when a timer interrupt arrives (and TIMER_SOFTIRQ is raised) and when softirqs are checked and handled, the timer that has fire is (right in stop_timer()) deactivated, and the handler for that occurrence of the interrupt never executed.
This happens, e.g. to timers stopped during the wakeup from idle (e.g., C-states, on x86) path. To fix that, don't deactivate a timer, while stopping it, if it has expired. On the contrary, when that happens, (re-)raise the timer softirq, to make sure the handler is invoked. Signed-off-by: Dario Faggioli <dario.faggi...@citrix.com> --- Cc: Andrew Cooper <andrew.coop...@citrix.com> Cc: George Dunlap <george.dun...@eu.citrix.com> Cc: Jan Beulich <jbeul...@suse.com> Cc: Stefano Stabellini <sstabell...@kernel.org> Cc: Julien Grall <julien.gr...@arm.com> Cc: Tim Deegan <t...@xen.org> --- xen/common/timer.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/xen/common/timer.c b/xen/common/timer.c index d9ff669..b1d1511 100644 --- a/xen/common/timer.c +++ b/xen/common/timer.c @@ -217,7 +217,7 @@ static inline void activate_timer(struct timer *timer) timer->status = TIMER_STATUS_invalid; list_del(&timer->inactive); - if ( add_entry(timer) ) + if ( add_entry(timer) || timer->expires <= NOW() ) cpu_raise_softirq(timer->cpu, TIMER_SOFTIRQ); } @@ -326,7 +326,17 @@ void stop_timer(struct timer *timer) return; if ( active_timer(timer) ) - deactivate_timer(timer); + { + /* + * If the timer is expired already, 'call' the softirq handler to + * execute it (it will leave it inactive after that). If not, just + * deactivate it. + */ + if ( timer->expires <= NOW() ) + cpu_raise_softirq(timer->cpu, TIMER_SOFTIRQ); + else + deactivate_timer(timer); + } timer_unlock_irqrestore(timer, flags); } _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel