qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] coroutine: Implement coroutines using gthread


From: Bastien ROUCARIES
Subject: Re: [Qemu-devel] [PATCH] coroutine: Implement coroutines using gthread
Date: Sat, 11 Jun 2011 14:27:24 +0200
User-agent: KMail/1.13.5 (Linux/2.6.37-trunk-amd64; KDE/4.4.5; x86_64; ; )

Le jeudi 9 juin 2011 19:41:06, Aneesh Kumar K.V a écrit :
> On platforms that doesn't support makecontext use gthread
> based coroutine implementation.

Why not using one of the existing lib of coroutine or improving it ?

Could you give some hints ?

Why not use http://cvs.schmorp.de/libcoro/coro.h what is the base of the perl 
coroutine lib and thus well tested on a lot of 
plateform?

Bastien

> 
> Signed-off-by: Aneesh Kumar K.V <address@hidden>
> ---
> 
> NOTE: Tested on linux with force compliation of coroutine-gthread.c
> 
>  Makefile.objs       |    5 ++
>  configure           |   18 +++++
>  coroutine-gthread.c |  172
> +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195
> insertions(+), 0 deletions(-)
>  create mode 100644 coroutine-gthread.c
> 
> diff --git a/Makefile.objs b/Makefile.objs
> index 0f1d7df..d354d3c 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -13,9 +13,14 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o
> qemu-thread-posix.o
> ####################################################################### #
> coroutines
>  coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.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
> 
> +
>  #######################################################################
>  # block-obj-y is code used by both qemu system emulation and qemu-img
> 
> diff --git a/configure b/configure
> index 980914a..529d8c4 100755
> --- a/configure
> +++ b/configure
> @@ -2568,6 +2568,20 @@ if test "$trace_backend" = "dtrace"; then
>  fi
> 
>  ##########################################
> +# check if we have makecontext
> +
> +ucontext_coroutine=no
> +cat > $TMPC << EOF
> +#include <ucontext.h>
> +int main(void) { makecontext(0, 0, 0); }
> +EOF
> +if compile_prog "" "" ; then
> +    ucontext_coroutine=yes
> +fi
> +
> +
> +
> +##########################################
>  # End of CC checks
>  # After here, no more $cc or $ld runs
> 
> @@ -3031,6 +3045,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..37e5a16
> --- /dev/null
> +++ b/coroutine-gthread.c
> @@ -0,0 +1,172 @@
> +/*
> + *
> + * Copyright (C) 2006  Anthony Liguori <address@hidden>
> + * Copyright (C) 2011  Aneesh Kumar K.V <address@hidden>
> + *
> + * 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, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
> 02110-1301 USA + */
> +
> +#include "qemu-common.h"
> +#include "qemu-coroutine-int.h"
> +#include <glib.h>
> +
> +typedef struct {
> +    Coroutine qemu_co;
> +    GThread *thread;
> +    gboolean runnable;
> +} CoroutineGthread;
> +
> +typedef struct {
> +    /** Currently executing coroutine */
> +    CoroutineGthread *current;
> +
> +    /** The default coroutine */
> +    CoroutineGthread leader;
> +} CoroutineThreadState;
> +
> +static GCond *run_cond;
> +static GMutex *run_lock;
> +static pthread_key_t thread_state_key;
> +
> +static void qemu_coroutine_thread_cleanup(void *opaque)
> +{
> +    CoroutineThreadState *s = opaque;
> +
> +    qemu_free(s);
> +}
> +
> +static void __attribute__((constructor)) coroutine_system_init(void)
> +{
> +    int ret;
> +    if (!g_thread_supported()) {
> +        g_thread_init(NULL);
> +    }
> +    run_cond = g_cond_new();
> +    run_lock = g_mutex_new();
> +
> +    ret = pthread_key_create(&thread_state_key,
> qemu_coroutine_thread_cleanup); +    if (ret != 0) {
> +        fprintf(stderr, "unable to create leader key: %s\n",
> strerror(errno)); +        abort();
> +    }
> +}
> +
> +static CoroutineThreadState *coroutine_get_thread_state(void)
> +{
> +    CoroutineThreadState *s = pthread_getspecific(thread_state_key);
> +
> +    if (!s) {
> +        s = qemu_mallocz(sizeof(*s));
> +        s->current = &s->leader;
> +        pthread_setspecific(thread_state_key, s);
> +    }
> +    return s;
> +}
> +
> +static gpointer coroutine_thread(gpointer opaque)
> +{
> +    CoroutineGthread *co = opaque;
> +    CoroutineThreadState *s = coroutine_get_thread_state();
> +
> +    s->current  = co;
> +
> +    /* Wait for somebody make it runnable */
> +    g_mutex_lock(run_lock);
> +    while (!co->runnable) {
> +        g_cond_wait(run_cond, run_lock);
> +    }
> +    g_mutex_unlock(run_lock);
> +    /*
> +     * run the coroutine function
> +     * Coroutines can run in parallel.
> +     */
> +    co->qemu_co.entry(co->qemu_co.entry_arg);
> +
> +    /* Now yield with terminating status */
> +    qemu_coroutine_switch(&co->qemu_co,
> +                          co->qemu_co.caller, COROUTINE_TERMINATE);
> +    return NULL;
> +}
> +
> +Coroutine *qemu_coroutine_new(void)
> +{
> +    CoroutineGthread *co;
> +    if (run_cond == NULL) {
> +        abort();
> +    }
> +    co = qemu_mallocz(sizeof(*co));
> +    co->runnable = FALSE;
> +    co->thread = g_thread_create_full(coroutine_thread, co, 0,
> +                                      FALSE, TRUE,
> +                                      G_THREAD_PRIORITY_NORMAL,
> +                                      NULL);
> +    if (co->thread == NULL) {
> +        qemu_free(co);
> +        return NULL;
> +    }
> +    co->qemu_co.caller = NULL;
> +    return &co->qemu_co;
> +}
> +
> +Coroutine *qemu_coroutine_self(void)
> +{
> +    CoroutineThreadState *s = coroutine_get_thread_state();
> +
> +    return &s->current->qemu_co;
> +}
> +
> +CoroutineAction qemu_coroutine_switch(Coroutine *qemu_co_from,
> +                                      Coroutine *qemu_co_to,
> +                                      CoroutineAction action)
> +{
> +    CoroutineGthread *from = DO_UPCAST(CoroutineGthread, qemu_co,
> qemu_co_from); +    CoroutineGthread *to = DO_UPCAST(CoroutineGthread,
> qemu_co, qemu_co_to); +
> +    /* Wakeup the runnable to coroutine */
> +    g_mutex_lock(run_lock);
> +    to->qemu_co.caller = qemu_co_from;
> +    from->runnable = FALSE;
> +    to->runnable = TRUE;
> +    g_cond_broadcast(run_cond);
> +    g_mutex_unlock(run_lock);
> +
> +    /* Don't wait if we are going to terminate */
> +    if (action == COROUTINE_TERMINATE) {
> +        return action;
> +    }
> +
> +    /* Now wait for somebody to make from runnable */
> +    g_mutex_lock(run_lock);
> +    while (!from->runnable) {
> +        g_cond_wait(run_cond, run_lock);
> +    }
> +    g_mutex_unlock(run_lock);
> +    return action;
> +}
> +
> +bool qemu_in_coroutine(void)
> +{
> +    CoroutineThreadState *s = pthread_getspecific(thread_state_key);
> +
> +    return s && s->current->qemu_co.caller;
> +}
> +
> +void qemu_coroutine_delete(Coroutine *qemu_co)
> +{
> +    CoroutineGthread *co = DO_UPCAST(CoroutineGthread, qemu_co, qemu_co);
> +    qemu_free(co);
> +    return;
> +}
> +



reply via email to

[Prev in Thread] Current Thread [Next in Thread]