Re: [gtk-vnc-devel] [RFC] GThread based coroutines
- From: Anthony Liguori <anthony codemonkey ws>
- To: "Daniel P. Berrange" <berrange redhat com>
- Cc: gtk-vnc-devel List <gtk-vnc-devel lists sourceforge net>
- Subject: Re: [gtk-vnc-devel] [RFC] GThread based coroutines
- Date: Wed, 19 Dec 2007 10:48:20 -0500
Daniel P. Berrange wrote:
On Tue, Dec 18, 2007 at 10:51:05PM -0500, Anthony Liguori wrote:
Also, I'm hoping someone who has a bit more autoconf foo can help me
with the proper autoconf/automake integration. We need to detect
ucontext in configure and if it's available, compile in
ucontext_coroutine.[ch], continuation.[ch]. Otherwise, we need to add a
dependency to gthread-2.0 and compile in gthread_coroutine.[ch].
Yep, I can do that pretty easily, but your patch seems to be incomplete.
It only has the removal of existing code & addition of gthread_coroutine,
but not the re-addition of ucontext_coroutine.
Sorry about that. The attached patch has all the right files.
I think I'm also going to refactor so that the GThread bits are
encapsulated at the continuation level instead of the coroutine level.
Regards,
Anthony Liguori
Regards,
Dan.
diff -r 71c9bd03a6c7 src/Makefile.am
--- a/src/Makefile.am Tue Dec 18 21:34:09 2007 -0500
+++ b/src/Makefile.am Wed Dec 19 10:46:43 2007 -0500
@@ -3,7 +3,7 @@ EXTRA_DIST = libgtk-vnc_sym.version vncm
lib_LTLIBRARIES = libgtk-vnc-1.0.la
-libgtk_vnc_1_0_la_LIBADD = @GTK_LIBS@ @GNUTLS_LIBS@
+libgtk_vnc_1_0_la_LIBADD = @GTK_LIBS@ @GNUTLS_LIBS@ -lgthread-2.0
libgtk_vnc_1_0_la_CFLAGS = @GTK_CFLAGS@ @GNUTLS_CFLAGS@ @WARNING_CFLAGS@ \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
@DEBUG_CFLAGS@
@@ -11,11 +11,10 @@ libgtk_vnc_1_0_la_LDFLAGS = -Wl,--versio
-version-info 0:1:0
gtk_vnc_includedir = $(includedir)/gtk-vnc-1.0/
-gtk_vnc_include_HEADERS = vncdisplay.h gvnc.h coroutine.h continuation.h
+gtk_vnc_include_HEADERS = vncdisplay.h gvnc.h coroutine.h gthread_coroutine.h
libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h \
- continuation.h continuation.c \
- coroutine.h coroutine.c \
+ gthread_coroutine.h gthread_coroutine.c \
d3des.h d3des.c \
gvnc.h gvnc.c \
vncdisplay.h vncdisplay.c \
diff -r 71c9bd03a6c7 src/coroutine.c
--- a/src/coroutine.c Tue Dec 18 21:34:09 2007 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2006 Anthony Liguori <anthony codemonkey ws>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * GTK VNC Widget
- */
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "coroutine.h"
-
-int coroutine_release(struct coroutine *co)
-{
- return cc_release(&co->cc);
-}
-
-static int _coroutine_release(struct continuation *cc)
-{
- struct coroutine *co = container_of(cc, struct coroutine, cc);
-
- if (co->release) {
- int ret = co->release(co);
- if (ret < 0)
- return ret;
- }
-
- co->caller = NULL;
-
- return munmap(cc->stack, cc->stack_size);
-}
-
-static void coroutine_trampoline(struct continuation *cc)
-{
- struct coroutine *co = container_of(cc, struct coroutine, cc);
- co->data = co->entry(co->data);
-}
-
-int coroutine_init(struct coroutine *co)
-{
- if (co->stack_size == 0)
- co->stack_size = 16 << 20;
-
- co->cc.stack_size = co->stack_size;
- co->cc.stack = mmap(0, co->stack_size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0);
- if (co->cc.stack == MAP_FAILED)
- return -1;
- co->cc.entry = coroutine_trampoline;
- co->cc.release = _coroutine_release;
- co->exited = 0;
-
- return cc_init(&co->cc);
-}
-
-#if 0
-static __thread struct coroutine leader;
-static __thread struct coroutine *current;
-#else
-static struct coroutine leader;
-static struct coroutine *current;
-#endif
-
-struct coroutine *coroutine_self(void)
-{
- if (current == NULL)
- current = &leader;
- return current;
-}
-
-void *coroutine_swap(struct coroutine *from, struct coroutine *to, void *arg)
-{
- int ret;
- to->data = arg;
- current = to;
- ret = cc_swap(&from->cc, &to->cc);
- if (ret == 0)
- return from->data;
- else if (ret == 1) {
- coroutine_release(to);
- current = &leader;
- to->exited = 1;
- return to->data;
- }
-
- return NULL;
-}
-
-void *coroutine_yieldto(struct coroutine *to, void *arg)
-{
- if (to->caller) {
- fprintf(stderr, "Co-routine is re-entering itself\n");
- abort();
- }
- to->caller = coroutine_self();
- return coroutine_swap(coroutine_self(), to, arg);
-}
-
-void *coroutine_yield(void *arg)
-{
- struct coroutine *to = coroutine_self()->caller;
- if (!to) {
- fprintf(stderr, "Co-routine is yielding to no one\n");
- abort();
- }
- coroutine_self()->caller = NULL;
- return coroutine_swap(coroutine_self(), to, arg);
-}
-/*
- * Local variables:
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- */
diff -r 71c9bd03a6c7 src/coroutine.h
--- a/src/coroutine.h Tue Dec 18 21:34:09 2007 -0500
+++ b/src/coroutine.h Wed Dec 19 10:46:43 2007 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Anthony Liguori <anthony codemonkey ws>
+ * Copyright (C) 2007 Anthony Liguori <anthony codemonkey ws>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2 as
@@ -11,41 +11,10 @@
#ifndef _COROUTINE_H_
#define _COROUTINE_H_
-#include "continuation.h"
-
-struct coroutine
-{
- size_t stack_size;
- void *(*entry)(void *);
- int (*release)(struct coroutine *);
-
- /* read-only */
- int exited;
-
- /* private */
- struct coroutine *caller;
- void *data;
-
- struct continuation cc;
-};
-
-int coroutine_init(struct coroutine *co);
-
-int coroutine_release(struct coroutine *co);
-
-void *coroutine_swap(struct coroutine *from, struct coroutine *to, void *arg);
-
-struct coroutine *coroutine_self(void);
-
-void *coroutine_yieldto(struct coroutine *to, void *arg);
-
-void *coroutine_yield(void *arg);
+#ifdef HAVE_UCONTEXT
+#include "ucontext_corutine.h"
+#else
+#include "gthread_coroutine.h"
+#endif
#endif
-/*
- * Local variables:
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- */
diff -r 71c9bd03a6c7 src/gthread_coroutine.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gthread_coroutine.c Wed Dec 19 10:46:43 2007 -0500
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2007 Anthony Liguori <anthony codemonkey ws>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * GTK VNC Widget
+ */
+
+#include "gthread_coroutine.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static GCond *run_cond;
+static GMutex *run_lock;
+static struct coroutine *current;
+static struct coroutine leader;
+
+static void coroutine_system_init(void)
+{
+ if (!g_thread_supported())
+ g_thread_init(NULL);
+
+ run_cond = g_cond_new();
+ run_lock = g_mutex_new();
+
+ /* The thread that creates the first coroutine is the system coroutine
+ * so let's fill out a structure for it */
+ leader.entry = NULL;
+ leader.release = NULL;
+ leader.stack_size = 0;
+ leader.exited = 0;
+ leader.thread = g_thread_self();
+ leader.runnable = TRUE; /* we're the one running right now */
+ leader.caller = NULL;
+ leader.data = NULL;
+
+ current = &leader;
+}
+
+static gpointer coroutine_thread(gpointer opaque)
+{
+ struct coroutine *co = opaque;
+
+ g_mutex_lock(run_lock);
+ while (!co->runnable)
+ g_cond_wait(run_cond, run_lock);
+
+ current = co;
+ co->data = co->entry(co->data);
+ co->exited = 1;
+
+ co->caller->runnable = TRUE;
+ g_cond_broadcast(run_cond);
+ g_mutex_unlock(run_lock);
+
+ return NULL;
+}
+
+int coroutine_init(struct coroutine *co)
+{
+ if (run_cond == NULL)
+ coroutine_system_init();
+
+ co->thread = g_thread_create_full(coroutine_thread, co, co->stack_size,
+ FALSE, TRUE,
+ G_THREAD_PRIORITY_NORMAL,
+ NULL);
+ if (co->thread == NULL)
+ return -1;
+
+ co->exited = 0;
+ co->runnable = FALSE;
+ co->caller = NULL;
+
+ return 0;
+}
+
+int coroutine_release(struct coroutine *co G_GNUC_UNUSED)
+{
+ /* should we join the thread? */
+ return 0;
+}
+
+void *coroutine_swap(struct coroutine *from, struct coroutine *to, void *arg)
+{
+ from->runnable = FALSE;
+ to->runnable = TRUE;
+ to->data = arg;
+ to->caller = from;
+ g_cond_broadcast(run_cond);
+ g_mutex_unlock(run_lock);
+
+ g_mutex_lock(run_lock);
+ while (!from->runnable)
+ g_cond_wait(run_cond, run_lock);
+
+ current = from;
+
+ return from->data;
+}
+
+struct coroutine *coroutine_self(void)
+{
+ return current;
+}
+
+void *coroutine_yieldto(struct coroutine *to, void *arg)
+{
+ if (to->caller) {
+ fprintf(stderr, "Co-routine is re-entering itself\n");
+ abort();
+ }
+ to->caller = coroutine_self();
+ return coroutine_swap(coroutine_self(), to, arg);
+}
+
+void *coroutine_yield(void *arg)
+{
+ struct coroutine *to = coroutine_self()->caller;
+ if (!to) {
+ fprintf(stderr, "Co-routine is yielding to no one\n");
+ abort();
+ }
+ coroutine_self()->caller = NULL;
+ return coroutine_swap(coroutine_self(), to, arg);
+}
+
diff -r 71c9bd03a6c7 src/gthread_coroutine.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gthread_coroutine.h Wed Dec 19 10:46:43 2007 -0500
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 Anthony Liguori <anthony codemonkey ws>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * GTK VNC Widget
+ */
+
+#ifndef _GTHREAD_COROUTINE_H_
+#define _GTHREAD_COROUTINE_H_
+
+#include <glib.h>
+
+struct coroutine
+{
+ size_t stack_size;
+ void *(*entry)(void *);
+ int (*release)(struct coroutine *);
+
+ /* read-only */
+ int exited;
+
+ /* private */
+ GThread *thread;
+ gboolean runnable;
+ struct coroutine *caller;
+ void *data;
+};
+
+int coroutine_init(struct coroutine *co);
+
+int coroutine_release(struct coroutine *co);
+
+void *coroutine_swap(struct coroutine *from, struct coroutine *to, void *arg);
+
+struct coroutine *coroutine_self(void);
+
+void *coroutine_yieldto(struct coroutine *to, void *arg);
+
+void *coroutine_yield(void *arg);
+
+#endif
diff -r 71c9bd03a6c7 src/ucontext_coroutine.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucontext_coroutine.c Wed Dec 19 10:46:43 2007 -0500
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2006 Anthony Liguori <anthony codemonkey ws>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * GTK VNC Widget
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "ucontext_coroutine.h"
+
+int coroutine_release(struct coroutine *co)
+{
+ return cc_release(&co->cc);
+}
+
+static int _coroutine_release(struct continuation *cc)
+{
+ struct coroutine *co = container_of(cc, struct coroutine, cc);
+
+ if (co->release) {
+ int ret = co->release(co);
+ if (ret < 0)
+ return ret;
+ }
+
+ co->caller = NULL;
+
+ return 0;
+}
+
+static void coroutine_trampoline(struct continuation *cc)
+{
+ struct coroutine *co = container_of(cc, struct coroutine, cc);
+ co->data = co->entry(co->data);
+}
+
+int coroutine_init(struct coroutine *co)
+{
+ co->cc.stack_size = co->stack_size;
+ co->cc.entry = coroutine_trampoline;
+ co->cc.release = _coroutine_release;
+ co->exited = 0;
+
+ return cc_init(&co->cc);
+}
+
+#if 0
+static __thread struct coroutine leader;
+static __thread struct coroutine *current;
+#else
+static struct coroutine leader;
+static struct coroutine *current;
+#endif
+
+struct coroutine *coroutine_self(void)
+{
+ if (current == NULL)
+ current = &leader;
+ return current;
+}
+
+void *coroutine_swap(struct coroutine *from, struct coroutine *to, void *arg)
+{
+ int ret;
+ to->data = arg;
+ current = to;
+ ret = cc_swap(&from->cc, &to->cc);
+ if (ret == 0)
+ return from->data;
+ else if (ret == 1) {
+ coroutine_release(to);
+ current = &leader;
+ to->exited = 1;
+ return to->data;
+ }
+
+ return NULL;
+}
+
+void *coroutine_yieldto(struct coroutine *to, void *arg)
+{
+ if (to->caller) {
+ fprintf(stderr, "Co-routine is re-entering itself\n");
+ abort();
+ }
+ to->caller = coroutine_self();
+ return coroutine_swap(coroutine_self(), to, arg);
+}
+
+void *coroutine_yield(void *arg)
+{
+ struct coroutine *to = coroutine_self()->caller;
+ if (!to) {
+ fprintf(stderr, "Co-routine is yielding to no one\n");
+ abort();
+ }
+ coroutine_self()->caller = NULL;
+ return coroutine_swap(coroutine_self(), to, arg);
+}
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff -r 71c9bd03a6c7 src/ucontext_coroutine.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucontext_coroutine.h Wed Dec 19 10:46:43 2007 -0500
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 Anthony Liguori <anthony codemonkey ws>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * GTK VNC Widget
+ */
+
+#ifndef _UCONTEXT_COROUTINE_H_
+#define _UCONTEXT_COROUTINE_H_
+
+#include "continuation.h"
+
+struct coroutine
+{
+ size_t stack_size;
+ void *(*entry)(void *);
+ int (*release)(struct coroutine *);
+
+ /* read-only */
+ int exited;
+
+ /* private */
+ struct coroutine *caller;
+ void *data;
+
+ struct continuation cc;
+};
+
+int coroutine_init(struct coroutine *co);
+
+int coroutine_release(struct coroutine *co);
+
+void *coroutine_swap(struct coroutine *from, struct coroutine *to, void *arg);
+
+struct coroutine *coroutine_self(void);
+
+void *coroutine_yieldto(struct coroutine *to, void *arg);
+
+void *coroutine_yield(void *arg);
+
+#endif
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]