[xen master] RCU: let the RCU idle timer handler run

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[xen master] RCU: let the RCU idle timer handler run

patchbot
commit 9e0a3a2a9143c17319660e22dcf4b7a59fa9473e
Author:     Dario Faggioli <[hidden email]>
AuthorDate: Mon Oct 9 13:22:07 2017 +0200
Commit:     Jan Beulich <[hidden email]>
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 <[hidden email]>
    Reviewed-by: Jan Beulich <[hidden email]>
---
 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
[hidden email]
https://lists.xenproject.org/xen-changelog