From patchwork Mon Jul 25 20:04:08 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Hajnoczi X-Patchwork-Id: 106745 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 19E9AB6FF5 for ; Tue, 26 Jul 2011 06:04:39 +1000 (EST) Received: from localhost ([::1]:46229 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QlROC-0003cm-Uq for incoming@patchwork.ozlabs.org; Mon, 25 Jul 2011 16:04:32 -0400 Received: from eggs.gnu.org ([140.186.70.92]:53898) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QlRNy-0003cC-Ag for qemu-devel@nongnu.org; Mon, 25 Jul 2011 16:04:22 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QlRNw-0001yP-BS for qemu-devel@nongnu.org; Mon, 25 Jul 2011 16:04:18 -0400 Received: from mtagate2.uk.ibm.com ([194.196.100.162]:40682) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QlRNw-0001y6-1M for qemu-devel@nongnu.org; Mon, 25 Jul 2011 16:04:16 -0400 Received: from d06nrmr1707.portsmouth.uk.ibm.com (d06nrmr1707.portsmouth.uk.ibm.com [9.149.39.225]) by mtagate2.uk.ibm.com (8.13.1/8.13.1) with ESMTP id p6PK4FfX030763 for ; Mon, 25 Jul 2011 20:04:15 GMT Received: from d06av07.portsmouth.uk.ibm.com (d06av07.portsmouth.uk.ibm.com [9.149.37.248]) by d06nrmr1707.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p6PK4F6A2052250 for ; Mon, 25 Jul 2011 21:04:15 +0100 Received: from d06av07.portsmouth.uk.ibm.com (loopback [127.0.0.1]) by d06av07.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p6PK4E11024104 for ; Mon, 25 Jul 2011 14:04:14 -0600 Received: from stefanha-thinkpad.ibm.com (sig-9-146-145-232.uk.ibm.com [9.146.145.232]) by d06av07.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p6PK4BpT024030; Mon, 25 Jul 2011 14:04:13 -0600 From: Stefan Hajnoczi To: Date: Mon, 25 Jul 2011 21:04:08 +0100 Message-Id: <1311624250-1670-3-git-send-email-stefanha@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1311624250-1670-1-git-send-email-stefanha@linux.vnet.ibm.com> References: <1311624250-1670-1-git-send-email-stefanha@linux.vnet.ibm.com> MIME-Version: 1.0 X-MIME-Autoconverted: from 8bit to quoted-printable by mtagate2.uk.ibm.com id p6PK4FfX030763 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 194.196.100.162 Cc: Kevin Wolf , Anthony Liguori , Stefan Hajnoczi , Blue Swirl , "Aneesh Kumar K.V" , Venkateswararao Jujjuri Subject: [Qemu-devel] [PATCH v7 2/4] coroutine: implement coroutines using gthread 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 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 + +########################################## # 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; +}