From patchwork Thu Jan 12 16:55:29 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 714553 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3tzsvn0Vv1z9t0q for ; Fri, 13 Jan 2017 04:20:05 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ivdqOcsQ"; dkim-atps=neutral Received: from localhost ([::1]:35377 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cRj2g-0007KP-Kp for incoming@patchwork.ozlabs.org; Thu, 12 Jan 2017 12:20:02 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53782) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cRifH-0002Bd-QU for qemu-devel@nongnu.org; Thu, 12 Jan 2017 11:55:56 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cRifC-00080v-RP for qemu-devel@nongnu.org; Thu, 12 Jan 2017 11:55:51 -0500 Received: from mail-wm0-x244.google.com ([2a00:1450:400c:c09::244]:36372) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cRifC-00080a-IO for qemu-devel@nongnu.org; Thu, 12 Jan 2017 11:55:46 -0500 Received: by mail-wm0-x244.google.com with SMTP id r126so4993250wmr.3 for ; Thu, 12 Jan 2017 08:55:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=+19UoGfWP5XdKPFv6NjYC4Qp7HnRXbgYLtUeV7H8W8M=; b=ivdqOcsQyaaBCiLenQWRSkRm6pccRXbAxlcScEzfc9WZDyfbrOQB20R2ze3nuRZsA/ hV647Kb8z2lqf/tba8qRZ1nFK+BwIWKn5mJqEptxsnJV85ZoA2GwT5QpvmbKfhIUe8So tKiuq7ZNSweZ1TfHLVnH9bsKpZIdjq1wUKYDSibosOVKvzhwNRxbH8CJA9HaEpmEwZaD DU6w4Mku13wWDKJXC5mkTW9FKYhD38Yv21eFPGyi91vn5HvR7aawIvBolIz5YznOufb5 aaUXLs8ilXaMnKmYDONweEg0bi3rPIL+aB/J4iEmsYlEb+pm4ATdsHelWDs6nEV10Ndc 6QHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=+19UoGfWP5XdKPFv6NjYC4Qp7HnRXbgYLtUeV7H8W8M=; b=f5xVdq/8zT9xb+BPqCQhg0UE2LbkFd7C1UWF0+Yax3Ro81Pz5ulRtLEPHrxUdn2bNn sQw4NgsCdE1Nb8SoolxcQ97MlByJMsYf+2AxzhVvCNU79r/mEe3Rcr93/9lT3fnlqqgv FLh+RLws0CFhgsA/9nnzqu14zH5KAtjM/w13Snm02dY80UmypXAXa4fgDrHnt67TjzEi yhbh8PlBT2oKli8Cze+xvmTv3xpF6iTM8sIf1sp4XIjqCp6TUIGNidBt3e1a7yOXYzJx tNDkKYhmwfGrnxUAfGqm0dc/HCisTry6nCT1en7F5NGkyEhQ0/lpSkbKaZJ+3gzpxGVx aNzw== X-Gm-Message-State: AIkVDXIZwwF4c/bZIXqhb145BO03cYLtb9uR9kIAjrUaqhcZ/dCg/Jg6YAN3+Meup+XTtQ== X-Received: by 10.28.45.1 with SMTP id t1mr5691574wmt.53.1484240145366; Thu, 12 Jan 2017 08:55:45 -0800 (PST) Received: from donizetti.lan (94-39-158-71.adsl-ull.clienti.tiscali.it. [94.39.158.71]) by smtp.gmail.com with ESMTPSA id u81sm4152974wmu.10.2017.01.12.08.55.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 Jan 2017 08:55:44 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Thu, 12 Jan 2017 17:55:29 +0100 Message-Id: <20170112165531.11882-9-pbonzini@redhat.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170112165531.11882-1-pbonzini@redhat.com> References: <20170112165531.11882-1-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:400c:c09::244 Subject: [Qemu-devel] [PATCH 08/10] aio-win32: remove walking_handlers, protecting AioHandler list with list_lock X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: famz@redhat.com, stefanha@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini --- aio-win32.c | 73 +++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/aio-win32.c b/aio-win32.c index 1ad459d..900524c 100644 --- a/aio-win32.c +++ b/aio-win32.c @@ -21,6 +21,7 @@ #include "qemu/queue.h" #include "qemu/sockets.h" #include "qapi/error.h" +#include "qemu/rcu_queue.h" struct AioHandler { EventNotifier *e; @@ -45,6 +46,7 @@ void aio_set_fd_handler(AioContext *ctx, /* fd is a SOCKET in our case */ AioHandler *node; + qemu_lockcnt_lock(&ctx->list_lock); QLIST_FOREACH(node, &ctx->aio_handlers, node) { if (node->pfd.fd == fd && !node->deleted) { break; @@ -54,14 +56,14 @@ void aio_set_fd_handler(AioContext *ctx, /* Are we deleting the fd handler? */ if (!io_read && !io_write) { if (node) { - /* If the lock is held, just mark the node as deleted */ - if (ctx->walking_handlers) { + /* If aio_poll is in progress, just mark the node as deleted */ + if (qemu_lockcnt_count(&ctx->list_lock)) { node->deleted = 1; node->pfd.revents = 0; } else { /* Otherwise, delete it for real. We can't just mark it as * deleted because deleted nodes are only cleaned up after - * releasing the walking_handlers lock. + * releasing the list_lock. */ QLIST_REMOVE(node, node); g_free(node); @@ -74,7 +76,7 @@ void aio_set_fd_handler(AioContext *ctx, /* Alloc and insert if it's not already there */ node = g_new0(AioHandler, 1); node->pfd.fd = fd; - QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node); + QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node); } node->pfd.events = 0; @@ -99,6 +101,7 @@ void aio_set_fd_handler(AioContext *ctx, FD_CONNECT | FD_WRITE | FD_OOB); } + qemu_lockcnt_unlock(&ctx->list_lock); aio_notify(ctx); } @@ -117,6 +120,7 @@ void aio_set_event_notifier(AioContext *ctx, { AioHandler *node; + qemu_lockcnt_lock(&ctx->list_lock); QLIST_FOREACH(node, &ctx->aio_handlers, node) { if (node->e == e && !node->deleted) { break; @@ -128,14 +132,14 @@ void aio_set_event_notifier(AioContext *ctx, if (node) { g_source_remove_poll(&ctx->source, &node->pfd); - /* If the lock is held, just mark the node as deleted */ - if (ctx->walking_handlers) { + /* aio_poll is in progress, just mark the node as deleted */ + if (qemu_lockcnt_count(&ctx->list_lock)) { node->deleted = 1; node->pfd.revents = 0; } else { /* Otherwise, delete it for real. We can't just mark it as * deleted because deleted nodes are only cleaned up after - * releasing the walking_handlers lock. + * releasing the list_lock. */ QLIST_REMOVE(node, node); g_free(node); @@ -149,7 +153,7 @@ void aio_set_event_notifier(AioContext *ctx, node->pfd.fd = (uintptr_t)event_notifier_get_handle(e); node->pfd.events = G_IO_IN; node->is_external = is_external; - QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node); + QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node); g_source_add_poll(&ctx->source, &node->pfd); } @@ -157,6 +161,7 @@ void aio_set_event_notifier(AioContext *ctx, node->io_notify = io_notify; } + qemu_lockcnt_unlock(&ctx->list_lock); aio_notify(ctx); } @@ -175,10 +180,16 @@ bool aio_prepare(AioContext *ctx) bool have_select_revents = false; fd_set rfds, wfds; + /* + * We have to walk very carefully in case aio_set_fd_handler is + * called while we're walking. + */ + qemu_lockcnt_inc(&ctx->list_lock); + /* fill fd sets */ FD_ZERO(&rfds); FD_ZERO(&wfds); - QLIST_FOREACH(node, &ctx->aio_handlers, node) { + QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { if (node->io_read) { FD_SET ((SOCKET)node->pfd.fd, &rfds); } @@ -188,7 +199,7 @@ bool aio_prepare(AioContext *ctx) } if (select(0, &rfds, &wfds, NULL, &tv0) > 0) { - QLIST_FOREACH(node, &ctx->aio_handlers, node) { + QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { node->pfd.revents = 0; if (FD_ISSET(node->pfd.fd, &rfds)) { node->pfd.revents |= G_IO_IN; @@ -202,41 +213,53 @@ bool aio_prepare(AioContext *ctx) } } + qemu_lockcnt_dec(&ctx->list_lock); return have_select_revents; } bool aio_pending(AioContext *ctx) { AioHandler *node; + bool result = false; - QLIST_FOREACH(node, &ctx->aio_handlers, node) { + /* + * We have to walk very carefully in case aio_set_fd_handler is + * called while we're walking. + */ + qemu_lockcnt_inc(&ctx->list_lock); + QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { if (node->pfd.revents && node->io_notify) { - return true; + result = true; + break; } if ((node->pfd.revents & G_IO_IN) && node->io_read) { - return true; + result = true; + break; } if ((node->pfd.revents & G_IO_OUT) && node->io_write) { - return true; + result = true; + break; } } - return false; + qemu_lockcnt_dec(&ctx->list_lock); + return result; } static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event) { - AioHandler *node, *tmp; + AioHandler *node; bool progress = false; + AioHandler *tmp; - ctx->walking_handlers++; + qemu_lockcnt_inc(&ctx->list_lock); /* * We have to walk very carefully in case aio_set_fd_handler is * called while we're walking. */ - QLIST_FOREACH_SAFE(node, &ctx->aio_handlers, node, tmp) { + QLIST_FOREACH_SAFE_RCU(node, &ctx->aio_handlers, node, tmp) { int revents = node->pfd.revents; if (!node->deleted && @@ -274,16 +297,15 @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event) } if (node->deleted) { - ctx->walking_handlers--; - if (!ctx->walking_handlers) { + if (qemu_lockcnt_dec_if_lock(&ctx->list_lock)) { QLIST_REMOVE(node, node); g_free(node); + qemu_lockcnt_inc_and_unlock(&ctx->list_lock); } - ctx->walking_handlers++; } } - ctx->walking_handlers--; + qemu_lockcnt_dec(&ctx->list_lock); return progress; } @@ -321,20 +343,19 @@ bool aio_poll(AioContext *ctx, bool blocking) atomic_add(&ctx->notify_me, 2); } + qemu_lockcnt_inc(&ctx->list_lock); have_select_revents = aio_prepare(ctx); - ctx->walking_handlers++; - /* fill fd sets */ count = 0; - QLIST_FOREACH(node, &ctx->aio_handlers, node) { + QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { if (!node->deleted && node->io_notify && aio_node_check(ctx, node->is_external)) { events[count++] = event_notifier_get_handle(node->e); } } - ctx->walking_handlers--; + qemu_lockcnt_dec(&ctx->list_lock); first = true; /* ctx->notifier is always registered. */