qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] coroutine: always use pooling
@ 2012-09-25 12:44 Paolo Bonzini
  2012-09-26 14:34 ` Peter Maydell
  0 siblings, 1 reply; 3+ messages in thread
From: Paolo Bonzini @ 2012-09-25 12:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, stefanha

It makes sense to use it for other implementations than ucontext, too.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 coroutine-ucontext.c | 43 +------------------------------------------
 qemu-coroutine.c     | 38 ++++++++++++++++++++++++++++++++++++--
 2 file modificati, 37 inserzioni(+), 44 rimozioni(-)

diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c
index 784081a..744f4f6 100644
--- a/coroutine-ucontext.c
+++ b/coroutine-ucontext.c
@@ -34,15 +34,6 @@
 #include <valgrind/valgrind.h>
 #endif
 
-enum {
-    /* Maximum free pool size prevents holding too many freed coroutines */
-    POOL_MAX_SIZE = 64,
-};
-
-/** Free list to speed up creation */
-static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
-static unsigned int pool_size;
-
 typedef struct {
     Coroutine base;
     void *stack;
@@ -96,17 +87,6 @@ static void qemu_coroutine_thread_cleanup(void *opaque)
     g_free(s);
 }
 
-static void __attribute__((destructor)) coroutine_cleanup(void)
-{
-    Coroutine *co;
-    Coroutine *tmp;
-
-    QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
-        g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
-        g_free(co);
-    }
-}
-
 static void __attribute__((constructor)) coroutine_init(void)
 {
     int ret;
@@ -140,7 +120,7 @@ static void coroutine_trampoline(int i0, int i1)
     }
 }
 
-static Coroutine *coroutine_new(void)
+Coroutine *qemu_coroutine_new(void)
 {
     const size_t stack_size = 1 << 20;
     CoroutineUContext *co;
@@ -185,20 +165,6 @@ static Coroutine *coroutine_new(void)
     return &co->base;
 }
 
-Coroutine *qemu_coroutine_new(void)
-{
-    Coroutine *co;
-
-    co = QSLIST_FIRST(&pool);
-    if (co) {
-        QSLIST_REMOVE_HEAD(&pool, pool_next);
-        pool_size--;
-    } else {
-        co = coroutine_new();
-    }
-    return co;
-}
-
 #ifdef CONFIG_VALGRIND_H
 #ifdef CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET
 /* Work around an unused variable in the valgrind.h macro... */
@@ -217,13 +183,6 @@ void qemu_coroutine_delete(Coroutine *co_)
 {
     CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
 
-    if (pool_size < POOL_MAX_SIZE) {
-        QSLIST_INSERT_HEAD(&pool, &co->base, pool_next);
-        co->base.caller = NULL;
-        pool_size++;
-        return;
-    }
-
 #ifdef CONFIG_VALGRIND_H
     valgrind_stack_deregister(co);
 #endif
diff --git a/qemu-coroutine.c b/qemu-coroutine.c
index 600be26..5a86837 100644
--- a/qemu-coroutine.c
+++ b/qemu-coroutine.c
@@ -17,9 +17,26 @@
 #include "qemu-coroutine.h"
 #include "qemu-coroutine-int.h"
 
+enum {
+    /* Maximum free pool size prevents holding too many freed coroutines */
+    POOL_MAX_SIZE = 64,
+};
+
+/** Free list to speed up creation */
+static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
+static unsigned int pool_size;
+
 Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
 {
-    Coroutine *co = qemu_coroutine_new();
+    Coroutine *co;
+
+    co = QSLIST_FIRST(&pool);
+    if (co) {
+        QSLIST_REMOVE_HEAD(&pool, pool_next);
+        pool_size--;
+    } else {
+        co = qemu_coroutine_new();
+    }
     co->entry = entry;
     return co;
 }
@@ -35,13 +52,30 @@ static void coroutine_swap(Coroutine *from, Coroutine *to)
         return;
     case COROUTINE_TERMINATE:
         trace_qemu_coroutine_terminate(to);
-        qemu_coroutine_delete(to);
+
+        if (pool_size < POOL_MAX_SIZE) {
+            QSLIST_INSERT_HEAD(&pool, to, pool_next);
+            to->caller = NULL;
+            pool_size++;
+        } else {
+            qemu_coroutine_delete(to);
+        }
         return;
     default:
         abort();
     }
 }
 
+static void __attribute__((destructor)) coroutine_cleanup(void)
+{
+    Coroutine *co;
+    Coroutine *tmp;
+
+    QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
+        qemu_coroutine_delete(co);
+    }
+}
+
 void qemu_coroutine_enter(Coroutine *co, void *opaque)
 {
     Coroutine *self = qemu_coroutine_self();
-- 
1.7.12

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [Qemu-devel] [PATCH] coroutine: always use pooling
  2012-09-25 12:44 [Qemu-devel] [PATCH] coroutine: always use pooling Paolo Bonzini
@ 2012-09-26 14:34 ` Peter Maydell
  2012-09-26 15:18   ` Paolo Bonzini
  0 siblings, 1 reply; 3+ messages in thread
From: Peter Maydell @ 2012-09-26 14:34 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kwolf, stefanha, qemu-devel

On 25 September 2012 13:44, Paolo Bonzini <pbonzini@redhat.com> wrote:
> It makes sense to use it for other implementations than ucontext, too.
>  Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
>  {
> -    Coroutine *co = qemu_coroutine_new();
> +    Coroutine *co;
> +
> +    co = QSLIST_FIRST(&pool);
> +    if (co) {
> +        QSLIST_REMOVE_HEAD(&pool, pool_next);
> +        pool_size--;
> +    } else {
> +        co = qemu_coroutine_new();
> +    }
>      co->entry = entry;
>      return co;
>  }

Since this is obviously going to blow up badly if it's called
from multiple threads, is there some kind of assert we can add
so that we fail obviously if somebody makes that coding error?
[the difficulty is probably when your backend is the gthread
one, at least I assume creating a coroutine inside a coroutine
is allowed.]

-- PMM

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Qemu-devel] [PATCH] coroutine: always use pooling
  2012-09-26 14:34 ` Peter Maydell
@ 2012-09-26 15:18   ` Paolo Bonzini
  0 siblings, 0 replies; 3+ messages in thread
From: Paolo Bonzini @ 2012-09-26 15:18 UTC (permalink / raw)
  To: Peter Maydell; +Cc: kwolf, stefanha, qemu-devel

Il 26/09/2012 16:34, Peter Maydell ha scritto:
>> It makes sense to use it for other implementations than ucontext, too.
>> >  Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
>> >  {
>> > -    Coroutine *co = qemu_coroutine_new();
>> > +    Coroutine *co;
>> > +
>> > +    co = QSLIST_FIRST(&pool);
>> > +    if (co) {
>> > +        QSLIST_REMOVE_HEAD(&pool, pool_next);
>> > +        pool_size--;
>> > +    } else {
>> > +        co = qemu_coroutine_new();
>> > +    }
>> >      co->entry = entry;
>> >      return co;
>> >  }
> Since this is obviously going to blow up badly if it's called
> from multiple threads, is there some kind of assert we can add
> so that we fail obviously if somebody makes that coding error?
> [the difficulty is probably when your backend is the gthread
> one, at least I assume creating a coroutine inside a coroutine
> is allowed.]

Yes, it is; however, creating a coroutine outside the big QEMU lock is
not allowed.  Since one coroutine only runs at a time the code is safe,
just like the other global variables that are used in
qemu-coroutine-lock.c for example.

Paolo

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-09-26 15:18 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-25 12:44 [Qemu-devel] [PATCH] coroutine: always use pooling Paolo Bonzini
2012-09-26 14:34 ` Peter Maydell
2012-09-26 15:18   ` Paolo Bonzini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).