[Spice-devel] [PATCH spice-gtk 01/10] spice-channel: Allow spice_msg_out_send to be called from multiple threads

Hans de Goede hdegoede at redhat.com
Mon Dec 19 03:24:34 PST 2011


This is a preparation patch for handling usb packet completion in a
separate thread.

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 gtk/spice-channel-priv.h |    3 +++
 gtk/spice-channel.c      |   38 ++++++++++++++++++++++++++++++++++----
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index ed5f3a7..b9e81f8 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -95,6 +95,9 @@ struct _SpiceChannelPrivate {
 
     struct wait_queue           wait;
     GQueue                      xmit_queue;
+    gboolean                    xmit_queue_blocked;
+    GStaticMutex                xmit_queue_lock;
+    GThread                     *main_thread;
 
     char                        name[16];
     enum spice_channel_state    state;
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index b6779ba..873f9b3 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -105,6 +105,8 @@ static void spice_channel_init(SpiceChannel *channel)
     c->remote_common_caps = g_array_new(FALSE, TRUE, sizeof(guint32));
     spice_channel_set_common_capability(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);
     g_queue_init(&c->xmit_queue);
+    g_static_mutex_init(&c->xmit_queue_lock);
+    c->main_thread = g_thread_self();
 }
 
 static void spice_channel_constructed(GObject *gobject)
@@ -535,16 +537,35 @@ void spice_msg_out_unref(SpiceMsgOut *out)
 }
 
 /* system context */
+static gboolean spice_channel_idle_wakeup(gpointer user_data)
+{
+    SpiceChannel *channel = SPICE_CHANNEL(user_data);
+
+    spice_channel_wakeup(channel);
+    g_object_unref(channel);
+
+    return FALSE;
+}
+
+/* system context */
 G_GNUC_INTERNAL
 void spice_msg_out_send(SpiceMsgOut *out)
 {
     g_return_if_fail(out != NULL);
     g_return_if_fail(out->channel != NULL);
 
-    g_queue_push_tail(&out->channel->priv->xmit_queue, out);
+    g_static_mutex_lock(&out->channel->priv->xmit_queue_lock);
+    if (!out->channel->priv->xmit_queue_blocked)
+        g_queue_push_tail(&out->channel->priv->xmit_queue, out);
+    g_static_mutex_unlock(&out->channel->priv->xmit_queue_lock);
 
     /* TODO: we currently flush/wakeup immediately all buffered messages */
-    spice_channel_wakeup(out->channel);
+    if (g_thread_self() != out->channel->priv->main_thread)
+        /* We use g_timeout_add_full so that can specify the priority */
+        g_timeout_add_full(G_PRIORITY_HIGH, 0, spice_channel_idle_wakeup,
+                           g_object_ref(out->channel), NULL);
+    else
+        spice_channel_wakeup(out->channel);
 }
 
 /* coroutine context */
@@ -1784,8 +1805,13 @@ static void spice_channel_iterate_write(SpiceChannel *channel)
     SpiceChannelPrivate *c = channel->priv;
     SpiceMsgOut *out;
 
-    while ((out = g_queue_pop_head(&c->xmit_queue)))
-        spice_channel_write_msg(channel, out);
+    do {
+        g_static_mutex_lock(&c->xmit_queue_lock);
+        out = g_queue_pop_head(&c->xmit_queue);
+        g_static_mutex_unlock(&c->xmit_queue_lock);
+        if (out)
+            spice_channel_write_msg(channel, out);
+    } while (out);
 }
 
 /* coroutine context */
@@ -2065,6 +2091,7 @@ static gboolean channel_connect(SpiceChannel *channel)
         }
     }
     c->state = SPICE_CHANNEL_STATE_CONNECTING;
+    c->xmit_queue_blocked = FALSE;
 
     g_return_val_if_fail(c->sock == NULL, FALSE);
     g_object_ref(G_OBJECT(channel)); /* Unref'd when co-routine exits */
@@ -2165,8 +2192,11 @@ static void channel_disconnect(SpiceChannel *channel)
     c->peer_msg = NULL;
     c->peer_pos = 0;
 
+    g_static_mutex_lock(&c->xmit_queue_lock);
+    c->xmit_queue_blocked = TRUE; /* Disallow queuing new messages */
     g_queue_foreach(&c->xmit_queue, (GFunc)spice_msg_out_unref, NULL);
     g_queue_clear(&c->xmit_queue);
+    g_static_mutex_unlock(&c->xmit_queue_lock);
 
     g_array_set_size(c->remote_common_caps, 0);
     g_array_set_size(c->remote_caps, 0);
-- 
1.7.7.4



More information about the Spice-devel mailing list