summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYonit Halperin <yhalperi@redhat.com>2012-11-05 21:18:56 +0200
committerYonit Halperin <yhalperi@redhat.com>2012-11-12 18:49:48 +0200
commit8918664cc3f63f3266490b2188ad537c282f021c (patch)
tree15c31c8f0681627ef3441b94d5203b1c8b96dc2b
parent4e7d25a7ac8c35cfea54b08f3d098895a09e15ea (diff)
display seamless migration: don't process both cmd ring and dispatcher queue till migration data is received
fix: rhbz#866929 At migration destination side, we need to restore the client's surfaces state, before sending surfaces related messages. Before this patch, we stopped the processing of only the cmd ring, till migration data arrived. However, some QXL_IOs require reading and rendering the cmd ring (e.g., update_area). Moreover, when the device is reset, after destroying all surfaces, we assert (in qemu) if the cmd ring is not empty (see rhbz#866929). This fix makes the red_worker thread wait till the migration data arrives (or till a timeout), and not process any input from the device after the vm is started.
-rw-r--r--server/red_worker.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/server/red_worker.c b/server/red_worker.c
index 9edd5d46..4636647d 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -102,6 +102,7 @@
#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro
#define DISPLAY_CLIENT_TIMEOUT 15000000000ULL //nano
+#define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec
#define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro
#define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
@@ -4892,13 +4893,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
int n = 0;
uint64_t start = red_now();
- /* we don't process the command ring if we are at the migration target and we
- * are expecting migration data. The migration data includes the list
- * of surfaces that are held by the client. We need to have it before
- * processing commands in order not to render and send surfaces unnecessarily
- */
- if (!worker->running || (worker->display_channel &&
- red_channel_waits_for_migrate_data(&worker->display_channel->common.base))) {
+ if (!worker->running) {
*ring_is_empty = TRUE;
return n;
}
@@ -11162,6 +11157,37 @@ void handle_dev_stop(void *opaque, void *payload)
red_wait_outgoing_items(&worker->cursor_channel->common.base);
}
+static int display_channel_wait_for_migrate_data(DisplayChannel *display)
+{
+ uint64_t end_time = red_now() + DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT;
+ RedChannel *channel = &display->common.base;
+ RedChannelClient *rcc;
+
+ spice_debug(NULL);
+ spice_assert(channel->clients_num == 1);
+
+ rcc = SPICE_CONTAINEROF(ring_get_head(&channel->clients), RedChannelClient, channel_link);
+ spice_assert(red_channel_client_waits_for_migrate_data(rcc));
+
+ for (;;) {
+ red_channel_client_receive(rcc);
+ if (!red_channel_client_is_connected(rcc)) {
+ break;
+ }
+
+ if (!red_channel_client_waits_for_migrate_data(rcc)) {
+ return TRUE;
+ }
+ if (red_now() > end_time) {
+ spice_warning("timeout");
+ red_channel_client_disconnect(rcc);
+ break;
+ }
+ usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
+ }
+ return FALSE;
+}
+
void handle_dev_start(void *opaque, void *payload)
{
RedWorker *worker = opaque;
@@ -11172,6 +11198,9 @@ void handle_dev_start(void *opaque, void *payload)
}
if (worker->display_channel) {
worker->display_channel->common.during_target_migrate = FALSE;
+ if (red_channel_waits_for_migrate_data(&worker->display_channel->common.base)) {
+ display_channel_wait_for_migrate_data(worker->display_channel);
+ }
}
worker->running = TRUE;
guest_set_client_capabilities(worker);