From d6798e8d30a5de9381a30638223e8283f0817660 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Fri, 13 May 2011 12:20:48 +0200
Subject: [PATCH] allow subclassing of coroutines
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
coroutine-ucontext.c | 45 +++++++++++++++++++++++++++++++++++++--------
coroutine-win32.c | 38 +++++++++++++++++++++++++++++++++-----
qemu-coroutine-int.h | 4 ++--
qemu-coroutine.c | 23 ++++++-----------------
4 files changed, 78 insertions(+), 32 deletions(-)
@@ -27,11 +27,33 @@
#include <ucontext.h>
#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;
@@ -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__
@@ -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
@@ -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