From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49771) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dkPVt-00024W-9p for qemu-devel@nongnu.org; Wed, 23 Aug 2017 02:51:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dkPVp-0007QR-Dd for qemu-devel@nongnu.org; Wed, 23 Aug 2017 02:51:41 -0400 Received: from mx1.redhat.com ([209.132.183.28]:37084) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dkPVp-0007QF-7W for qemu-devel@nongnu.org; Wed, 23 Aug 2017 02:51:37 -0400 From: Peter Xu Date: Wed, 23 Aug 2017 14:51:06 +0800 Message-Id: <1503471071-2233-4-git-send-email-peterx@redhat.com> In-Reply-To: <1503471071-2233-1-git-send-email-peterx@redhat.com> References: <1503471071-2233-1-git-send-email-peterx@redhat.com> Subject: [Qemu-devel] [RFC v2 3/8] char-io: fix possible risk on IOWatchPoll List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Paolo Bonzini , "Daniel P . Berrange" , Fam Zheng , Juan Quintela , mdroth@linux.vnet.ibm.com, peterx@redhat.com, Eric Blake , Laurent Vivier , Markus Armbruster , "Dr . David Alan Gilbert" This is not a problem if we are only having one single loop thread like before. However, after per-monitor thread is introduced, this is not true any more, and the risk can happen. The risk can be triggered with "make check -j8" sometimes: qemu-system-x86_64: /root/git/qemu/chardev/char-io.c:91: io_watch_poll_finalize: Assertion `iwp->src == NULL' failed. This patch keeps the reference for the watch object when creating in io_add_watch_poll(), so that the object will never be released in the context main loop, especially when the context loop is running in another standalone thread. Meanwhile, when we want to remove the watch object, we always first detach the watch object from its owner context, then we continue with the cleanup. Without this patch, calling io_remove_watch_poll() in main loop thread is not thread-safe, since the other per-monitor thread may be modifying the watch object at the same time. Signed-off-by: Peter Xu --- chardev/char-io.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/chardev/char-io.c b/chardev/char-io.c index f810524..5c52c40 100644 --- a/chardev/char-io.c +++ b/chardev/char-io.c @@ -122,7 +122,6 @@ GSource *io_add_watch_poll(Chardev *chr, g_free(name); g_source_attach(&iwp->parent, context); - g_source_unref(&iwp->parent); return (GSource *)iwp; } @@ -131,12 +130,24 @@ static void io_remove_watch_poll(GSource *source) IOWatchPoll *iwp; iwp = io_watch_poll_from_source(source); + + /* + * Here the order of destruction really matters. We need to first + * detach the IOWatchPoll object from the context (which may still + * be running in another loop thread), only after that could we + * continue to operate on iwp->src, or there may be risk condition + * between current thread and the context loop thread. + * + * Let's blame the glib bug mentioned in commit 2b3167 (again) for + * this extra complexity. + */ + g_source_destroy(&iwp->parent); if (iwp->src) { g_source_destroy(iwp->src); g_source_unref(iwp->src); iwp->src = NULL; } - g_source_destroy(&iwp->parent); + g_source_unref(&iwp->parent); } void remove_fd_in_watch(Chardev *chr) -- 2.7.4