From patchwork Fri Jan 9 17:19:50 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 427187 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 DFCFE140192 for ; Sat, 10 Jan 2015 04:20:52 +1100 (AEDT) Received: from localhost ([::1]:51567 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y9dEw-0006Wv-Ji for incoming@patchwork.ozlabs.org; Fri, 09 Jan 2015 12:20:50 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38200) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y9dEL-0005sL-B8 for qemu-devel@nongnu.org; Fri, 09 Jan 2015 12:20:14 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Y9dEH-0001Fw-49 for qemu-devel@nongnu.org; Fri, 09 Jan 2015 12:20:13 -0500 Received: from mail-qa0-x236.google.com ([2607:f8b0:400d:c00::236]:34429) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y9dEG-0001Ev-Tv for qemu-devel@nongnu.org; Fri, 09 Jan 2015 12:20:09 -0500 Received: by mail-qa0-f54.google.com with SMTP id i13so7875536qae.13 for ; Fri, 09 Jan 2015 09:20:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:mime-version:content-type :content-transfer-encoding; bh=vmRjW7HOOJZexryVPjTRQQwn8fk7FeZH9FZMeM22Hfc=; b=WbLLEKPrgqbona1pXyTp5Y5rP3wMnyRhH86Wux7KRUdbAal9E+V5/qoQTiUaKITlR8 DeUPodmhWXliHlWZtad6UeJOIBFCz0Y/6lZIXeF/lWkNBYUf7N2nTuF3QJDa+gZNfkFP 3n0VAagdRUxgJcO24YBpS8Hy946wBUdthifCKr4rfbYs1IsgA1zV57F4T/4+yb9Ct5lg Hup3ONxtEHt2AfKuR7+cTIWXWVUfaD96KTFI0XD1vKge0cHhc6bIlLN8/xc+Nso1TItv 9MtmvDTVKxWAYQ2AJXUFgZ+ivIAjROWdJdCbMucInu66bxs3mvWq3M0RGRXv7FXaVDsZ U41Q== X-Received: by 10.224.129.70 with SMTP id n6mr27488051qas.104.1420824007967; Fri, 09 Jan 2015 09:20:07 -0800 (PST) Received: from localhost (bne75-h02-31-39-163-232.dsl.sta.abo.bbox.fr. [31.39.163.232]) by mx.google.com with ESMTPSA id n18sm7484387qae.27.2015.01.09.09.20.06 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 09 Jan 2015 09:20:07 -0800 (PST) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 9 Jan 2015 18:19:50 +0100 Message-Id: <1420823990-31461-1-git-send-email-marcandre.lureau@gmail.com> X-Mailer: git-send-email 2.1.0 MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400d:c00::236 Cc: pbonzini@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , stefanha@redhat.com Subject: [Qemu-devel] [PATCH] WIP: add GCoroutine support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Learn to use the GCoroutine library instead of qemu own coroutine implementation. GCoroutine is hosted on github: https://github.com/elmarco/gcoroutine This allows to share the same coroutine implementation between various projects (gtk-vnc and spice-gtk). It is related to the effort to push coroutine support in GLib. See also: https://bugzilla.gnome.org/show_bug.cgi?id=719362 Notes: - there are no GCoroutine releases, the API isn't frozen - this patch hasn't been thoroughly tested - GCoroutine doesn't implement pools yet - GCoroutine is missing sigaltstack based coroutines - spice-gtk and gtk-vnc patches are being worked on --- Makefile.objs | 11 +++- configure | 26 +++++++- coroutine-gcoroutine.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++ include/block/coroutine.h | 15 +++++ 4 files changed, 201 insertions(+), 5 deletions(-) create mode 100644 coroutine-gcoroutine.c diff --git a/Makefile.objs b/Makefile.objs index abeb902..250c58a 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -14,10 +14,17 @@ block-obj-$(CONFIG_WIN32) += aio-win32.o block-obj-y += block/ block-obj-y += qemu-io-cmds.o -block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o -block-obj-y += qemu-coroutine-sleep.o block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o +ifeq ($(CONFIG_COROUTINE_BACKEND),gcoroutine) +coroutine-gcoroutine.o-cflags := $(GCOROUTINE_CFLAGS) +coroutine-gcoroutine.o-libs := $(GCOROUTINE_LIBS) +else +block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o +endif +block-obj-y += qemu-coroutine-io.o +block-obj-y += qemu-coroutine-sleep.o + block-obj-m = block/ diff --git a/configure b/configure index cae588c..e36ee74 100755 --- a/configure +++ b/configure @@ -1381,7 +1381,7 @@ Advanced options (experts only): --disable-seccomp disable seccomp support --enable-seccomp enable seccomp support --with-coroutine=BACKEND coroutine backend. Supported options: - gthread, ucontext, sigaltstack, windows + gcoroutine, gthread, ucontext, sigaltstack, windows --disable-coroutine-pool disable coroutine freelist (worse performance) --enable-coroutine-pool enable coroutine freelist (better performance) --enable-glusterfs enable GlusterFS backend @@ -3870,8 +3870,16 @@ EOF fi fi +if $pkg_config gcoroutine-1.0 --exists; then + gcoroutine_cflags=`$pkg_config --cflags gcoroutine-1.0` + gcoroutine_libs=`$pkg_config --libs gcoroutine-1.0` + gcoroutine=yes +fi + if test "$coroutine" = ""; then - if test "$mingw32" = "yes"; then + if test "$gcoroutine" = "yes"; then + coroutine=gcoroutine + elif test "$mingw32" = "yes"; then coroutine=win32 elif test "$ucontext_works" = "yes"; then coroutine=ucontext @@ -3898,6 +3906,11 @@ else error_exit "only the 'windows' coroutine backend is valid for Windows" fi ;; + gcoroutine) + if test "$gcoroutine" != "yes"; then + feature_not_found "gcoroutine" + fi + ;; *) error_exit "unknown coroutine backend $coroutine" ;; @@ -4213,7 +4226,7 @@ EOF fi # prepend pixman and ftd flags after all config tests are done -QEMU_CFLAGS="$pixman_cflags $fdt_cflags $QEMU_CFLAGS" +QEMU_CFLAGS="$pixman_cflags $fdt_cflags $gcoroutine_cflags $QEMU_CFLAGS" libs_softmmu="$pixman_libs $libs_softmmu" echo "Install prefix $prefix" @@ -4733,6 +4746,13 @@ else echo "CONFIG_COROUTINE_POOL=0" >> $config_host_mak fi +if test "$coroutine" = "gcoroutine" ; then + echo "CONFIG_GCOROUTINE=1" >> $config_host_mak + echo "GCOROUTINE_LIBS=$gcoroutine_libs" >> $config_host_mak + echo "GCOROUTINE_CFLAGS=$gcoroutine_cflags" >> $config_host_mak +fi + + if test "$open_by_handle_at" = "yes" ; then echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak fi diff --git a/coroutine-gcoroutine.c b/coroutine-gcoroutine.c new file mode 100644 index 0000000..3d5b749 --- /dev/null +++ b/coroutine-gcoroutine.c @@ -0,0 +1,154 @@ +/* + * GCoroutine wrapper + * + * Copyright (C) 2014 Marc-André Lureau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include +#include "qemu-common.h" +#include "block/coroutine_int.h" + +Coroutine *qemu_coroutine_self(void) +{ + return (Coroutine *)g_coroutine_self(); +} + +bool qemu_in_coroutine(void) +{ + return g_in_coroutine(); +} + +void qemu_co_queue_init(CoQueue *queue) +{ + g_co_queue_init(queue); +} + +void coroutine_fn qemu_co_queue_wait(CoQueue *queue) +{ + g_co_queue_yield(queue, NULL); +} + +bool coroutine_fn qemu_co_queue_next(CoQueue *queue) +{ + return g_co_queue_schedule(queue, 1) == 1; +} + +void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue) +{ + g_co_queue_schedule(queue, -1); +} + +bool qemu_co_enter_next(CoQueue *queue) +{ + if (g_co_queue_is_empty(queue)) + return false; + + g_co_queue_resume_head(queue, NULL); + + return true; +} + +bool qemu_co_queue_empty(CoQueue *queue) +{ + return g_co_queue_is_empty(queue); +} + +void qemu_co_mutex_init(CoMutex *mutex) +{ + g_co_mutex_init(mutex); +} + +void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex) +{ + g_co_mutex_lock(mutex); +} + +void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex) +{ + g_co_mutex_unlock(mutex); +} + +void qemu_co_rwlock_init(CoRwlock *lock) +{ + g_co_rw_lock_init(lock); +} + +void qemu_co_rwlock_rdlock(CoRwlock *lock) +{ + g_co_rw_lock_reader_lock(lock); +} + +void qemu_co_rwlock_unlock(CoRwlock *lock) +{ + if (lock->writer) + g_co_rw_lock_writer_unlock(lock); + else + g_co_rw_lock_reader_unlock(lock); +} + +void qemu_co_rwlock_wrlock(CoRwlock *lock) +{ + g_co_rw_lock_writer_lock(lock); +} + +static gboolean coroutine_end_cb(gpointer data) +{ + GCoroutine *co = data; + + g_coroutine_unref(co); + + return FALSE; +} + +static gpointer coroutine_func(gpointer data) +{ + CoroutineEntry *entry = data; + + data = g_coroutine_yield(NULL); + + entry(data); + + g_idle_add(coroutine_end_cb, g_coroutine_self()); + + return NULL; +} + +Coroutine *qemu_coroutine_create(CoroutineEntry *entry) +{ + GCoroutine *co = g_coroutine_new(coroutine_func); + + if (!co) + return NULL; + + g_coroutine_resume(co, entry); + + return (Coroutine*)co; +} + +void qemu_coroutine_enter(Coroutine *co, void *opaque) +{ + g_coroutine_resume((GCoroutine*)co, opaque); +} + +void coroutine_fn qemu_coroutine_yield(void) +{ + g_coroutine_yield(NULL); +} + +void qemu_coroutine_adjust_pool_size(int n) +{ + g_warning("no pool yet"); +} diff --git a/include/block/coroutine.h b/include/block/coroutine.h index 793df0e..cb1fbfc 100644 --- a/include/block/coroutine.h +++ b/include/block/coroutine.h @@ -19,6 +19,9 @@ #include "qemu/typedefs.h" #include "qemu/queue.h" #include "qemu/timer.h" +#ifdef CONFIG_GCOROUTINE +#include +#endif /** * Coroutines are a mechanism for stack switching and can be used for @@ -103,9 +106,13 @@ bool qemu_in_coroutine(void); * them later. They provide the fundamental primitives on which coroutine locks * are built. */ +#ifdef CONFIG_GCOROUTINE +typedef GCoQueue CoQueue; +#else typedef struct CoQueue { QTAILQ_HEAD(, Coroutine) entries; } CoQueue; +#endif /** * Initialise a CoQueue. This must be called before any other operation is used @@ -145,10 +152,14 @@ bool qemu_co_queue_empty(CoQueue *queue); /** * Provides a mutex that can be used to synchronise coroutines */ +#ifdef CONFIG_GCOROUTINE +typedef GCoMutex CoMutex; +#else typedef struct CoMutex { bool locked; CoQueue queue; } CoMutex; +#endif /** * Initialises a CoMutex. This must be called before any other operation is used @@ -168,11 +179,15 @@ void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex); */ void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex); +#ifdef CONFIG_GCOROUTINE +typedef GCoRWLock CoRwlock; +#else typedef struct CoRwlock { bool writer; int reader; CoQueue queue; } CoRwlock; +#endif /** * Initialises a CoRwlock. This must be called before any other operation