From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:44961) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QlRuh-0000Ny-M0 for qemu-devel@nongnu.org; Mon, 25 Jul 2011 16:38:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QlRuf-0000Uq-A3 for qemu-devel@nongnu.org; Mon, 25 Jul 2011 16:38:07 -0400 Received: from mail-yx0-f173.google.com ([209.85.213.173]:61514) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QlRuf-0000Um-3J for qemu-devel@nongnu.org; Mon, 25 Jul 2011 16:38:05 -0400 Received: by yxt3 with SMTP id 3so3027866yxt.4 for ; Mon, 25 Jul 2011 13:38:04 -0700 (PDT) Message-ID: <4E2DD429.7010301@codemonkey.ws> Date: Mon, 25 Jul 2011 15:38:01 -0500 From: Anthony Liguori MIME-Version: 1.0 References: <1311624250-1670-1-git-send-email-stefanha@linux.vnet.ibm.com> <1311624250-1670-3-git-send-email-stefanha@linux.vnet.ibm.com> In-Reply-To: <1311624250-1670-3-git-send-email-stefanha@linux.vnet.ibm.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Subject: Re: [Qemu-devel] [PATCH v7 2/4] coroutine: implement coroutines using gthread List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Stefan Hajnoczi Cc: Kevin Wolf , Anthony Liguori , qemu-devel@nongnu.org, Blue Swirl , "Aneesh Kumar K.V" , Venkateswararao Jujjuri On 07/25/2011 03:04 PM, Stefan Hajnoczi wrote: > From: "Aneesh Kumar K.V" > > On platforms that don't support makecontext(3) use gthread based > coroutine implementation. > > Darwin has makecontext(3) but getcontext(3) is stubbed out to return > ENOTSUP. Andreas Färber debugged this and > contributed the ./configure test which solves the issue for Darwin/ppc64 > (and ppc) v10.5. > > [Original patch by Aneesh, made consistent with coroutine-ucontext.c and > switched to GStaticPrivate by Stefan. Tested on Linux and OpenBSD.] > > Signed-off-by: Aneesh Kumar K.V > Signed-off-by: Stefan Hajnoczi > --- > Makefile.objs | 4 ++ > configure | 18 +++++++ > coroutine-gthread.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 153 insertions(+), 0 deletions(-) > create mode 100644 coroutine-gthread.c > > diff --git a/Makefile.objs b/Makefile.objs > index 28e1762..5679e1f 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -13,7 +13,11 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o > ####################################################################### > # coroutines > coroutine-obj-y = qemu-coroutine.o > +ifeq ($(CONFIG_UCONTEXT_COROUTINE),y) > coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o > +else > +coroutine-obj-$(CONFIG_POSIX) += coroutine-gthread.o > +endif > coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o > > ####################################################################### > diff --git a/configure b/configure > index 600da9b..1b6ad87 100755 > --- a/configure > +++ b/configure > @@ -2499,6 +2499,20 @@ if test "$trace_backend" = "dtrace"; then > fi > > ########################################## > +# check if we have makecontext > + > +ucontext_coroutine=no > +if test "$darwin" != "yes"; then > + cat> $TMPC<< EOF > +#include > +int main(void) { makecontext(0, 0, 0); } > +EOF > + if compile_prog "" "" ; then > + ucontext_coroutine=yes > + fi > +fi > + Doesn't this make the build non-bisectable on platforms that don't have makecontext? I think the gthread patch needs to come first and then the ucontext version can be used on platforms that we detect it's there. Regards, Anthony Liguori > +########################################## > # End of CC checks > # After here, no more $cc or $ld runs > > @@ -2970,6 +2984,10 @@ if test "$rbd" = "yes" ; then > echo "CONFIG_RBD=y">> $config_host_mak > fi > > +if test "$ucontext_coroutine" = "yes" ; then > + echo "CONFIG_UCONTEXT_COROUTINE=y">> $config_host_mak > +fi > + > # USB host support > case "$usb" in > linux) > diff --git a/coroutine-gthread.c b/coroutine-gthread.c > new file mode 100644 > index 0000000..f09877e > --- /dev/null > +++ b/coroutine-gthread.c > @@ -0,0 +1,131 @@ > +/* > + * GThread coroutine initialization code > + * > + * Copyright (C) 2006 Anthony Liguori > + * Copyright (C) 2011 Aneesh Kumar K.V > + * > + * 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 "qemu-coroutine-int.h" > + > +typedef struct { > + Coroutine base; > + GThread *thread; > + bool runnable; > + CoroutineAction action; > +} CoroutineGThread; > + > +static GCond *coroutine_cond; > +static GStaticMutex coroutine_lock = G_STATIC_MUTEX_INIT; > +static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT; > + > +static void __attribute__((constructor)) coroutine_init(void) > +{ > + if (!g_thread_supported()) { > + g_thread_init(NULL); > + } > + > + coroutine_cond = g_cond_new(); > +} > + > +static void coroutine_wait_runnable_locked(CoroutineGThread *co) > +{ > + while (!co->runnable) { > + g_cond_wait(coroutine_cond, g_static_mutex_get_mutex(&coroutine_lock)); > + } > +} > + > +static void coroutine_wait_runnable(CoroutineGThread *co) > +{ > + g_static_mutex_lock(&coroutine_lock); > + coroutine_wait_runnable_locked(co); > + g_static_mutex_unlock(&coroutine_lock); > +} > + > +static gpointer coroutine_thread(gpointer opaque) > +{ > + CoroutineGThread *co = opaque; > + > + g_static_private_set(&coroutine_key, co, NULL); > + coroutine_wait_runnable(co); > + co->base.entry(co->base.entry_arg); > + qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE); > + return NULL; > +} > + > +Coroutine *qemu_coroutine_new(void) > +{ > + CoroutineGThread *co; > + > + co = qemu_mallocz(sizeof(*co)); > + co->thread = g_thread_create_full(coroutine_thread, co, 0, TRUE, TRUE, > + G_THREAD_PRIORITY_NORMAL, NULL); > + if (!co->thread) { > + qemu_free(co); > + return NULL; > + } > + return&co->base; > +} > + > +void qemu_coroutine_delete(Coroutine *co_) > +{ > + CoroutineGThread *co = DO_UPCAST(CoroutineGThread, base, co_); > + > + g_thread_join(co->thread); > + qemu_free(co); > +} > + > +CoroutineAction qemu_coroutine_switch(Coroutine *from_, > + Coroutine *to_, > + CoroutineAction action) > +{ > + CoroutineGThread *from = DO_UPCAST(CoroutineGThread, base, from_); > + CoroutineGThread *to = DO_UPCAST(CoroutineGThread, base, to_); > + > + g_static_mutex_lock(&coroutine_lock); > + from->runnable = false; > + from->action = action; > + to->runnable = true; > + to->action = action; > + g_cond_broadcast(coroutine_cond); > + > + if (action != COROUTINE_TERMINATE) { > + coroutine_wait_runnable_locked(from); > + } > + g_static_mutex_unlock(&coroutine_lock); > + return from->action; > +} > + > +Coroutine *qemu_coroutine_self(void) > +{ > + CoroutineGThread *co = g_static_private_get(&coroutine_key); > + > + if (!co) { > + co = qemu_mallocz(sizeof(*co)); > + co->runnable = true; > + g_static_private_set(&coroutine_key, co, (GDestroyNotify)qemu_free); > + } > + > + return&co->base; > +} > + > +bool qemu_in_coroutine(void) > +{ > + CoroutineGThread *co = g_static_private_get(&coroutine_key); > + > + return co&& co->base.caller; > +}