summaryrefslogtreecommitdiffstats
path: root/server/red_channel.c
diff options
context:
space:
mode:
authorYonit Halperin <yhalperi@redhat.com>2012-08-14 14:47:49 +0300
committerYonit Halperin <yhalperi@redhat.com>2012-08-27 09:13:00 +0300
commit275e4312df6c0f13ca2253ceac3976cee7d700e9 (patch)
tree7b49c3f4b54d7382c0a79ecc5cf71cd282362e08 /server/red_channel.c
parenteb4c95b08b6848ee604497bb66392636341ad1fe (diff)
downloadspice-275e4312df6c0f13ca2253ceac3976cee7d700e9.tar.gz
spice-275e4312df6c0f13ca2253ceac3976cee7d700e9.tar.xz
spice-275e4312df6c0f13ca2253ceac3976cee7d700e9.zip
seamless migration: migration completion on the destination side
Tracking the channels that wait for migration data. If there is a new migration process pending, when all the channels have restored their state, we begin the new migration.
Diffstat (limited to 'server/red_channel.c')
-rw-r--r--server/red_channel.c107
1 files changed, 98 insertions, 9 deletions
diff --git a/server/red_channel.c b/server/red_channel.c
index d715ce8c..65ef2da5 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -36,6 +36,7 @@
#include "stat.h"
#include "red_channel.h"
#include "reds.h"
+#include "main_dispatcher.h"
static void red_channel_client_event(int fd, int event, void *data);
static void red_client_add_channel(RedClient *client, RedChannelClient *rcc);
@@ -688,6 +689,45 @@ error:
return NULL;
}
+static void red_channel_client_seamless_migration_done(RedChannelClient *rcc)
+{
+ rcc->wait_migrate_data = FALSE;
+
+ pthread_mutex_lock(&rcc->client->lock);
+ rcc->client->num_migrated_channels--;
+
+ /* we assume we always have at least one channel who has migration data transfer,
+ * otherwise, this flag will never be set back to FALSE*/
+ if (!rcc->client->num_migrated_channels) {
+ rcc->client->during_target_migrate = FALSE;
+ rcc->client->seamless_migrate = FALSE;
+ /* migration completion might have been triggered from a different thread
+ * than the main thread */
+ main_dispatcher_seamless_migrate_dst_complete(rcc->client);
+ }
+ pthread_mutex_unlock(&rcc->client->lock);
+}
+
+int red_channel_client_waits_for_migrate_data(RedChannelClient *rcc)
+{
+ return rcc->wait_migrate_data;
+}
+
+int red_channel_waits_for_migrate_data(RedChannel *channel)
+{
+ RedChannelClient *rcc;
+ if (!red_channel_is_connected(channel)) {
+ return FALSE;
+ }
+
+ if (channel->clients_num > 1) {
+ return FALSE;
+ }
+ spice_assert(channel->clients_num == 1);
+ rcc = SPICE_CONTAINEROF(ring_get_head(&channel->clients), RedChannelClient, channel_link);
+ return red_channel_client_waits_for_migrate_data(rcc);
+}
+
static void red_channel_client_default_connect(RedChannel *channel, RedClient *client,
RedsStream *stream,
int migration,
@@ -1085,13 +1125,21 @@ static void red_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
// So need to make all the handlers work with per channel/client data (what data exactly?)
static void red_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
{
+ spice_debug("channel type %d id %d rcc %p size %u",
+ rcc->channel->type, rcc->channel->id, rcc, size);
if (!rcc->channel->channel_cbs.handle_migrate_data) {
return;
}
- spice_assert(red_channel_client_get_message_serial(rcc) == 0);
- red_channel_client_set_message_serial(rcc,
- rcc->channel->channel_cbs.handle_migrate_data_get_serial(rcc, size, message));
+ if (!red_channel_client_waits_for_migrate_data(rcc)) {
+ spice_error("unexcpected");
+ return;
+ }
+ if (rcc->channel->channel_cbs.handle_migrate_data_get_serial) {
+ red_channel_client_set_message_serial(rcc,
+ rcc->channel->channel_cbs.handle_migrate_data_get_serial(rcc, size, message));
+ }
rcc->channel->channel_cbs.handle_migrate_data(rcc, size, message);
+ red_channel_client_seamless_migration_done(rcc);
}
int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
@@ -1555,11 +1603,38 @@ RedClient *red_client_new(int migrated)
ring_init(&client->channels);
pthread_mutex_init(&client->lock, NULL);
client->thread_id = pthread_self();
- client->migrated = migrated;
+ client->during_target_migrate = migrated;
return client;
}
+/* client mutex should be locked before this call */
+static void red_channel_client_set_migration_seamless(RedChannelClient *rcc)
+{
+ spice_assert(rcc->client->during_target_migrate && rcc->client->seamless_migrate);
+
+ if (rcc->channel->migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) {
+ rcc->wait_migrate_data = TRUE;
+ rcc->client->num_migrated_channels++;
+ }
+ spice_debug("channel type %d id %d rcc %p wait data %d", rcc->channel->type, rcc->channel->id, rcc,
+ rcc->wait_migrate_data);
+}
+
+void red_client_set_migration_seamless(RedClient *client) // dest
+{
+ RingItem *link;
+ pthread_mutex_lock(&client->lock);
+ client->seamless_migrate = TRUE;
+ /* update channel clients that got connected before the migration
+ * type was set. red_client_add_channel will handle newer channel clients */
+ RING_FOREACH(link, &client->channels) {
+ RedChannelClient *rcc = SPICE_CONTAINEROF(link, RedChannelClient, client_link);
+ red_channel_client_set_migration_seamless(rcc);
+ }
+ pthread_mutex_unlock(&client->lock);
+}
+
void red_client_migrate(RedClient *client)
{
RingItem *link, *next;
@@ -1625,6 +1700,9 @@ static void red_client_add_channel(RedClient *client, RedChannelClient *rcc)
{
spice_assert(rcc && client);
ring_add(&client->channels, &rcc->client_link);
+ if (client->during_target_migrate && client->seamless_migrate) {
+ red_channel_client_set_migration_seamless(rcc);
+ }
client->channels_num++;
}
@@ -1636,16 +1714,27 @@ void red_client_set_main(RedClient *client, MainChannelClient *mcc) {
client->mcc = mcc;
}
-void red_client_migrate_complete(RedClient *client)
+void red_client_semi_seamless_migrate_complete(RedClient *client)
{
- spice_assert(client->migrated);
- client->migrated = FALSE;
- reds_on_client_migrate_complete(client);
+ pthread_mutex_lock(&client->lock);
+ if (!client->during_target_migrate || client->seamless_migrate) {
+ spice_error("unexpected");
+ pthread_mutex_unlock(&client->lock);
+ return;
+ }
+ client->during_target_migrate = FALSE;
+ pthread_mutex_unlock(&client->lock);
+ reds_on_client_semi_seamless_migrate_complete(client);
}
+/* should be called only from the main thread */
int red_client_during_migrate_at_target(RedClient *client)
{
- return client->migrated;
+ int ret;
+ pthread_mutex_lock(&client->lock);
+ ret = client->during_target_migrate;
+ pthread_mutex_unlock(&client->lock);
+ return ret;
}
/*