[Spice-commits] 7 commits - gtk/channel-base.c gtk/channel-display.c gtk/channel-main.c gtk/decode-glz.c gtk/gio-coroutine.c gtk/gio-coroutine.h gtk/spice-channel.c gtk/spice-channel-priv.h gtk/spice-session.c gtk/spice-session-priv.h

Marc-André Lureau elmarco at kemper.freedesktop.org
Fri Jan 13 08:21:05 PST 2012


 gtk/channel-base.c       |    7 +-
 gtk/channel-display.c    |   66 ++++++++++++++++--------
 gtk/channel-main.c       |   10 +--
 gtk/decode-glz.c         |    4 +
 gtk/gio-coroutine.c      |  127 +++++++++++++++++++++++++++++------------------
 gtk/gio-coroutine.h      |   31 +++++------
 gtk/spice-channel-priv.h |    5 -
 gtk/spice-channel.c      |   35 +++++++-----
 gtk/spice-session-priv.h |    3 -
 gtk/spice-session.c      |   14 +++--
 10 files changed, 183 insertions(+), 119 deletions(-)

New commits:
commit ecfe99f7c406a70c16c9fa5ded66b73425c2bd20
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Mon Jan 9 18:11:33 2012 +0100

    wait for cached images that haven't been added to the cache yet
    
    https://bugs.freedesktop.org/show_bug.cgi?id=44570

diff --git a/gtk/channel-display.c b/gtk/channel-display.c
index d5061da..ec42829 100644
--- a/gtk/channel-display.c
+++ b/gtk/channel-display.c
@@ -404,18 +404,44 @@ static void image_put(SpiceImageCache *cache, uint64_t id, pixman_image_t *image
     item->ptr = pixman_image_ref(image);
 }
 
-static pixman_image_t *image_get(SpiceImageCache *cache, uint64_t id)
+typedef struct _WaitImageData
+{
+    gboolean lossy;
+    SpiceImageCache *cache;
+    uint64_t id;
+    pixman_image_t *image;
+} WaitImageData;
+
+static gboolean wait_image(gpointer data)
 {
-    SpiceDisplayChannelPrivate *c =
-        SPICE_CONTAINEROF(cache, SpiceDisplayChannelPrivate, image_cache);
     display_cache_item *item;
+    WaitImageData *wait = data;
+    SpiceDisplayChannelPrivate *c =
+        SPICE_CONTAINEROF(wait->cache, SpiceDisplayChannelPrivate, image_cache);
 
-    item = cache_find(c->images, id);
-    if (item) {
-        cache_used(c->images, item);
-        return pixman_image_ref(item->ptr);
-    }
-    return NULL;
+    item = cache_find(c->images, wait->id);
+    if (item == NULL ||
+        (item->lossy && !wait->lossy))
+        return FALSE;
+
+    cache_used(c->images, item);
+    wait->image = pixman_image_ref(item->ptr);
+
+    return TRUE;
+}
+
+static pixman_image_t *image_get(SpiceImageCache *cache, uint64_t id)
+{
+    WaitImageData wait = {
+        .lossy = TRUE,
+        .cache = cache,
+        .id = id,
+        .image = NULL
+    };
+    if (!g_coroutine_condition_wait(g_coroutine_self(), wait_image, &wait))
+        SPICE_DEBUG("wait image got cancelled");
+
+    return wait.image;
 }
 
 static void image_remove(SpiceImageCache *cache, uint64_t id)
@@ -511,20 +537,16 @@ static void image_replace_lossy(SpiceImageCache *cache, uint64_t id,
 
 static pixman_image_t* image_get_lossless(SpiceImageCache *cache, uint64_t id)
 {
-    SpiceDisplayChannelPrivate *c =
-        SPICE_CONTAINEROF(cache, SpiceDisplayChannelPrivate, image_cache);
-    display_cache_item *item;
-
-    item = cache_find(c->images, id);
-    if (!item)
-        return NULL;
-
-    /* TODO: shared_cache.hpp does wait until it is lossless..., is
-       that necessary? */
-    g_warn_if_fail(item->lossy == FALSE);
+    WaitImageData wait = {
+        .lossy = FALSE,
+        .cache = cache,
+        .id = id,
+        .image = NULL
+    };
+    if (!g_coroutine_condition_wait(g_coroutine_self(), wait_image, &wait))
+        SPICE_DEBUG("wait lossless got cancelled");
 
-    cache_used(c->images, item);
-    return pixman_image_ref(item->ptr);
+    return wait.image;
 }
 #endif
 
commit 2d2a5b55b718ad8ee4822999e979d1ca4811deb8
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Mon Jan 9 17:42:14 2012 +0100

    Log if condition wait got cancelled
    
    https://bugs.freedesktop.org/show_bug.cgi?id=44570

diff --git a/gtk/channel-base.c b/gtk/channel-base.c
index fd36696..b01be23 100644
--- a/gtk/channel-base.c
+++ b/gtk/channel-base.c
@@ -130,8 +130,10 @@ void spice_channel_handle_wait_for_channels(SpiceChannel *channel, SpiceMsgIn *i
         };
 
         SPICE_DEBUG("waiting for serial %lu (%d/%d)", data.wait->message_serial, i + 1, wfc->wait_count);
-        g_coroutine_condition_wait(&c->coroutine, wait_for_channel, &data);
-        SPICE_DEBUG("waiting for serial %lu, done", data.wait->message_serial);
+        if (g_coroutine_condition_wait(&c->coroutine, wait_for_channel, &data))
+            SPICE_DEBUG("waiting for serial %lu, done", data.wait->message_serial);
+        else
+            SPICE_DEBUG("waiting for serial %lu, cancelled", data.wait->message_serial);
     }
 }
 
diff --git a/gtk/decode-glz.c b/gtk/decode-glz.c
index 377f7af..3b7c34b 100644
--- a/gtk/decode-glz.c
+++ b/gtk/decode-glz.c
@@ -153,7 +153,9 @@ static void *glz_decoder_window_bits(SpiceGlzDecoderWindow *w, uint64_t id,
             .id = id - dist,
         };
 
-        g_coroutine_condition_wait(g_coroutine_self(), wait_for_image, &data);
+        if (!g_coroutine_condition_wait(g_coroutine_self(), wait_for_image, &data))
+            SPICE_DEBUG("wait for image cancelled");
+
         slot = (id - dist) % w->nimages;
     }
 
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index 9316f90..ed0ca8b 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -1997,9 +1997,9 @@ static gboolean spice_channel_iterate(SpiceChannel *channel)
     GIOCondition ret;
 
     do {
-        /* freeze coroutine */
-        if (c->state == SPICE_CHANNEL_STATE_MIGRATING)
-            g_coroutine_condition_wait(&c->coroutine, wait_migration, channel);
+        if (c->state == SPICE_CHANNEL_STATE_MIGRATING &&
+            !g_coroutine_condition_wait(&c->coroutine, wait_migration, channel))
+                SPICE_DEBUG("migration wait cancelled");
 
         if (c->has_error) {
             SPICE_DEBUG("channel has error, breaking loop");
commit 173841cb216c244580f72d61892f67f91a4c7b8a
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Mon Jan 9 16:34:16 2012 +0100

    Make g_coroutine_condition_wait() cancellable
    
    https://bugs.freedesktop.org/show_bug.cgi?id=44570

diff --git a/gtk/channel-base.c b/gtk/channel-base.c
index e41b1f5..fd36696 100644
--- a/gtk/channel-base.c
+++ b/gtk/channel-base.c
@@ -116,6 +116,7 @@ static gboolean wait_for_channel(gpointer data)
 G_GNUC_INTERNAL
 void spice_channel_handle_wait_for_channels(SpiceChannel *channel, SpiceMsgIn *in)
 {
+    SpiceChannelPrivate *c = channel->priv;
     SpiceMsgWaitForChannels *wfc = spice_msg_in_parsed(in);
     int i;
 
@@ -129,7 +130,7 @@ void spice_channel_handle_wait_for_channels(SpiceChannel *channel, SpiceMsgIn *i
         };
 
         SPICE_DEBUG("waiting for serial %lu (%d/%d)", data.wait->message_serial, i + 1, wfc->wait_count);
-        g_condition_wait(wait_for_channel, &data);
+        g_coroutine_condition_wait(&c->coroutine, wait_for_channel, &data);
         SPICE_DEBUG("waiting for serial %lu, done", data.wait->message_serial);
     }
 }
diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index 42e4494..ebf660f 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -1709,7 +1709,7 @@ static gboolean timer_set_display(gpointer data)
     c->timer_id = 0;
     if (c->agent_connected)
         spice_main_send_monitor_config(SPICE_MAIN_CHANNEL(channel));
-    spice_channel_wakeup(channel);
+    spice_channel_wakeup(channel, FALSE);
 
     return false;
 }
@@ -1783,7 +1783,7 @@ void spice_main_clipboard_selection_grab(SpiceMainChannel *channel, guint select
     g_return_if_fail(SPICE_IS_MAIN_CHANNEL(channel));
 
     agent_clipboard_grab(channel, selection, types, ntypes);
-    spice_channel_wakeup(SPICE_CHANNEL(channel));
+    spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
 }
 
 /**
@@ -1822,7 +1822,7 @@ void spice_main_clipboard_selection_release(SpiceMainChannel *channel, guint sel
         return;
 
     agent_clipboard_release(channel, selection);
-    spice_channel_wakeup(SPICE_CHANNEL(channel));
+    spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
 }
 
 /**
@@ -1863,7 +1863,7 @@ void spice_main_clipboard_selection_notify(SpiceMainChannel *channel, guint sele
     g_return_if_fail(SPICE_IS_MAIN_CHANNEL(channel));
 
     agent_clipboard_notify(channel, selection, type, data, size);
-    spice_channel_wakeup(SPICE_CHANNEL(channel));
+    spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
 }
 
 /**
@@ -1899,7 +1899,7 @@ void spice_main_clipboard_selection_request(SpiceMainChannel *channel, guint sel
     g_return_if_fail(SPICE_IS_MAIN_CHANNEL(channel));
 
     agent_clipboard_request(channel, selection, type);
-    spice_channel_wakeup(SPICE_CHANNEL(channel));
+    spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
 }
 
 /**
diff --git a/gtk/decode-glz.c b/gtk/decode-glz.c
index 317fa9e..377f7af 100644
--- a/gtk/decode-glz.c
+++ b/gtk/decode-glz.c
@@ -153,7 +153,7 @@ static void *glz_decoder_window_bits(SpiceGlzDecoderWindow *w, uint64_t id,
             .id = id - dist,
         };
 
-        g_condition_wait(wait_for_image, &data);
+        g_coroutine_condition_wait(g_coroutine_self(), wait_for_image, &data);
         slot = (id - dist) % w->nimages;
     }
 
diff --git a/gtk/gio-coroutine.c b/gtk/gio-coroutine.c
index 806dad9..355c75c 100644
--- a/gtk/gio-coroutine.c
+++ b/gtk/gio-coroutine.c
@@ -23,8 +23,8 @@
 
 typedef struct _GConditionWaitSource
 {
+    GCoroutine *self;
     GSource src;
-    struct coroutine *co;
     GConditionWaitFunc func;
     gpointer data;
 } GConditionWaitSource;
@@ -70,6 +70,17 @@ GIOCondition g_coroutine_socket_wait(GCoroutine *self,
     return val;
 }
 
+void g_coroutine_condition_cancel(GCoroutine *coroutine)
+{
+    g_return_if_fail(coroutine != NULL);
+
+    if (coroutine->condition_id == 0)
+        return;
+
+    g_source_remove(coroutine->condition_id);
+    coroutine->condition_id = 0;
+}
+
 void g_coroutine_wakeup(GCoroutine *coroutine)
 {
     g_return_if_fail(coroutine != NULL);
@@ -79,7 +90,6 @@ void g_coroutine_wakeup(GCoroutine *coroutine)
         coroutine_yieldto(&coroutine->coroutine, NULL);
 }
 
-
 /*
  * Call immediately before the main loop does an iteration. Returns
  * true if the condition we're checking is ready for dispatch
@@ -120,15 +130,32 @@ static gboolean g_condition_wait_helper(gpointer data)
     return FALSE;
 }
 
-gboolean g_condition_wait(GConditionWaitFunc func, gpointer data)
+/*
+ * g_coroutine_condition_wait:
+ * @coroutine: the coroutine to wait on
+ * @func: the condition callback
+ * @data: the user data passed to @func callback
+ *
+ * This function will wait on caller coroutine until @func returns %TRUE.
+ *
+ * @func is called when entering the main loop from the main context (coroutine).
+ *
+ * The condition can be cancelled by calling g_coroutine_wakeup()
+ *
+ * Returns: %TRUE if condition reached, %FALSE if not and cancelled
+ */
+gboolean g_coroutine_condition_wait(GCoroutine *self, GConditionWaitFunc func, gpointer data)
 {
     GSource *src;
     GConditionWaitSource *vsrc;
 
+    g_return_val_if_fail(self != NULL, FALSE);
+    g_return_val_if_fail(self->condition_id == 0, FALSE);
+    g_return_val_if_fail(func != NULL, FALSE);
+
     /* Short-circuit check in case we've got it ahead of time */
-    if (func(data)) {
+    if (func(data))
         return TRUE;
-    }
 
     /*
      * Don't have it, so yield to the main loop, checking the condition
@@ -139,13 +166,18 @@ gboolean g_condition_wait(GConditionWaitFunc func, gpointer data)
 
     vsrc->func = func;
     vsrc->data = data;
-    vsrc->co = coroutine_self();
+    vsrc->self = self;
 
-    g_source_attach(src, NULL);
-    g_source_set_callback(src, g_condition_wait_helper, coroutine_self(), NULL);
+    self->condition_id = g_source_attach(src, NULL);
+    g_source_set_callback(src, g_condition_wait_helper, self, NULL);
     coroutine_yield(NULL);
     g_source_unref(src);
 
+    /* it got woked up / cancelled? */
+    if (self->condition_id == 0)
+        return func(data);
+
+    self->condition_id = 0;
     return TRUE;
 }
 
diff --git a/gtk/gio-coroutine.h b/gtk/gio-coroutine.h
index cb96a52..1c4094e 100644
--- a/gtk/gio-coroutine.h
+++ b/gtk/gio-coroutine.h
@@ -32,6 +32,7 @@ struct _GCoroutine
 {
     struct coroutine coroutine;
     guint wait_id;
+    guint condition_id;
 };
 
 /*
@@ -47,11 +48,14 @@ typedef gboolean (*GConditionWaitFunc)(gpointer);
 
 typedef void (*GSignalEmitMainFunc)(GObject *object, int signum, gpointer params);
 
-GCoroutine*  g_coroutine_self       (void);
-void         g_coroutine_wakeup     (GCoroutine *coroutine);
-GIOCondition g_coroutine_socket_wait(GCoroutine *coroutine, GSocket *sock, GIOCondition cond);
+GCoroutine*  g_coroutine_self           (void);
+void         g_coroutine_wakeup         (GCoroutine *coroutine);
+GIOCondition g_coroutine_socket_wait    (GCoroutine *coroutine,
+                                         GSocket *sock, GIOCondition cond);
+gboolean     g_coroutine_condition_wait (GCoroutine *coroutine,
+                                         GConditionWaitFunc func, gpointer data);
+void         g_coroutine_condition_cancel(GCoroutine *coroutine);
 
-gboolean     g_condition_wait       (GConditionWaitFunc func, gpointer data);
 void         g_signal_emit_main_context(GObject *object, GSignalEmitMainFunc func,
                                         int signum, gpointer params, const char *debug_info);
 void         g_object_notify_main_context(GObject *object, const gchar *property_name);
diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index 7fa005c..ebdc5ce 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -154,7 +154,7 @@ uint16_t spice_header_get_msg_type(uint8_t *header, gboolean is_mini_header);
 uint32_t spice_header_get_msg_size(uint8_t *header, gboolean is_mini_header);
 
 void spice_channel_up(SpiceChannel *channel);
-void spice_channel_wakeup(SpiceChannel *channel);
+void spice_channel_wakeup(SpiceChannel *channel, gboolean cancel);
 
 SpiceSession* spice_channel_get_session(SpiceChannel *channel);
 
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index 806f37c..9316f90 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -650,7 +650,7 @@ static gboolean spice_channel_idle_wakeup(gpointer user_data)
 {
     SpiceChannel *channel = SPICE_CHANNEL(user_data);
 
-    spice_channel_wakeup(channel);
+    spice_channel_wakeup(channel, FALSE);
     g_object_unref(channel);
 
     return FALSE;
@@ -674,7 +674,7 @@ void spice_msg_out_send(SpiceMsgOut *out)
         g_timeout_add_full(G_PRIORITY_HIGH, 0, spice_channel_idle_wakeup,
                            g_object_ref(out->channel), NULL);
     else
-        spice_channel_wakeup(out->channel);
+        spice_channel_wakeup(out->channel, FALSE);
 }
 
 /* coroutine context */
@@ -1690,11 +1690,14 @@ error:
 /* system context */
 /* TODO: we currently flush/wakeup immediately all buffered messages */
 G_GNUC_INTERNAL
-void spice_channel_wakeup(SpiceChannel *channel)
+void spice_channel_wakeup(SpiceChannel *channel, gboolean cancel)
 {
-    SpiceChannelPrivate *c = channel->priv;
+    GCoroutine *c = &channel->priv->coroutine;
+
+    if (cancel)
+        g_coroutine_condition_cancel(c);
 
-    g_coroutine_wakeup(&c->coroutine);
+    g_coroutine_wakeup(c);
 }
 
 G_GNUC_INTERNAL
@@ -1996,7 +1999,7 @@ static gboolean spice_channel_iterate(SpiceChannel *channel)
     do {
         /* freeze coroutine */
         if (c->state == SPICE_CHANNEL_STATE_MIGRATING)
-            g_condition_wait(wait_migration, channel);
+            g_coroutine_condition_wait(&c->coroutine, wait_migration, channel);
 
         if (c->has_error) {
             SPICE_DEBUG("channel has error, breaking loop");
@@ -2407,7 +2410,7 @@ void spice_channel_disconnect(SpiceChannel *channel, SpiceChannelEvent reason)
     if (c->state == SPICE_CHANNEL_STATE_MIGRATING) {
         c->state = SPICE_CHANNEL_STATE_READY;
     } else
-        spice_channel_wakeup(channel);
+        spice_channel_wakeup(channel, TRUE);
 
     if (reason != SPICE_CHANNEL_NONE)
         g_signal_emit(G_OBJECT(channel), signals[SPICE_CHANNEL_EVENT], 0, reason);
commit 348acdb3ad40282b9675b4706298df31d60ac11d
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Mon Jan 9 14:35:40 2012 +0100

    Remove the non-interruptible version g_io_wait()
    
    Use the common g_coroutine_socket_wait()
    
    https://bugs.freedesktop.org/show_bug.cgi?id=44570

diff --git a/gtk/gio-coroutine.c b/gtk/gio-coroutine.c
index 704b5ac..806dad9 100644
--- a/gtk/gio-coroutine.c
+++ b/gtk/gio-coroutine.c
@@ -29,6 +29,11 @@ typedef struct _GConditionWaitSource
     gpointer data;
 } GConditionWaitSource;
 
+GCoroutine* g_coroutine_self(void)
+{
+    return (GCoroutine*)coroutine_self();
+}
+
 /* Main loop helper functions */
 static gboolean g_io_wait_helper(GSocket *sock G_GNUC_UNUSED,
 				 GIOCondition cond,
@@ -39,52 +44,38 @@ static gboolean g_io_wait_helper(GSocket *sock G_GNUC_UNUSED,
     return FALSE;
 }
 
-GIOCondition g_io_wait(GSocket *sock, GIOCondition cond)
-{
-    GIOCondition *ret;
-    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_attach(src, NULL);
-    ret = coroutine_yield(NULL);
-    g_source_unref(src);
-    return *ret;
-}
-
-
-GIOCondition g_io_wait_interruptible(GCoroutine *self,
+GIOCondition g_coroutine_socket_wait(GCoroutine *self,
                                      GSocket *sock,
                                      GIOCondition cond)
 {
-    GIOCondition *ret;
-    gint id;
+    GIOCondition *ret, val = 0;
+    GSource *src;
 
     g_return_val_if_fail(self != NULL, 0);
+    g_return_val_if_fail(self->wait_id == 0, 0);
     g_return_val_if_fail(sock != NULL, 0);
 
-    GSource *src = g_socket_create_source(sock,
-                                          cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                                          NULL);
+    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, self, NULL);
-    id = g_source_attach(src, NULL);
-    self->waiting = TRUE;
+    self->wait_id = g_source_attach(src, NULL);
     ret = coroutine_yield(NULL);
-    self->waiting = FALSE;
     g_source_unref(src);
 
-    if (ret == NULL) {
-        g_source_remove(id);
-        return 0;
-    } else
-        return *ret;
+    if (ret != NULL)
+        val = *ret;
+    else
+        g_source_remove(self->wait_id);
+
+    self->wait_id = 0;
+    return val;
 }
 
-void g_io_wakeup(GCoroutine *coroutine)
+void g_coroutine_wakeup(GCoroutine *coroutine)
 {
     g_return_if_fail(coroutine != NULL);
+    g_return_if_fail(coroutine != g_coroutine_self());
 
-    if (coroutine->waiting)
+    if (coroutine->wait_id)
         coroutine_yieldto(&coroutine->coroutine, NULL);
 }
 
diff --git a/gtk/gio-coroutine.h b/gtk/gio-coroutine.h
index 43dbc55..cb96a52 100644
--- a/gtk/gio-coroutine.h
+++ b/gtk/gio-coroutine.h
@@ -31,7 +31,7 @@ typedef struct _GCoroutine GCoroutine;
 struct _GCoroutine
 {
     struct coroutine coroutine;
-    gboolean waiting;
+    guint wait_id;
 };
 
 /*
@@ -47,10 +47,11 @@ typedef gboolean (*GConditionWaitFunc)(gpointer);
 
 typedef void (*GSignalEmitMainFunc)(GObject *object, int signum, gpointer params);
 
-GIOCondition g_io_wait              (GSocket *sock, GIOCondition cond);
+GCoroutine*  g_coroutine_self       (void);
+void         g_coroutine_wakeup     (GCoroutine *coroutine);
+GIOCondition g_coroutine_socket_wait(GCoroutine *coroutine, GSocket *sock, GIOCondition cond);
+
 gboolean     g_condition_wait       (GConditionWaitFunc func, gpointer data);
-void         g_io_wakeup            (GCoroutine *coroutine);
-GIOCondition g_io_wait_interruptible(GCoroutine *coroutine, GSocket *sock, GIOCondition cond);
 void         g_signal_emit_main_context(GObject *object, GSignalEmitMainFunc func,
                                         int signum, gpointer params, const char *debug_info);
 void         g_object_notify_main_context(GObject *object, const gchar *property_name);
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index 5f698b9..806f37c 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -755,7 +755,7 @@ static void spice_channel_flush_wire(SpiceChannel *channel,
         }
         if (ret == -1) {
             if (cond != 0) {
-                g_io_wait(c->sock, cond);
+                g_coroutine_socket_wait(&c->coroutine, c->sock, cond);
                 continue;
             } else {
                 SPICE_DEBUG("Closing the channel: spice_channel_flush %d", errno);
@@ -883,7 +883,7 @@ reread:
 
     if (ret == -1) {
         if (cond != 0) {
-            g_io_wait(c->sock, cond);
+            g_coroutine_socket_wait(&c->coroutine, c->sock, cond);
             goto reread;
         } else {
             c->has_error = TRUE;
@@ -1694,7 +1694,7 @@ void spice_channel_wakeup(SpiceChannel *channel)
 {
     SpiceChannelPrivate *c = channel->priv;
 
-    g_io_wakeup(&c->coroutine);
+    g_coroutine_wakeup(&c->coroutine);
 }
 
 G_GNUC_INTERNAL
@@ -2004,7 +2004,7 @@ static gboolean spice_channel_iterate(SpiceChannel *channel)
         }
 
         SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel);
-        ret = g_io_wait_interruptible(&c->coroutine, c->sock, G_IO_IN);
+        ret = g_coroutine_socket_wait(&c->coroutine, c->sock, G_IO_IN);
 
 #ifdef WIN32
         /* FIXME: windows gsocket is buggy, it doesn't return correct condition... */
@@ -2075,7 +2075,7 @@ static void *spice_channel_coroutine(void *data)
     }
 
 reconnect:
-    c->sock = spice_session_channel_open_host(c->session, c->tls);
+    c->sock = spice_session_channel_open_host(c->session, channel, c->tls);
     if (c->sock == NULL) {
         if (!c->tls) {
             SPICE_DEBUG("connection failed, trying with TLS port");
@@ -2154,7 +2154,7 @@ ssl_reconnect:
         if (rc <= 0) {
             rc = SSL_get_error(c->ssl, rc);
             if (rc == SSL_ERROR_WANT_READ || rc == SSL_ERROR_WANT_WRITE) {
-                g_io_wait(c->sock, G_IO_OUT|G_IO_ERR|G_IO_HUP);
+                g_coroutine_socket_wait(&c->coroutine, c->sock, G_IO_OUT|G_IO_ERR|G_IO_HUP);
                 goto ssl_reconnect;
             } else {
                 g_warning("%s: SSL_connect: %s",
diff --git a/gtk/spice-session-priv.h b/gtk/spice-session-priv.h
index bb5ae9b..5df1182 100644
--- a/gtk/spice-session-priv.h
+++ b/gtk/spice-session-priv.h
@@ -97,7 +97,8 @@ void spice_session_set_connection_id(SpiceSession *session, int id);
 int spice_session_get_connection_id(SpiceSession *session);
 gboolean spice_session_get_client_provided_socket(SpiceSession *session);
 
-GSocket* spice_session_channel_open_host(SpiceSession *session, gboolean use_tls);
+GSocket* spice_session_channel_open_host(SpiceSession *session, SpiceChannel *channel,
+                                         gboolean use_tls);
 void spice_session_channel_new(SpiceSession *session, SpiceChannel *channel);
 void spice_session_channel_destroy(SpiceSession *session, SpiceChannel *channel);
 void spice_session_channel_migrate(SpiceSession *session, SpiceChannel *channel);
diff --git a/gtk/spice-session.c b/gtk/spice-session.c
index 614cf02..79ba1b6 100644
--- a/gtk/spice-session.c
+++ b/gtk/spice-session.c
@@ -1359,9 +1359,11 @@ gboolean spice_session_has_channel_type(SpiceSession *session, gint type)
 /* ------------------------------------------------------------------ */
 /* private functions                                                  */
 
-static GSocket *channel_connect_socket(GSocketAddress *sockaddr,
+static GSocket *channel_connect_socket(SpiceChannel *channel,
+                                       GSocketAddress *sockaddr,
                                        GError **error)
 {
+    SpiceChannelPrivate *c = channel->priv;
     GSocket *sock = g_socket_new(g_socket_address_get_family(sockaddr),
                                  G_SOCKET_TYPE_STREAM,
                                  G_SOCKET_PROTOCOL_DEFAULT,
@@ -1375,7 +1377,7 @@ static GSocket *channel_connect_socket(GSocketAddress *sockaddr,
         if (*error && (*error)->code == G_IO_ERROR_PENDING) {
             g_clear_error(error);
             SPICE_DEBUG("Socket pending");
-            g_io_wait(sock, G_IO_OUT | G_IO_ERR | G_IO_HUP);
+            g_coroutine_socket_wait(&c->coroutine, sock, G_IO_OUT | G_IO_ERR | G_IO_HUP);
 
             if (!g_socket_check_connect_result(sock, error)) {
                 SPICE_DEBUG("Failed to connect %s", (*error)->message);
@@ -1394,8 +1396,10 @@ static GSocket *channel_connect_socket(GSocketAddress *sockaddr,
     return sock;
 }
 
+/* coroutine context */
 G_GNUC_INTERNAL
-GSocket* spice_session_channel_open_host(SpiceSession *session, gboolean use_tls)
+GSocket* spice_session_channel_open_host(SpiceSession *session, SpiceChannel *channel,
+                                         gboolean use_tls)
 {
     SpiceSessionPrivate *s = SPICE_SESSION_GET_PRIVATE(session);
     GSocketConnectable *addr;
@@ -1425,7 +1429,7 @@ GSocket* spice_session_channel_open_host(SpiceSession *session, gboolean use_tls
            (sockaddr = g_socket_address_enumerator_next(enumerator, NULL, &conn_error))) {
         SPICE_DEBUG("Trying one socket");
         g_clear_error(&conn_error);
-        sock = channel_connect_socket(sockaddr, &conn_error);
+        sock = channel_connect_socket(channel, sockaddr, &conn_error);
         if (conn_error != NULL)
             SPICE_DEBUG("%s", conn_error->message);
         g_object_unref(sockaddr);
commit 24187e7179c7bf37187b0c06e85fa867810fa00a
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Mon Jan 9 14:23:21 2012 +0100

    Create a GCoroutine, get rid of wait_queue
    
    https://bugs.freedesktop.org/show_bug.cgi?id=44570

diff --git a/gtk/gio-coroutine.c b/gtk/gio-coroutine.c
index 5c9621d..704b5ac 100644
--- a/gtk/gio-coroutine.c
+++ b/gtk/gio-coroutine.c
@@ -53,26 +53,24 @@ GIOCondition g_io_wait(GSocket *sock, GIOCondition cond)
 }
 
 
-GIOCondition g_io_wait_interruptible(struct wait_queue *wait,
+GIOCondition g_io_wait_interruptible(GCoroutine *self,
                                      GSocket *sock,
                                      GIOCondition cond)
 {
     GIOCondition *ret;
     gint id;
 
-    g_return_val_if_fail(wait != NULL, 0);
+    g_return_val_if_fail(self != NULL, 0);
     g_return_val_if_fail(sock != NULL, 0);
 
-    wait->context = coroutine_self();
     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,
-                          wait->context, NULL);
+    g_source_set_callback(src, (GSourceFunc)g_io_wait_helper, self, NULL);
     id = g_source_attach(src, NULL);
-    wait->waiting = TRUE;
+    self->waiting = TRUE;
     ret = coroutine_yield(NULL);
-    wait->waiting = FALSE;
+    self->waiting = FALSE;
     g_source_unref(src);
 
     if (ret == NULL) {
@@ -82,10 +80,12 @@ GIOCondition g_io_wait_interruptible(struct wait_queue *wait,
         return *ret;
 }
 
-void g_io_wakeup(struct wait_queue *wait)
+void g_io_wakeup(GCoroutine *coroutine)
 {
-    if (wait->waiting)
-        coroutine_yieldto(wait->context, NULL);
+    g_return_if_fail(coroutine != NULL);
+
+    if (coroutine->waiting)
+        coroutine_yieldto(&coroutine->coroutine, NULL);
 }
 
 
@@ -124,8 +124,8 @@ GSourceFuncs waitFuncs = {
 
 static gboolean g_condition_wait_helper(gpointer data)
 {
-    struct coroutine *co = (struct coroutine *)data;
-    coroutine_yieldto(co, NULL);
+    GCoroutine *self = (GCoroutine *)data;
+    coroutine_yieldto(&self->coroutine, NULL);
     return FALSE;
 }
 
diff --git a/gtk/gio-coroutine.h b/gtk/gio-coroutine.h
index 26e447e..43dbc55 100644
--- a/gtk/gio-coroutine.h
+++ b/gtk/gio-coroutine.h
@@ -26,10 +26,12 @@
 
 G_BEGIN_DECLS
 
-struct wait_queue
+typedef struct _GCoroutine GCoroutine;
+
+struct _GCoroutine
 {
+    struct coroutine coroutine;
     gboolean waiting;
-    struct coroutine *context;
 };
 
 /*
@@ -47,8 +49,8 @@ typedef void (*GSignalEmitMainFunc)(GObject *object, int signum, gpointer params
 
 GIOCondition g_io_wait              (GSocket *sock, GIOCondition cond);
 gboolean     g_condition_wait       (GConditionWaitFunc func, gpointer data);
-void         g_io_wakeup            (struct wait_queue *wait);
-GIOCondition g_io_wait_interruptible(struct wait_queue *wait, GSocket *sock, GIOCondition cond);
+void         g_io_wakeup            (GCoroutine *coroutine);
+GIOCondition g_io_wait_interruptible(GCoroutine *coroutine, GSocket *sock, GIOCondition cond);
 void         g_signal_emit_main_context(GObject *object, GSignalEmitMainFunc func,
                                         int signum, gpointer params, const char *debug_info);
 void         g_object_notify_main_context(GObject *object, const gchar *property_name);
diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index a3d1cd2..7fa005c 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -94,12 +94,11 @@ struct _SpiceChannelPrivate {
 
     /* not swapped */
     SpiceSession                *session;
-    struct coroutine            coroutine;
+    GCoroutine                  coroutine;
     int                         fd;
     gboolean                    has_error;
     guint                       connect_delayed_id;
 
-    struct wait_queue           wait;
     GQueue                      xmit_queue;
     gboolean                    xmit_queue_blocked;
     GStaticMutex                xmit_queue_lock;
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index 71c671e..5f698b9 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -1694,7 +1694,7 @@ void spice_channel_wakeup(SpiceChannel *channel)
 {
     SpiceChannelPrivate *c = channel->priv;
 
-    g_io_wakeup(&c->wait);
+    g_io_wakeup(&c->coroutine);
 }
 
 G_GNUC_INTERNAL
@@ -2004,7 +2004,7 @@ static gboolean spice_channel_iterate(SpiceChannel *channel)
         }
 
         SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel);
-        ret = g_io_wait_interruptible(&c->wait, c->sock, G_IO_IN);
+        ret = g_io_wait_interruptible(&c->coroutine, c->sock, G_IO_IN);
 
 #ifdef WIN32
         /* FIXME: windows gsocket is buggy, it doesn't return correct condition... */
@@ -2042,7 +2042,7 @@ static gboolean spice_channel_delayed_unref(gpointer data)
     g_return_val_if_fail(channel != NULL, FALSE);
     SPICE_DEBUG("Delayed unref channel %s %p", c->name, channel);
 
-    g_return_val_if_fail(c->coroutine.exited == TRUE, FALSE);
+    g_return_val_if_fail(c->coroutine.coroutine.exited == TRUE, FALSE);
 
     g_object_unref(G_OBJECT(data));
 
@@ -2209,7 +2209,7 @@ static gboolean connect_delayed(gpointer data)
     SPICE_DEBUG("Open coroutine starting %p", channel);
     c->connect_delayed_id = 0;
 
-    co = &c->coroutine;
+    co = &c->coroutine.coroutine;
 
     co->stack_size = 16 << 20; /* 16Mb */
     co->entry = spice_channel_coroutine;
commit 2126a03a8f70b5f3748d8d954d38aa1955f068b6
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Mon Jan 9 13:06:37 2012 +0100

    Hide g_condition_wait_source, use GLib style convention
    
    https://bugs.freedesktop.org/show_bug.cgi?id=44570

diff --git a/gtk/gio-coroutine.c b/gtk/gio-coroutine.c
index 7470b43..5c9621d 100644
--- a/gtk/gio-coroutine.c
+++ b/gtk/gio-coroutine.c
@@ -21,6 +21,14 @@
 
 #include "gio-coroutine.h"
 
+typedef struct _GConditionWaitSource
+{
+    GSource src;
+    struct coroutine *co;
+    GConditionWaitFunc func;
+    gpointer data;
+} GConditionWaitSource;
+
 /* Main loop helper functions */
 static gboolean g_io_wait_helper(GSocket *sock G_GNUC_UNUSED,
 				 GIOCondition cond,
@@ -87,7 +95,7 @@ void g_io_wakeup(struct wait_queue *wait)
  */
 static gboolean g_condition_wait_prepare(GSource *src,
 					 int *timeout) {
-    struct g_condition_wait_source *vsrc = (struct g_condition_wait_source *)src;
+    GConditionWaitSource *vsrc = (GConditionWaitSource *)src;
     *timeout = -1;
     return vsrc->func(vsrc->data);
 }
@@ -98,7 +106,7 @@ static gboolean g_condition_wait_prepare(GSource *src,
  */
 static gboolean g_condition_wait_check(GSource *src)
 {
-    struct g_condition_wait_source *vsrc = (struct g_condition_wait_source *)src;
+    GConditionWaitSource *vsrc = (GConditionWaitSource *)src;
     return vsrc->func(vsrc->data);
 }
 
@@ -121,10 +129,10 @@ static gboolean g_condition_wait_helper(gpointer data)
     return FALSE;
 }
 
-gboolean g_condition_wait(g_condition_wait_func func, gpointer data)
+gboolean g_condition_wait(GConditionWaitFunc func, gpointer data)
 {
     GSource *src;
-    struct g_condition_wait_source *vsrc;
+    GConditionWaitSource *vsrc;
 
     /* Short-circuit check in case we've got it ahead of time */
     if (func(data)) {
@@ -135,8 +143,8 @@ gboolean g_condition_wait(g_condition_wait_func func, gpointer data)
      * Don't have it, so yield to the main loop, checking the condition
      * on each iteration of the main loop
      */
-    src = g_source_new(&waitFuncs, sizeof(struct g_condition_wait_source));
-    vsrc = (struct g_condition_wait_source *)src;
+    src = g_source_new(&waitFuncs, sizeof(GConditionWaitSource));
+    vsrc = (GConditionWaitSource *)src;
 
     vsrc->func = func;
     vsrc->data = data;
diff --git a/gtk/gio-coroutine.h b/gtk/gio-coroutine.h
index 56a87e1..26e447e 100644
--- a/gtk/gio-coroutine.h
+++ b/gtk/gio-coroutine.h
@@ -41,20 +41,12 @@ struct wait_queue
  * to busy wait on a timeout, since our condition is only checked
  * when some other source's state changes
  */
-typedef gboolean (*g_condition_wait_func)(gpointer);
-
-struct g_condition_wait_source
-{
-    GSource src;
-    struct coroutine *co;
-    g_condition_wait_func func;
-    gpointer data;
-};
+typedef gboolean (*GConditionWaitFunc)(gpointer);
 
 typedef void (*GSignalEmitMainFunc)(GObject *object, int signum, gpointer params);
 
 GIOCondition g_io_wait              (GSocket *sock, GIOCondition cond);
-gboolean     g_condition_wait       (g_condition_wait_func func, gpointer data);
+gboolean     g_condition_wait       (GConditionWaitFunc func, gpointer data);
 void         g_io_wakeup            (struct wait_queue *wait);
 GIOCondition g_io_wait_interruptible(struct wait_queue *wait, GSocket *sock, GIOCondition cond);
 void         g_signal_emit_main_context(GObject *object, GSignalEmitMainFunc func,
commit f37f7819eeeaf9c144cc0eef250c9475db8f94ce
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Thu Jan 12 18:57:56 2012 +0100

    Lower connection error from warning to debug, it's normal to fail
    
    We try several connections, so it's normal to fail for some.
    No need to warn.
    
    https://bugs.freedesktop.org/show_bug.cgi?id=44570

diff --git a/gtk/spice-session.c b/gtk/spice-session.c
index ef4f3c1..614cf02 100644
--- a/gtk/spice-session.c
+++ b/gtk/spice-session.c
@@ -1427,7 +1427,7 @@ GSocket* spice_session_channel_open_host(SpiceSession *session, gboolean use_tls
         g_clear_error(&conn_error);
         sock = channel_connect_socket(sockaddr, &conn_error);
         if (conn_error != NULL)
-            g_warning("%s", conn_error->message);
+            SPICE_DEBUG("%s", conn_error->message);
         g_object_unref(sockaddr);
     }
     g_object_unref(enumerator);


More information about the Spice-commits mailing list