From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55941) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WLcD4-0003KY-Jd for qemu-devel@nongnu.org; Thu, 06 Mar 2014 12:35:59 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WLcCz-0003qX-EH for qemu-devel@nongnu.org; Thu, 06 Mar 2014 12:35:54 -0500 Received: from mail-qa0-f45.google.com ([209.85.216.45]:46272) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WLcCz-0003qS-97 for qemu-devel@nongnu.org; Thu, 06 Mar 2014 12:35:49 -0500 Received: by mail-qa0-f45.google.com with SMTP id hw13so2794021qab.4 for ; Thu, 06 Mar 2014 09:35:49 -0800 (PST) From: Mike Day Date: Thu, 6 Mar 2014 12:35:28 -0500 Message-Id: <1394127328-13779-3-git-send-email-ncmike@ncultra.org> In-Reply-To: <1394127328-13779-1-git-send-email-ncmike@ncultra.org> References: <1394127328-13779-1-git-send-email-ncmike@ncultra.org> Subject: [Qemu-devel] [PATCH 2/2] [RFC] Convert Clock Timerlists to RCU V3 List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Mike Day , pbonzini@redhat.com, alex@alex.org.uk timerlists is a list of lists that holds active timers, among other items. It is read-mostly. This patch converts read access to the timerlists to use RCU. Rather than introduce a second mutex for timerlists, which would require nested mutexes to in order to write to the timerlists, use one QemuMutex in the QemuClock structure for all write access to any list hanging off the QemuClock structure. This patch applies against Paolo Bonzini's rcu branch: https://github.com/bonzini/qemu/tree/rcu and also requires the previously submitted patch ae11e1c "Convert active timers list to use RCU for read operations V3." V3: - timerlists modifications split to a separate patch (this one). - Addressed comments from Alex Bligh and Paolo Bonzini. Signed-off-by: Mike Day --- qemu-timer.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/qemu-timer.c b/qemu-timer.c index 57a1545..4144e54 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -74,6 +74,7 @@ struct QEMUTimerList { QEMUTimerListNotifyCB *notify_cb; void *notify_opaque; QemuEvent timers_done_ev; + struct rcu_head rcu; }; /** @@ -111,6 +112,13 @@ QEMUTimerList *timerlist_new(QEMUClockType type, return timer_list; } +static void reclaim_timerlist(struct rcu_head *rcu) +{ + QEMUTimerList *tl = container_of(rcu, QEMUTimerList, rcu); + g_free(tl); +} + + void timerlist_free(QEMUTimerList *timer_list) { assert(!timerlist_has_timers(timer_list)); @@ -118,7 +126,7 @@ void timerlist_free(QEMUTimerList *timer_list) QLIST_REMOVE(timer_list, list); } qemu_event_destroy(&timer_list->timers_done_ev); - g_free(timer_list); + call_rcu1(&timer_list->rcu, reclaim_timerlist); } static void qemu_clock_init(QEMUClockType type) @@ -143,9 +151,11 @@ void qemu_clock_notify(QEMUClockType type) { QEMUTimerList *timer_list; QEMUClock *clock = qemu_clock_ptr(type); - QLIST_FOREACH(timer_list, &clock->timerlists, list) { + rcu_read_lock(); + QLIST_FOREACH_RCU(timer_list, &clock->timerlists, list) { timerlist_notify(timer_list); } + rcu_read_unlock(); } void qemu_clock_enable(QEMUClockType type, bool enabled) @@ -157,9 +167,11 @@ void qemu_clock_enable(QEMUClockType type, bool enabled) if (enabled && !old) { qemu_clock_notify(type); } else if (!enabled && old) { - QLIST_FOREACH(tl, &clock->timerlists, list) { + rcu_read_lock(); + QLIST_FOREACH_RCU(tl, &clock->timerlists, list) { qemu_event_wait(&tl->timers_done_ev); } + rcu_read_unlock(); } } @@ -243,10 +255,12 @@ int64_t qemu_clock_deadline_ns_all(QEMUClockType type) int64_t deadline = -1; QEMUTimerList *timer_list; QEMUClock *clock = qemu_clock_ptr(type); - QLIST_FOREACH(timer_list, &clock->timerlists, list) { + rcu_read_lock(); + QLIST_FOREACH_RCU(timer_list, &clock->timerlists, list) { deadline = qemu_soonest_timeout(deadline, timerlist_deadline_ns(timer_list)); } + rcu_read_unlock(); return deadline; } @@ -262,11 +276,13 @@ QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type) void timerlist_notify(QEMUTimerList *timer_list) { - if (timer_list->notify_cb) { + rcu_read_lock(); + if (atomic_rcu_read(&timer_list->notify_cb)) { timer_list->notify_cb(timer_list->notify_opaque); } else { qemu_notify_event(); } + rcu_read_unlock(); } /* Transition function to convert a nanosecond timeout to ms @@ -585,13 +601,18 @@ void qemu_clock_register_reset_notifier(QEMUClockType type, Notifier *notifier) { QEMUClock *clock = qemu_clock_ptr(type); + qemu_mutex_lock(&clock->timer_lock); notifier_list_add(&clock->reset_notifiers, notifier); + qemu_mutex_unlock(&clock->timer_lock); } void qemu_clock_unregister_reset_notifier(QEMUClockType type, Notifier *notifier) { + QEMUClock *clock = qemu_clock_ptr(type); + qemu_mutex_lock(&clock->timer_lock); notifier_remove(notifier); + qemu_mutex_unlock(&clock->timer_lock); } void init_clocks(void) -- 1.9.0