From patchwork Fri May 13 10:32:10 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 95456 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 59C36B6F08 for ; Fri, 13 May 2011 20:32:37 +1000 (EST) Received: from localhost ([::1]:36106 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QKpfe-0006NK-M5 for incoming@patchwork.ozlabs.org; Fri, 13 May 2011 06:32:34 -0400 Received: from eggs.gnu.org ([140.186.70.92]:47246) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QKpfO-0006Mq-B2 for qemu-devel@nongnu.org; Fri, 13 May 2011 06:32:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QKpfM-0006RY-EO for qemu-devel@nongnu.org; Fri, 13 May 2011 06:32:18 -0400 Received: from mail-ww0-f53.google.com ([74.125.82.53]:33025) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QKpfM-0006RA-3e for qemu-devel@nongnu.org; Fri, 13 May 2011 06:32:16 -0400 Received: by wwj40 with SMTP id 40so2414118wwj.10 for ; Fri, 13 May 2011 03:32:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:message-id:date:from:user-agent :mime-version:newsgroups:to:cc:subject:references:in-reply-to :content-type; bh=X9kIf43vBkQ1vknLbqMakrzut2duBFJtEjoxoAlEMxA=; b=m0pjUozOPKq66MSnxzVzxCKUqqSqHLPaLhHFyCh8ZrBq4Q7LPNiiZsliIldIZu84OQ IIYVHkwD9R3Txoo7+EUPVAZj/GE3HNOFxD7wNoh6/ltsfVw6oCyQqObfi7pYNJIOF7VJ X65sMNo70HaI8h37ECbJ7766RKs1V2CP5zAs8= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:message-id:date:from:user-agent:mime-version:newsgroups:to :cc:subject:references:in-reply-to:content-type; b=wxo6QjMrtQR5zOBbj7399TrJpfIjJvy+cx6mGPKNpn4RlVa7rIVnggYY2HmrvWeeB9 cKweYXZpOnE7CfSe7j3LdW8m8U+wOWA9VE1e9nnf85pWvBZb2gM1SaI1ShzPbGOopfk9 NM0gZvcaP0e2zjFYcDOeixjzoXSZWMmHhAQCM= Received: by 10.217.7.72 with SMTP id z50mr422849wes.60.1305282735033; Fri, 13 May 2011 03:32:15 -0700 (PDT) Received: from yakj.usersys.redhat.com (93-34-184-88.ip51.fastwebnet.it [93.34.184.88]) by mx.google.com with ESMTPS id m84sm1063503weq.12.2011.05.13.03.32.12 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 13 May 2011 03:32:13 -0700 (PDT) Message-ID: <4DCD08AA.7060205@redhat.com> Date: Fri, 13 May 2011 12:32:10 +0200 From: Paolo Bonzini User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc14 Lightning/1.0b3pre Mnenhy/0.8.3 Thunderbird/3.1.10 MIME-Version: 1.0 Newsgroups: gmane.comp.emulators.qemu To: Stefan Hajnoczi References: <1305278792-20933-1-git-send-email-stefanha@linux.vnet.ibm.com> <1305278792-20933-2-git-send-email-stefanha@linux.vnet.ibm.com> In-Reply-To: <1305278792-20933-2-git-send-email-stefanha@linux.vnet.ibm.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 74.125.82.53 Cc: Kevin Wolf , Blue Swirl , Anthony Liguori , qemu-devel@nongnu.org Subject: Re: [Qemu-devel] [PATCH v3 1/4] coroutine: introduce coroutines 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 On 05/13/2011 11:26 AM, Stefan Hajnoczi wrote: > This coroutines implementation is based on the gtk-vnc implementation > written by Anthony Liguori but it has been > significantly rewritten by Kevin Wolf to use > setjmp()/longjmp() instead of the more expensive swapcontext(). Since in the future we'll have at least three implementations of coroutines (ucontext, win32 fibers, threads) can you squash in something like the attached to allow "subclassing" of coroutines using DO_UPCAST)? Resolving conflicts with 4/4 should be trivial (Sorry for not doing my homework completely; I started describing in English what I had in mind, but it was too much of a mouthful). Paolo From d6798e8d30a5de9381a30638223e8283f0817660 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 13 May 2011 12:20:48 +0200 Subject: [PATCH] allow subclassing of coroutines Signed-off-by: Paolo Bonzini --- coroutine-ucontext.c | 45 +++++++++++++++++++++++++++++++++++++-------- coroutine-win32.c | 38 +++++++++++++++++++++++++++++++++----- qemu-coroutine-int.h | 4 ++-- qemu-coroutine.c | 23 ++++++----------------- 4 files changed, 78 insertions(+), 32 deletions(-) diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c index 3a8973e..14a0e81 100644 --- a/coroutine-ucontext.c +++ b/coroutine-ucontext.c @@ -27,11 +27,33 @@ #include #include "qemu-coroutine-int.h" -static Coroutine *new_coroutine; +struct CoroutineUContext { + Coroutine base; + + jmp_buf env; +}; + +typedef struct CoroutineUContext CoroutineUContext; + +static CoroutineUContext *new_coroutine; + +int qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, int action) +{ + CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_); + CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_); + int ret; + + ret = setjmp(from->env); + if (ret == 0) { + longjmp(to->env, action); + } else { + return ret; + } +} static void continuation_trampoline(void) { - Coroutine *co = new_coroutine; + CoroutineUContext *co = new_coroutine; /* Initialize longjmp environment and switch back to * qemu_coroutine_init_env() in the old ucontext. */ @@ -40,16 +62,23 @@ static void continuation_trampoline(void) } while (true) { - co->entry(co->data); - if (!setjmp(co->env)) { - longjmp(co->caller->env, COROUTINE_TERMINATE); - } + co->base.entry(co->base.data); + qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE); } } -int qemu_coroutine_init_env(Coroutine *co, size_t stack_size) +Coroutine *qemu_coroutine_new(size_t stack_size) +{ + CoroutineUContext *co; + co = qemu_mallocz(sizeof(*co)); + co->base.stack = qemu_malloc(stack_size); + return &co->base; +} + +int qemu_coroutine_init_env(Coroutine *co_, size_t stack_size) { ucontext_t old_uc, uc; + CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); /* Create a new ucontext for switching to the coroutine stack and setting * up a longjmp environment. */ @@ -58,7 +87,7 @@ int qemu_coroutine_init_env(Coroutine *co, size_t stack_size) } uc.uc_link = &old_uc; - uc.uc_stack.ss_sp = co->stack; + uc.uc_stack.ss_sp = co->base.stack; uc.uc_stack.ss_size = stack_size; uc.uc_stack.ss_flags = 0; diff --git a/coroutine-win32.c b/coroutine-win32.c index 99141dd..5301975 100644 --- a/coroutine-win32.c +++ b/coroutine-win32.c @@ -24,20 +24,48 @@ #include "qemu-coroutine-int.h" -static void __attribute__((used)) trampoline(Coroutine *co) +struct CoroutineWin32 { + Coroutine base; + + jmp_buf env; +}; + +typedef struct CoroutineWin32 CoroutineWin32; + +int qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, int action) +{ + CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_); + CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_); + int ret; + + ret = setjmp(from->env); + if (ret == 0) { + longjmp(to->env, action); + } else { + return ret; + } +} + +static void __attribute__((used)) trampoline(CoroutineWin32 *co) { if (!setjmp(co->env)) { return; } while (true) { - co->entry(co->data); - if (!setjmp(co->env)) { - longjmp(co->caller->env, COROUTINE_TERMINATE); - } + co->base.entry(co->base.data); + qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE); } } +Coroutine *qemu_coroutine_new(size_t stack_size) +{ + CoroutineWin32 *co; + co = qemu_mallocz(sizeof(*co)); + co->base.stack = qemu_malloc(stack_size); + return &co->base; +} + int qemu_coroutine_init_env(Coroutine *co, size_t stack_size) { #ifdef __i386__ diff --git a/qemu-coroutine-int.h b/qemu-coroutine-int.h index 71c6ee9..04eb41a 100644 --- a/qemu-coroutine-int.h +++ b/qemu-coroutine-int.h @@ -44,10 +44,10 @@ struct Coroutine { /* Used to pass arguments/return values for coroutines */ void *data; CoroutineEntry *entry; - - jmp_buf env; }; int qemu_coroutine_init_env(Coroutine *co, size_t stack_size); +int qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, int action); +Coroutine *qemu_coroutine_new(size_t stack_size); #endif diff --git a/qemu-coroutine.c b/qemu-coroutine.c index a80468b..02c345d 100644 --- a/qemu-coroutine.c +++ b/qemu-coroutine.c @@ -34,24 +34,15 @@ static void coroutine_terminate(Coroutine *co) qemu_free(co); } -static Coroutine *coroutine_new(void) -{ - const size_t stack_size = 4 << 20; - Coroutine *co; - - co = qemu_mallocz(sizeof(*co)); - co->stack = qemu_malloc(stack_size); - qemu_coroutine_init_env(co, stack_size); - return co; -} - Coroutine *qemu_coroutine_create(CoroutineEntry *entry) { + const size_t stack_size = 4 << 20; Coroutine *co; - co = coroutine_new(); + co = qemu_coroutine_new(stack_size); co->entry = entry; + qemu_coroutine_init_env(co, stack_size); return co; } @@ -76,7 +67,8 @@ static void *coroutine_swap(Coroutine *from, Coroutine *to, void *opaque) to->data = opaque; - ret = setjmp(from->env); + current = to; + ret = qemu_coroutine_switch(from, to, COROUTINE_YIELD); switch (ret) { case COROUTINE_YIELD: return from->data; @@ -86,10 +78,7 @@ static void *coroutine_swap(Coroutine *from, Coroutine *to, void *opaque) coroutine_terminate(to); return to_data; default: - /* Switch to called coroutine */ - current = to; - longjmp(to->env, COROUTINE_YIELD); - return NULL; + abort(); } } -- 1.7.4.4