[Spice-devel] [PATCH spice-gtk 3/6] Add channel_reset method

Marc-André Lureau marcandre.lureau at gmail.com
Sun Dec 18 09:27:22 PST 2011


This new private method is to reset the channel to its initial state,
used by semi-seamless migration
---
 gtk/channel-cursor.c     |   12 ++++++++++
 gtk/channel-display.c    |   18 ++++++++++++++
 gtk/channel-main.c       |   41 ++++++++++++++++++++++++++++++++-
 gtk/channel-playback.c   |   19 +++++++++++++++
 gtk/channel-record.c     |   21 +++++++++++++++++
 gtk/channel-smartcard.c  |   56 +++++++++++++++++++++++++++++++++------------
 gtk/channel-usbredir.c   |    8 ++++++
 gtk/spice-channel-priv.h |    2 +
 gtk/spice-channel.c      |   35 +++++++++++++++++++++-------
 gtk/spice-channel.h      |    4 ++-
 10 files changed, 190 insertions(+), 26 deletions(-)

diff --git a/gtk/channel-cursor.c b/gtk/channel-cursor.c
index 4ad402c..6766b40 100644
--- a/gtk/channel-cursor.c
+++ b/gtk/channel-cursor.c
@@ -92,6 +92,17 @@ static void spice_cursor_channel_finalize(GObject *obj)
         G_OBJECT_CLASS(spice_cursor_channel_parent_class)->finalize(obj);
 }
 
+/* coroutine context */
+static void spice_cursor_channel_reset(SpiceChannel *channel, gboolean migrating)
+{
+    SpiceCursorChannelPrivate *c = SPICE_CURSOR_CHANNEL(channel)->priv;
+
+    delete_cursor_all(channel);
+    c->init_done = FALSE;
+
+    SPICE_CHANNEL_CLASS(spice_cursor_channel_parent_class)->channel_reset(channel, migrating);
+}
+
 static void spice_cursor_channel_class_init(SpiceCursorChannelClass *klass)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
@@ -99,6 +110,7 @@ static void spice_cursor_channel_class_init(SpiceCursorChannelClass *klass)
 
     gobject_class->finalize     = spice_cursor_channel_finalize;
     channel_class->handle_msg   = spice_cursor_handle_msg;
+    channel_class->channel_reset = spice_cursor_channel_reset;
 
     /**
      * SpiceCursorChannel::cursor-set:
diff --git a/gtk/channel-display.c b/gtk/channel-display.c
index 120128f..47beaa1 100644
--- a/gtk/channel-display.c
+++ b/gtk/channel-display.c
@@ -73,6 +73,7 @@ struct _SpiceDisplayChannelPrivate {
 #ifdef WIN32
     HDC dc;
 #endif
+    gboolean                    migrate_wait_primary;
 };
 
 G_DEFINE_TYPE(SpiceDisplayChannel, spice_display_channel, SPICE_TYPE_CHANNEL)
@@ -103,6 +104,8 @@ static void clear_surfaces(SpiceChannel *channel);
 static void clear_streams(SpiceChannel *channel);
 static display_surface *find_surface(SpiceDisplayChannelPrivate *c, int surface_id);
 static gboolean display_stream_render(display_stream *st);
+static void spice_display_channel_reset(SpiceChannel *channel, gboolean migrating);
+static void destroy_canvas(display_surface *surface);
 
 /* ------------------------------------------------------------------ */
 
@@ -181,6 +184,20 @@ static void spice_display_set_property(GObject      *object,
     }
 }
 
+/* main or coroutine context */
+static void spice_display_channel_reset(SpiceChannel *channel, gboolean migrating)
+{
+    SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(channel)->priv;
+
+    /* palettes, images, and glz_window are cleared in the session */
+
+    c->migrate_wait_primary = migrating;
+    clear_streams(channel);
+    clear_surfaces(channel);
+
+    SPICE_CHANNEL_CLASS(spice_display_channel_parent_class)->channel_reset(channel, migrating);
+}
+
 static void spice_display_channel_class_init(SpiceDisplayChannelClass *klass)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
@@ -194,6 +211,7 @@ static void spice_display_channel_class_init(SpiceDisplayChannelClass *klass)
 
     channel_class->handle_msg   = spice_display_handle_msg;
     channel_class->channel_up   = spice_display_channel_up;
+    channel_class->channel_reset = spice_display_channel_reset;
 
     g_object_class_install_property
         (gobject_class, PROP_HEIGHT,
diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index 615cdf6..47e41ab 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -122,6 +122,7 @@ static guint signals[SPICE_MAIN_LAST_SIGNAL];
 
 static void spice_main_handle_msg(SpiceChannel *channel, SpiceMsgIn *msg);
 static void agent_send_msg_queue(SpiceMainChannel *channel);
+static void agent_free_msg_queue(SpiceMainChannel *channel);
 static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent event,
                                      gpointer data);
 
@@ -250,7 +251,7 @@ static void spice_main_channel_finalize(GObject *obj)
     SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(obj)->priv;
 
     g_free(c->agent_msg_data);
-    g_queue_free(c->agent_msg_queue);
+    agent_free_msg_queue(SPICE_MAIN_CHANNEL(obj));
 
     if (G_OBJECT_CLASS(spice_main_channel_parent_class)->finalize)
         G_OBJECT_CLASS(spice_main_channel_parent_class)->finalize(obj);
@@ -265,6 +266,26 @@ static void spice_channel_iterate_write(SpiceChannel *channel)
         SPICE_CHANNEL_CLASS(spice_main_channel_parent_class)->iterate_write(channel);
 }
 
+/* main or coroutine context */
+static void spice_main_channel_reset(SpiceChannel *channel, gboolean migrating)
+{
+    SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(channel)->priv;
+
+    c->agent_connected = FALSE;
+    c->agent_caps_received = FALSE;
+    c->agent_display_config_sent = FALSE;
+    c->agent_tokens = 0;
+    c->agent_msg_pos = 0;
+    g_free(c->agent_msg_data);
+    c->agent_msg_data = NULL;
+    c->agent_msg_size = 0;
+
+    agent_free_msg_queue(SPICE_MAIN_CHANNEL(channel));
+    c->agent_msg_queue = g_queue_new();
+
+    SPICE_CHANNEL_CLASS(spice_main_channel_parent_class)->channel_reset(channel, migrating);
+}
+
 static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
@@ -277,6 +298,7 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
 
     channel_class->handle_msg    = spice_main_handle_msg;
     channel_class->iterate_write = spice_channel_iterate_write;
+    channel_class->channel_reset = spice_main_channel_reset;
 
     /**
      * SpiceMainChannel:mouse-mode:
@@ -706,6 +728,23 @@ static void do_emit_main_context(GObject *object, int signum, gpointer params)
 
 /* ------------------------------------------------------------------ */
 
+static void agent_free_msg_queue(SpiceMainChannel *channel)
+{
+    SpiceMainChannelPrivate *c = channel->priv;
+    SpiceMsgOut *out;
+
+    if (!c->agent_msg_queue)
+        return;
+
+    while (!g_queue_is_empty(c->agent_msg_queue)) {
+        out = g_queue_pop_head(c->agent_msg_queue);
+        spice_msg_out_unref(out);
+    }
+
+    g_queue_free(c->agent_msg_queue);
+    c->agent_msg_queue = NULL;
+}
+
 /* coroutine context */
 static void agent_send_msg_queue(SpiceMainChannel *channel)
 {
diff --git a/gtk/channel-playback.c b/gtk/channel-playback.c
index 4804682..32f8b1a 100644
--- a/gtk/channel-playback.c
+++ b/gtk/channel-playback.c
@@ -154,6 +154,24 @@ static void spice_playback_channel_set_property(GObject      *gobject,
     }
 }
 
+/* main or coroutine context */
+static void spice_playback_channel_reset(SpiceChannel *channel, gboolean migrating)
+{
+    SpicePlaybackChannelPrivate *c = SPICE_PLAYBACK_CHANNEL(channel)->priv;
+
+    if (c->celt_decoder) {
+        celt051_decoder_destroy(c->celt_decoder);
+        c->celt_decoder = NULL;
+    }
+
+    if (c->celt_mode) {
+        celt051_mode_destroy(c->celt_mode);
+        c->celt_mode = NULL;
+    }
+
+    SPICE_CHANNEL_CLASS(spice_playback_channel_parent_class)->channel_reset(channel, migrating);
+}
+
 static void spice_playback_channel_class_init(SpicePlaybackChannelClass *klass)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
@@ -164,6 +182,7 @@ static void spice_playback_channel_class_init(SpicePlaybackChannelClass *klass)
     gobject_class->set_property = spice_playback_channel_set_property;
 
     channel_class->handle_msg   = spice_playback_handle_msg;
+    channel_class->channel_reset = spice_playback_channel_reset;
 
     g_object_class_install_property
         (gobject_class, PROP_NCHANNELS,
diff --git a/gtk/channel-record.c b/gtk/channel-record.c
index 4e5e893..c5aded9 100644
--- a/gtk/channel-record.c
+++ b/gtk/channel-record.c
@@ -163,6 +163,26 @@ static void spice_record_channel_set_property(GObject      *gobject,
     }
 }
 
+static void channel_reset(SpiceChannel *channel, gboolean migrating)
+{
+    SpiceRecordChannelPrivate *c = SPICE_RECORD_CHANNEL(channel)->priv;
+
+    g_free(c->last_frame);
+    c->last_frame = NULL;
+
+    if (c->celt_encoder) {
+        celt051_encoder_destroy(c->celt_encoder);
+        c->celt_encoder = NULL;
+    }
+
+    if (c->celt_mode) {
+        celt051_mode_destroy(c->celt_mode);
+        c->celt_mode = NULL;
+    }
+
+    SPICE_CHANNEL_CLASS(spice_record_channel_parent_class)->channel_reset(channel, migrating);
+}
+
 static void spice_record_channel_class_init(SpiceRecordChannelClass *klass)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
@@ -173,6 +193,7 @@ static void spice_record_channel_class_init(SpiceRecordChannelClass *klass)
     gobject_class->set_property = spice_record_channel_set_property;
     channel_class->handle_msg   = spice_record_handle_msg;
     channel_class->channel_up   = channel_up;
+    channel_class->channel_reset = channel_reset;
 
     g_object_class_install_property
         (gobject_class, PROP_NCHANNELS,
diff --git a/gtk/channel-smartcard.c b/gtk/channel-smartcard.c
index 98e77eb..6fa4435 100644
--- a/gtk/channel-smartcard.c
+++ b/gtk/channel-smartcard.c
@@ -144,31 +144,56 @@ static void spice_smartcard_channel_init(SpiceSmartcardChannel *channel)
 
 static void spice_smartcard_channel_finalize(GObject *obj)
 {
-    SpiceSmartcardChannel *channel = SPICE_SMARTCARD_CHANNEL(obj);
+    SpiceSmartcardChannelPrivate *c = SPICE_SMARTCARD_CHANNEL_GET_PRIVATE(obj);
 
-    if (channel->priv->pending_card_insertions != NULL) {
-        g_hash_table_destroy(channel->priv->pending_card_insertions);
-        channel->priv->pending_card_insertions = NULL;
+    if (c->pending_card_insertions != NULL) {
+        g_hash_table_destroy(c->pending_card_insertions);
+        c->pending_card_insertions = NULL;
     }
-    if (channel->priv->pending_reader_removals != NULL) {
-        g_hash_table_destroy(channel->priv->pending_reader_removals);
-        channel->priv->pending_reader_removals = NULL;
+    if (c->pending_reader_removals != NULL) {
+        g_hash_table_destroy(c->pending_reader_removals);
+        c->pending_reader_removals = NULL;
     }
-    if (channel->priv->message_queue != NULL) {
-        g_queue_foreach(channel->priv->message_queue,
-                        (GFunc)smartcard_message_free, NULL);
-        g_queue_free(channel->priv->message_queue);
-        channel->priv->message_queue = NULL;
+    if (c->message_queue != NULL) {
+        g_queue_foreach(c->message_queue, (GFunc)smartcard_message_free, NULL);
+        g_queue_free(c->message_queue);
+        c->message_queue = NULL;
     }
-    if (channel->priv->in_flight_message != NULL) {
-        smartcard_message_free(channel->priv->in_flight_message);
-        channel->priv->in_flight_message = NULL;
+    if (c->in_flight_message != NULL) {
+        smartcard_message_free(c->in_flight_message);
+        c->in_flight_message = NULL;
     }
 
+    g_list_free(c->pending_reader_additions);
+    c->pending_reader_additions = NULL;
+
     if (G_OBJECT_CLASS(spice_smartcard_channel_parent_class)->finalize)
         G_OBJECT_CLASS(spice_smartcard_channel_parent_class)->finalize(obj);
 }
 
+static void spice_smartcard_channel_reset(SpiceChannel *channel, gboolean migrating)
+{
+    SpiceSmartcardChannelPrivate *c = SPICE_SMARTCARD_CHANNEL_GET_PRIVATE(channel);
+
+    g_hash_table_remove_all(c->pending_card_insertions);
+    g_hash_table_remove_all(c->pending_reader_removals);
+
+    if (c->message_queue != NULL) {
+        g_queue_foreach(c->message_queue, (GFunc)smartcard_message_free, NULL);
+        g_queue_clear(c->message_queue);
+    }
+
+    if (c->in_flight_message != NULL) {
+        smartcard_message_free(c->in_flight_message);
+        c->in_flight_message = NULL;
+    }
+
+    g_list_free(c->pending_reader_additions);
+    c->pending_reader_additions = NULL;
+
+    SPICE_CHANNEL_CLASS(spice_smartcard_channel_parent_class)->channel_reset(channel, migrating);
+}
+
 static void spice_smartcard_channel_class_init(SpiceSmartcardChannelClass *klass)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
@@ -177,6 +202,7 @@ static void spice_smartcard_channel_class_init(SpiceSmartcardChannelClass *klass
     gobject_class->finalize     = spice_smartcard_channel_finalize;
     channel_class->handle_msg   = spice_smartcard_handle_msg;
     channel_class->channel_up   = spice_smartcard_channel_up;
+    channel_class->channel_reset = spice_smartcard_channel_reset;
 
     g_type_class_add_private(klass, sizeof(SpiceSmartcardChannelPrivate));
 }
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index 06d80d5..cdc04a9 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -102,6 +102,13 @@ static void spice_usbredir_channel_init(SpiceUsbredirChannel *channel)
 #endif
 }
 
+static void spice_usbredir_channel_reset(SpiceChannel *channel, gboolean migrating)
+{
+    spice_usbredir_channel_disconnect(SPICE_USBREDIR_CHANNEL(channel));
+
+    SPICE_CHANNEL_CLASS(spice_usbredir_channel_parent_class)->channel_reset(channel, migrating);
+}
+
 static void spice_usbredir_channel_class_init(SpiceUsbredirChannelClass *klass)
 {
 #ifdef USE_USBREDIR
@@ -111,6 +118,7 @@ static void spice_usbredir_channel_class_init(SpiceUsbredirChannelClass *klass)
     gobject_class->dispose      = spice_usbredir_channel_dispose;
     channel_class->handle_msg   = spice_usbredir_handle_msg;
     channel_class->channel_up   = spice_usbredir_channel_up;
+    channel_class->channel_reset = spice_usbredir_channel_reset;
 
     g_type_class_add_private(klass, sizeof(SpiceUsbredirChannelPrivate));
 #endif
diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index ed5f3a7..5585f13 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -166,6 +166,8 @@ void spice_channel_swap(SpiceChannel *channel, SpiceChannel *swap);
 void spice_channel_set_common_capability(SpiceChannel *channel, guint32 cap);
 gboolean spice_channel_get_read_only(SpiceChannel *channel);
 
+void spice_channel_reset(SpiceChannel *channel, gboolean migrating);
+
 /* coroutine context */
 #define emit_main_context(object, event, args...)                       \
     G_STMT_START {                                                      \
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index b6779ba..6420c53 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -45,6 +45,7 @@ static void spice_channel_handle_msg(SpiceChannel *channel, SpiceMsgIn *msg);
 static void spice_channel_write_msg(SpiceChannel *channel, SpiceMsgOut *out);
 static void spice_channel_send_link(SpiceChannel *channel);
 static void channel_disconnect(SpiceChannel *channel);
+static void channel_reset(SpiceChannel *channel, gboolean migrating);
 
 /**
  * SECTION:spice-channel
@@ -249,6 +250,7 @@ static void spice_channel_class_init(SpiceChannelClass *klass)
     klass->iterate_write = spice_channel_iterate_write;
     klass->iterate_read  = spice_channel_iterate_read;
     klass->channel_disconnect = channel_disconnect;
+    klass->channel_reset = channel_reset;
 
     gobject_class->constructed  = spice_channel_constructed;
     gobject_class->dispose      = spice_channel_dispose;
@@ -2116,18 +2118,10 @@ gboolean spice_channel_open_fd(SpiceChannel *channel, int fd)
 }
 
 /* system or coroutine context */
-static void channel_disconnect(SpiceChannel *channel)
+static void channel_reset(SpiceChannel *channel, gboolean migrating)
 {
     SpiceChannelPrivate *c = SPICE_CHANNEL_GET_PRIVATE(channel);
 
-    g_return_if_fail(c != NULL);
-
-    if (c->state == SPICE_CHANNEL_STATE_UNCONNECTED) {
-        return;
-    }
-
-    c->has_error = TRUE; /* break the loop */
-
     if (c->connect_delayed_id) {
         g_source_remove(c->connect_delayed_id);
         c->connect_delayed_id = 0;
@@ -2174,9 +2168,32 @@ static void channel_disconnect(SpiceChannel *channel)
     g_array_set_size(c->caps, 0);
     /* Restore our default capabilities in case the channel gets re-used */
     spice_channel_set_common_capability(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);
+}
+
+/* system or coroutine context */
+G_GNUC_INTERNAL
+void spice_channel_reset(SpiceChannel *channel, gboolean migrating)
+{
+    SPICE_CHANNEL_GET_CLASS(channel)->channel_reset(channel, migrating);
+}
+
+/* system or coroutine context */
+static void channel_disconnect(SpiceChannel *channel)
+{
+    SpiceChannelPrivate *c = SPICE_CHANNEL_GET_PRIVATE(channel);
+
+    g_return_if_fail(c != NULL);
+
+    if (c->state == SPICE_CHANNEL_STATE_UNCONNECTED)
+        return;
+
+    c->has_error = TRUE; /* break the loop */
+
+    spice_channel_reset(channel, FALSE);
 
     if (c->state == SPICE_CHANNEL_STATE_READY)
         emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_CLOSED);
+
     g_return_if_fail(SPICE_IS_CHANNEL(channel));
     c->state = SPICE_CHANNEL_STATE_UNCONNECTED;
 }
diff --git a/gtk/spice-channel.h b/gtk/spice-channel.h
index 793c5d6..2a8e7e7 100644
--- a/gtk/spice-channel.h
+++ b/gtk/spice-channel.h
@@ -87,11 +87,13 @@ struct _SpiceChannelClass
     /*< private >*/
     /* virtual method, any context */
     void (*channel_disconnect)(SpiceChannel *channel);
+
+    void (*channel_reset)(SpiceChannel *channel, gboolean migrating);
     /*
      * If adding fields to this struct, remove corresponding
      * amount of padding to avoid changing overall struct size
      */
-    gchar _spice_reserved[SPICE_RESERVED_PADDING - 4 * sizeof(void*)];
+    gchar _spice_reserved[SPICE_RESERVED_PADDING - 5 * sizeof(void*)];
 };
 
 GType spice_channel_get_type(void);
-- 
1.7.7.4



More information about the Spice-devel mailing list