[PATCH] Add support to GCoroutine



Use GCoroutine, for now optionally, instead of gtk-vnc's own
coroutine implementations.

GCoroutine is library that provides a better coroutine implementation
based on qemu and spice-gtk code and is going to be used for qemu and
spice-gtk as well. The project lives in elmarco's github:
https://github.com/elmarco/gcoroutine
---
 configure.ac        | 74 ++++++++++++++++++++++++++-------------
 src/Makefile.am     | 11 ++++--
 src/vncconnection.c | 99 ++++++++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 137 insertions(+), 47 deletions(-)

diff --git a/configure.ac b/configure.ac
index ecb33cf..150b6c1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -301,41 +301,66 @@ AM_CONDITIONAL([HAVE_SASL], [test "x$with_sasl2" = "xyes" || test "x$with_sasl"
 AC_SUBST([SASL_CFLAGS])
 AC_SUBST([SASL_LIBS])
 
+AC_CHECK_LIB(z, inflate, [], [AC_MSG_ERROR([zlib not found])])
+
+AC_ARG_WITH([gcoroutine],
+  [AS_HELP_STRING([--with-gcoroutine=@<:@auto/yes/no@:>@],
+                  [use GCoroutine for coroutines instead of the own gtk-vnc implementation 
@<:@default=auto@:>@])],
+  [],
+  [with_gcoroutine="auto"])
+
+if test "x$with_gcoroutine" == "xauto" ; then
+  if ${PKG_CONFIG} gcoroutine-1.0 ; then
+    with_gcoroutine=yes;
+  else
+    with_gcoroutine=no;
+  fi
+fi
 
 GTHREAD_CFLAGS=
 GTHREAD_LIBS=
 
-AC_CHECK_LIB(z, inflate, [], [AC_MSG_ERROR([zlib not found])])
-
 WITH_UCONTEXT=1
 
-AC_ARG_WITH(coroutine,
-[  --with-coroutine=ucontext/gthread  use ucontext or GThread for coroutines],
-[],[with_coroutine=ucontext])
+if test "x$with_gcoroutine" == "xyes" ; then
+  PKG_CHECK_MODULES(GCOROUTINE, gcoroutine-1.0 >= 0.1.10)
+  AC_SUBST([GCOROUTINE_CFLAGS])
+  AC_SUBST([GCOROUTINE_LIBS])
 
-case $with_coroutine in
-  ucontext)
-    ;;
-  gthread)
-    ;;
-  *)
-    AC_MSG_ERROR(Unsupported coroutine type)
-esac
+  AC_DEFINE_UNQUOTED([WITH_GCOROUTINE], 1,
+    [Whether GCoroutine is available for coroutines])
 
-if test "$with_coroutine" = "ucontext"; then
-  AC_CHECK_FUNC(makecontext, [],[with_coroutine=gthread])
-  AC_CHECK_FUNC(swapcontext, [],[with_coroutine=gthread])
-  AC_CHECK_FUNC(getcontext, [],[with_coroutine=gthread])
-fi
+else
+  AC_ARG_WITH(coroutine,
+  [  --with-coroutine=ucontext/gthread use ucontext or GThread for coroutines],
+  [],[with_coroutine=ucontext])
+
+  case $with_coroutine in
+    ucontext)
+      ;;
+    gthread)
+      ;;
+    *)
+      AC_MSG_ERROR(Unsupported coroutine type)
+  esac
+
+  if test "$with_coroutine" = "ucontext"; then
+    AC_CHECK_FUNC(makecontext, [],[with_coroutine=gthread])
+    AC_CHECK_FUNC(swapcontext, [],[with_coroutine=gthread])
+    AC_CHECK_FUNC(getcontext, [],[with_coroutine=gthread])
+  fi
 
-if test "$with_coroutine" = "gthread"; then
-  PKG_CHECK_MODULES(GTHREAD, gthread-2.0 > $GTHREAD_REQUIRED)
-  WITH_UCONTEXT=0
+  if test "$with_coroutine" = "gthread"; then
+    PKG_CHECK_MODULES(GTHREAD, gthread-2.0 > $GTHREAD_REQUIRED)
+    WITH_UCONTEXT=0
+  fi
+  AC_SUBST(GTHREAD_CFLAGS)
+  AC_SUBST(GTHREAD_LIBS)
+  AC_DEFINE_UNQUOTED([WITH_UCONTEXT],[$WITH_UCONTEXT], [Whether to use ucontext coroutine impl])
 fi
-AC_SUBST(GTHREAD_CFLAGS)
-AC_SUBST(GTHREAD_LIBS)
-AC_DEFINE_UNQUOTED([WITH_UCONTEXT],[$WITH_UCONTEXT], [Whether to use ucontext coroutine impl])
+
 AM_CONDITIONAL(WITH_UCONTEXT, [test "$WITH_UCONTEXT" != "0"])
+AM_CONDITIONAL(WITH_GCOROUTINE, [test "x$with_gcoroutine" == "xyes"])
 
 if test "$WITH_PYTHON" = "yes"; then
   PKG_CHECK_MODULES(PYGTK, pygtk-2.0 >= $PYGTK_REQUIRED)
@@ -449,4 +474,5 @@ Configure summary:
        SASL support................:  ${enable_sasl}
        PulseAudio support..........:  ${HAVE_PULSEAUDIO}
        GTK+ version................:  ${GTK_API_VERSION}
+       GCoroutine support..........:  ${with_gcoroutine}
 "
diff --git a/src/Makefile.am b/src/Makefile.am
index f143c90..e6fbc0e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,14 +34,12 @@ endif
 libgvnc_1_0_la_LIBADD = \
                        $(GOBJECT_LIBS) \
                        $(GIO_LIBS) \
-                       $(GTHREAD_LIBS) \
                        $(GDK_PIXBUF_LIBS) \
                        $(GNUTLS_LIBS) \
                        $(SASL_LIBS)
 libgvnc_1_0_la_CFLAGS = \
                        $(GOBJECT_CFLAGS) \
                        $(GIO_CFLAGS) \
-                       $(GTHREAD_CFLAGS) \
                        $(GDK_PIXBUF_CFLAGS) \
                        $(GNUTLS_CFLAGS) \
                        $(SASL_CFLAGS) \
@@ -120,13 +118,20 @@ libgvncpulse_1_0_la_LDFLAGS = \
                        -version-info 0:1:0 $(NO_UNDEFINED_FLAGS)
 endif
 
+if WITH_GCOROUTINE
+libgvnc_1_0_la_LIBADD += $(GCOROUTINE_LIBS)
+libgvnc_1_0_la_CFLAGS += $(GCOROUTINE_CFLAGS)
+else
+libgvnc_1_0_la_LIBADD += $(GTHREAD_LIBS)
+libgvnc_1_0_la_CFLAGS += $(GTHREAD_CFLAGS)
 if WITH_UCONTEXT
 libgvnc_1_0_la_SOURCES += continuation.h continuation.c coroutine_ucontext.c
 EXTRA_DIST += coroutine_gthread.c
 else
 libgvnc_1_0_la_SOURCES += coroutine_gthread.c
 EXTRA_DIST += continuation.h continuation.c coroutine_ucontext.c
-endif
+endif #WITH_UCONTEXT
+endif #WITH_GCOROUTINE
 
 gtk_vnc_LIBADD = \
                        $(GTK_LIBS) \
diff --git a/src/vncconnection.c b/src/vncconnection.c
index ca4d239..cfe8dd5 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -37,7 +37,12 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#ifdef WITH_GCOROUTINE
+#include <gcoroutine.h>
+#else
 #include "coroutine.h"
+#endif
+
 #include "d3des.h"
 
 #include <gnutls/gnutls.h>
@@ -61,10 +66,22 @@
 #define g_mutex_free(m) g_free(m)
 #endif
 
+#ifndef WITH_GCOROUTINE
+
+#define g_coroutine_self() coroutine_self()
+#define g_coroutine_yield(d) coroutine_yield(d)
+#define g_coroutine_resume(c, d) coroutine_yieldto(c, d)
+
+#endif
+
 struct wait_queue
 {
     gboolean waiting;
+#ifdef WITH_GCOROUTINE
+    GCoroutine *context;
+#else
     struct coroutine *context;
+#endif
 };
 
 typedef enum {
@@ -132,7 +149,11 @@ typedef gboolean (*g_condition_wait_func)(gpointer);
 struct g_condition_wait_source
 {
     GSource src;
+#ifdef WITH_GCOROUTINE
+    GCoroutine *co;
+#else
     struct coroutine *co;
+#endif
     g_condition_wait_func func;
     gpointer data;
 };
@@ -143,7 +164,11 @@ struct g_condition_wait_source
 
 struct _VncConnectionPrivate
 {
+#ifdef WITH_GCOROUTINE
+    GCoroutine *coroutine;
+#else
     struct coroutine coroutine;
+#endif
     guint open_id;
     GSocket *sock;
     GSocketAddress *addr;
@@ -278,8 +303,12 @@ static gboolean g_io_wait_helper(GSocket *sock G_GNUC_UNUSED,
                                  GIOCondition cond,
                                  gpointer data)
 {
+#ifdef WITH_GCOROUTINE
+    GCoroutine *to = data;
+#else
     struct coroutine *to = data;
-    coroutine_yieldto(to, &cond);
+#endif
+    g_coroutine_resume(to, &cond);
     return FALSE;
 }
 
@@ -289,9 +318,9 @@ static GIOCondition g_io_wait(GSocket *sock, GIOCondition cond)
     GSource *src = g_socket_create_source(sock,
                                           cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
                                           NULL);
-    g_source_set_callback(src, (GSourceFunc)g_io_wait_helper, coroutine_self(), NULL);
+    g_source_set_callback(src, (GSourceFunc)g_io_wait_helper, g_coroutine_self(), NULL);
     g_source_attach(src, NULL);
-    ret = coroutine_yield(NULL);
+    ret = g_coroutine_yield(NULL);
     g_source_unref(src);
     return *ret;
 }
@@ -304,7 +333,7 @@ static GIOCondition g_io_wait_interruptable(struct wait_queue *wait,
     GIOCondition *ret;
     gint id;
 
-    wait->context = coroutine_self();
+    wait->context = g_coroutine_self();
     GSource *src = g_socket_create_source(sock,
                                           cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
                                           NULL);
@@ -312,7 +341,7 @@ static GIOCondition g_io_wait_interruptable(struct wait_queue *wait,
                           wait->context, NULL);
     id = g_source_attach(src, NULL);
     wait->waiting = TRUE;
-    ret = coroutine_yield(NULL);
+    ret = g_coroutine_yield(NULL);
     g_source_unref(src);
     wait->waiting = FALSE;
 
@@ -326,7 +355,7 @@ static GIOCondition g_io_wait_interruptable(struct wait_queue *wait,
 static void g_io_wakeup(struct wait_queue *wait)
 {
     if (wait->waiting)
-        coroutine_yieldto(wait->context, NULL);
+        g_coroutine_resume(wait->context, NULL);
 }
 
 
@@ -365,8 +394,12 @@ GSourceFuncs waitFuncs = {
 
 static gboolean g_condition_wait_helper(gpointer data)
 {
+#ifdef WITH_GCOROUTINE
+    GCoroutine *co = data;
+#else
     struct coroutine *co = (struct coroutine *)data;
-    coroutine_yieldto(co, NULL);
+#endif
+    g_coroutine_resume(co, NULL);
     return FALSE;
 }
 
@@ -389,11 +422,11 @@ static gboolean g_condition_wait(g_condition_wait_func func, gpointer data)
 
     vsrc->func = func;
     vsrc->data = data;
-    vsrc->co = coroutine_self();
+    vsrc->co = g_coroutine_self();
 
     g_source_attach(src, NULL);
-    g_source_set_callback(src, g_condition_wait_helper, coroutine_self(), NULL);
-    coroutine_yield(NULL);
+    g_source_set_callback(src, g_condition_wait_helper, g_coroutine_self(), NULL);
+    g_coroutine_yield(NULL);
     g_source_unref(src);
 
     return TRUE;
@@ -444,7 +477,11 @@ static void vnc_connection_set_property(GObject *object,
 struct signal_data
 {
     VncConnection *conn;
+#ifdef WITH_GCOROUTINE
+    GCoroutine *caller;
+#else
     struct coroutine *caller;
+#endif
 
     int signum;
 
@@ -584,7 +621,7 @@ static gboolean do_vnc_connection_emit_main_context(gpointer opaque)
         g_warn_if_reached();
     }
 
-    coroutine_yieldto(data->caller, NULL);
+    g_coroutine_resume(data->caller, NULL);
 
     return FALSE;
 }
@@ -594,7 +631,7 @@ static void vnc_connection_emit_main_context(VncConnection *conn,
                                              struct signal_data *data)
 {
     data->conn = conn;
-    data->caller = coroutine_self();
+    data->caller = g_coroutine_self();
     data->signum = signum;
 
     g_idle_add(do_vnc_connection_emit_main_context, data);
@@ -605,7 +642,7 @@ static void vnc_connection_emit_main_context(VncConnection *conn,
      * from the POV of the VNC coroutine despite there being
      * an idle function involved
      */
-    coroutine_yield(NULL);
+    g_coroutine_yield(NULL);
 }
 
 
@@ -2978,7 +3015,11 @@ static gboolean vnc_connection_audio_timer(gpointer opaque)
 struct audio_action_data
 {
     VncConnection *conn;
+#ifdef WITH_GCOROUTINE
+    GCoroutine *caller;
+#else
     struct coroutine *caller;
+#endif
     enum {
         VNC_AUDIO_PLAYBACK_STOP = 0,
         VNC_AUDIO_PLAYBACK_START = 1,
@@ -3007,7 +3048,7 @@ static gboolean do_vnc_connection_audio_action(gpointer opaque)
         g_warn_if_reached();
     }
 
-    coroutine_yieldto(data->caller, NULL);
+    g_coroutine_resume(data->caller, NULL);
     return FALSE;
 }
 
@@ -3016,7 +3057,7 @@ static void vnc_connection_audio_action(VncConnection *conn,
 {
     struct audio_action_data data = {
         conn,
-        coroutine_self(),
+        g_coroutine_self(),
         action,
     };
 
@@ -3030,7 +3071,7 @@ static void vnc_connection_audio_action(VncConnection *conn,
      * from the POV of the VNC coroutine despite there being
      * an idle function involved
      */
-    coroutine_yield(NULL);
+    g_coroutine_yield(NULL);
 }
 
 
@@ -4545,6 +4586,10 @@ static void vnc_connection_finalize (GObject *object)
         g_object_unref(G_OBJECT(priv->audio_sample));
     if (priv->audio_timer)
         g_source_remove(priv->audio_timer);
+#if WITH_GCOROUTINE
+    if (priv->coroutine)
+        g_coroutine_unref(priv->coroutine);
+#endif
 
     G_OBJECT_CLASS(vnc_connection_parent_class)->finalize (object);
 }
@@ -5159,11 +5204,16 @@ static gboolean vnc_connection_open_host_internal(VncConnection *conn)
 static gboolean vnc_connection_delayed_unref(gpointer data)
 {
     VncConnection *conn = VNC_CONNECTION(data);
-    VncConnectionPrivate *priv = conn->priv;
-
     VNC_DEBUG("Delayed unref VncConnection=%p", conn);
 
-    g_assert(priv->coroutine.exited == TRUE);
+#ifdef WITH_GCOROUTINE
+    g_assert(!g_in_coroutine());
+#else
+    {
+        VncConnectionPrivate *priv = conn->priv;
+        g_assert(priv->coroutine.exited == TRUE);
+    }
+#endif
 
     g_object_unref(G_OBJECT(data));
 
@@ -5216,11 +5266,18 @@ static gboolean do_vnc_connection_open(gpointer data)
 {
     VncConnection *conn = VNC_CONNECTION(data);
     VncConnectionPrivate *priv = conn->priv;
+#ifdef WITH_GCOROUTINE
+    GCoroutine *co;
+#else
     struct coroutine *co;
+#endif
 
     VNC_DEBUG("Open coroutine starting");
     priv->open_id = 0;
 
+#ifdef WITH_GCOROUTINE
+    co = priv->coroutine = g_coroutine_new(vnc_connection_coroutine);
+#else
     co = &priv->coroutine;
 
     co->stack_size = 16 << 20;
@@ -5228,7 +5285,9 @@ static gboolean do_vnc_connection_open(gpointer data)
     co->release = NULL;
 
     coroutine_init(co);
-    coroutine_yieldto(co, conn);
+#endif
+
+    g_coroutine_resume(co, conn);
 
     return FALSE;
 }
-- 
2.1.0



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