After disabling the QemuClock, we should make sure that no QemuTimers
are still in flight. To implement that, the caller of disabling will
wait until the last user's exit.

Note, the callers of qemu_clock_enable() should be sync by themselves,
not protected by this patch.

Signed-off-by: Liu Ping Fan <pingf...@linux.vnet.ibm.com>
---
 qemu-timer.c | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/qemu-timer.c b/qemu-timer.c
index 5a42035..d941a83 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -60,6 +60,14 @@ struct QEMUClock {
 
     int type;
     bool enabled;
+
+    /* rule: Innermost lock
+     * to protect the disable against timer's cb in flight.
+     */
+    QemuMutex lock;
+    /* reference by timer list */
+    int using;
+    QemuCond wait_using;
 };
 
 struct QEMUTimer {
@@ -274,6 +282,9 @@ static QEMUClock *qemu_new_clock(int type)
     clock->type = type;
     clock->enabled = true;
     clock->last = INT64_MIN;
+    clock->using = 0;
+    qemu_cond_init(&clock->wait_using);
+    qemu_mutex_init(&clock->lock);
     notifier_list_init(&clock->reset_notifiers);
     tlist = clock_to_timerlist(clock);
     timer_list_init(tlist);
@@ -287,6 +298,13 @@ void qemu_clock_enable(QEMUClock *clock, bool enabled)
     clock->enabled = enabled;
     if (enabled && !old) {
         qemu_rearm_alarm_timer(alarm_timer);
+    } else {
+        qemu_mutex_lock(&clock->lock);
+        /* Wait for cb in flight to terminate */
+        while (atomic_read(clock->using)) {
+            qemu_cond_wait(&clock->wait_using, &clock->lock);
+        }
+        qemu_mutex_unlock(&clock->lock);
     }
 }
 
@@ -440,8 +458,11 @@ void qemu_run_timers(QEMUClock *clock)
     int64_t current_time;
     TimerList *tlist;
 
-    if (!clock->enabled)
-        return;
+    atomic_inc(&clock->using);
+    if (unlikely(!clock->enabled)) {
+        goto exit;
+    }
+
 
     current_time = qemu_get_clock_ns(clock);
     tlist = clock_to_timerlist(clock);
@@ -461,6 +482,15 @@ void qemu_run_timers(QEMUClock *clock)
         /* run the callback (the timer list can be modified) */
         ts->cb(ts->opaque);
     }
+
+exit:
+    qemu_mutex_lock(&clock->lock);
+    if (atomic_fetch_dec(&clock->using) == 1) {
+        if (unlikely(!clock->enabled)) {
+            qemu_cond_signal(&clock->wait_using);
+        }
+    }
+    qemu_mutex_unlock(&clock->lock);
 }
 
 int64_t qemu_get_clock_ns(QEMUClock *clock)
-- 
1.8.1.4


Reply via email to