[Spice-devel] [PATCH 31/35] replace worker load/save with loadvm_commands, allow keeping surface content

Gerd Hoffmann kraxel at redhat.com
Wed May 12 04:32:25 PDT 2010


Add worker->loadvm_commands.  qemu will uses this to send a series of
commands needed to restore state after savevm/loadvm and migration.
That will be one create-surface command per surface and one cursor-set
command for the local pointer.

The worker->save/load functions are not needed any more.
Likewise the interface->{get,set}_save_data callbacks.

Surfaces created via loadvm_commands *will* not be cleared.  Also
primary surfaces are not cleared any more (unconditionally, although
we could do that conditionally on loadvm using the flags field in
QXLSurfaceCreate).
---
 server/red_dispatcher.c |   29 ++++-------
 server/red_worker.c     |  119 ++++++++++++++++------------------------------
 server/red_worker.h     |    3 +-
 server/vd_interface.h   |    5 +--
 4 files changed, 55 insertions(+), 101 deletions(-)

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 3d1d6f9..2d23cbe 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -345,40 +345,34 @@ static void qxl_worker_oom(QXLWorker *qxl_worker)
     }
 }
 
-static void qxl_worker_save(QXLWorker *qxl_worker)
+static void qxl_worker_start(QXLWorker *qxl_worker)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkeMessage message = RED_WORKER_MESSAGE_SAVE;
+    RedWorkeMessage message = RED_WORKER_MESSAGE_START;
 
     write_message(dispatcher->channel, &message);
-    read_message(dispatcher->channel, &message);
-    ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_load(QXLWorker *qxl_worker)
+static void qxl_worker_stop(QXLWorker *qxl_worker)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkeMessage message = RED_WORKER_MESSAGE_LOAD;
+    RedWorkeMessage message = RED_WORKER_MESSAGE_STOP;
 
     write_message(dispatcher->channel, &message);
     read_message(dispatcher->channel, &message);
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_start(QXLWorker *qxl_worker)
+void qxl_worker_loadvm_commands(QXLWorker *qxl_worker,
+                                struct QXLCommandExt *ext, uint32_t count)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkeMessage message = RED_WORKER_MESSAGE_START;
-
-    write_message(dispatcher->channel, &message);
-}
-
-static void qxl_worker_stop(QXLWorker *qxl_worker)
-{
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkeMessage message = RED_WORKER_MESSAGE_STOP;
+    RedWorkeMessage message = RED_WORKER_MESSAGE_LOADVM_COMMANDS;
 
+    red_printf("");
     write_message(dispatcher->channel, &message);
+    send_data(dispatcher->channel, &count, sizeof(uint32_t));
+    send_data(dispatcher->channel, ext, sizeof(QXLCommandExt) * count);
     read_message(dispatcher->channel, &message);
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
@@ -506,8 +500,6 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     dispatcher->base.minor_version = SPICE_INTERFACE_QXL_MINOR;
     dispatcher->base.wakeup = qxl_worker_wakeup;
     dispatcher->base.oom = qxl_worker_oom;
-    dispatcher->base.save = qxl_worker_save;
-    dispatcher->base.load = qxl_worker_load;
     dispatcher->base.start = qxl_worker_start;
     dispatcher->base.stop = qxl_worker_stop;
     dispatcher->base.update_area = qxl_worker_update_area;
@@ -521,6 +513,7 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     dispatcher->base.reset_image_cache = qxl_worker_reset_image_cache;
     dispatcher->base.reset_cursor = qxl_worker_reset_cursor;
     dispatcher->base.destroy_surface_wait = qxl_worker_destroy_surface_wait;
+    dispatcher->base.loadvm_commands = qxl_worker_loadvm_commands;
 
     qxl->st->qif->get_init_info(qxl, &init_info);
 
diff --git a/server/red_worker.c b/server/red_worker.c
index 208b685..7963946 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -3866,9 +3866,9 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable
 
 static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width,
                                       uint32_t height, int32_t stride, uint32_t format,
-                                      void *line_0);
+                                      void *line_0, int data_is_valid);
 
-static inline void red_process_surface(RedWorker *worker, QXLSurfaceCmd *surface, uint32_t group_id)
+static inline void red_process_surface(RedWorker *worker, QXLSurfaceCmd *surface, uint32_t group_id, int data_is_valid)
 {
     int surface_id;
     RedSurface *red_surface;
@@ -3890,7 +3890,8 @@ static inline void red_process_surface(RedWorker *worker, QXLSurfaceCmd *surface
             data -= (int32_t)(stride * (height - 1));
         }
         red_create_surface(worker, surface_id, surface->u.surface_create.width,
-                           height, stride, surface->u.surface_create.format, data);
+                           height, stride, surface->u.surface_create.format, data,
+                           data_is_valid);
         set_surface_release_info(worker, surface_id, 1, &surface->release_info, group_id);
         break;
     }
@@ -4906,7 +4907,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size)
         case QXL_CMD_SURFACE: {
             QXLSurfaceCmd *surface = (QXLSurfaceCmd *)get_virt(&worker->mem_slots, ext_cmd.cmd.data,
                                                                sizeof(QXLSurfaceCmd), ext_cmd.group_id);
-            red_process_surface(worker, surface, ext_cmd.group_id);
+            red_process_surface(worker, surface, ext_cmd.group_id, 0);
             break;
         }
         default:
@@ -8024,7 +8025,7 @@ static inline void red_create_surface_item(RedWorker *worker, int surface_id)
 
 static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, uint32_t width,
                                       uint32_t height, int32_t stride, uint32_t format,
-                                      void *line_0)
+                                      void *line_0, int data_is_valid)
 {
     uint32_t i;
     RedSurface *surface = &worker->surfaces[surface_id];
@@ -8039,7 +8040,8 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
     surface->context.format = format;
     surface->context.stride = stride;
     surface->context.line_0 = line_0;
-    memset(line_0 + (int32_t)(stride * (height - 1)), 0, height*abs(stride));
+    if (!data_is_valid)
+        memset(line_0 + (int32_t)(stride * (height - 1)), 0, height*abs(stride));
     surface->create.info = NULL;
     surface->destroy.info = NULL;
     ring_init(&surface->current);
@@ -8833,29 +8835,6 @@ typedef struct __attribute__ ((__packed__)) CursorData {
     SpiceCursor _cursor;
 } CursorData;
 
-static void red_save_cursor(RedWorker *worker)
-{
-    CursorData *cursor_data;
-    LocalCursor *local;
-    int size;
-
-    ASSERT(worker->cursor);
-    ASSERT(worker->cursor->type == CURSOR_TYPE_LOCAL);
-
-    local = (LocalCursor *)worker->cursor;
-    size = sizeof(CursorData) + sizeof(SpiceCursor) + local->data_size;
-    cursor_data = spice_malloc(size);
-
-    cursor_data->position = worker->cursor_position;
-    cursor_data->visible = worker->cursor_visible;
-    cursor_data->trail_frequency = worker->cursor_trail_frequency;
-    cursor_data->trail_length = worker->cursor_trail_length;
-    cursor_data->data_size = local->data_size;
-    cursor_data->_cursor.header = local->red_cursor.header;
-    memcpy(cursor_data->_cursor.data, local->red_cursor.data, local->data_size);
-    worker->qxl->st->qif->set_save_data(worker->qxl, cursor_data, size);
-}
-
 static LocalCursor *_new_local_cursor(SpiceCursorHeader *header, int data_size, SpicePoint16 position)
 {
     LocalCursor *local;
@@ -8915,37 +8894,6 @@ static void red_cursor_flush(RedWorker *worker)
     red_release_cursor(worker, &local->base);
 }
 
-static void red_save(RedWorker *worker)
-{
-    if (!worker->cursor) {
-        worker->qxl->st->qif->set_save_data(worker->qxl, NULL, 0);
-        return;
-    }
-    red_save_cursor(worker);
-}
-
-static void red_cursor_load(RedWorker *worker)
-{
-    CursorData *cursor_data = worker->qxl->st->qif->get_save_data(worker->qxl);
-    LocalCursor *local;
-
-    if (!cursor_data) {
-        return;
-    }
-
-    worker->cursor_position = cursor_data->position;
-    worker->cursor_visible = cursor_data->visible;
-    worker->cursor_trail_frequency = cursor_data->trail_frequency;
-    worker->cursor_trail_length = cursor_data->trail_length;
-
-    local = _new_local_cursor(&cursor_data->_cursor.header, cursor_data->data_size,
-                              cursor_data->position);
-    ASSERT(local);
-    memcpy(local->red_cursor.data, cursor_data->_cursor.data, cursor_data->data_size);
-    red_set_cursor(worker, &local->base);
-    red_release_cursor(worker, &local->base);
-}
-
 static void red_wait_outgoiong_item(RedChannel *channel)
 {
     uint64_t end_time;
@@ -9138,7 +9086,7 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
     }
 
     red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.format,
-                       line_0);
+                       line_0, 1);
 
     if (worker->display_channel) {
         red_pipe_add_verb(&worker->display_channel->base, SPICE_MSG_DISPLAY_MARK);
@@ -9272,22 +9220,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         red_printf("disconnect");
         red_disconnect_display((RedChannel *)worker->display_channel);
         break;
-    case RED_WORKER_MESSAGE_SAVE:
-        red_printf("save");
-        ASSERT(!worker->running);
-        red_save(worker);
-        message = RED_WORKER_MESSAGE_READY;
-        write_message(worker->channel, &message);
-        break;
-    case RED_WORKER_MESSAGE_LOAD:
-        red_printf("load");
-        ASSERT(!worker->running);
-        red_add_surface_image(worker, 0);
-        red_cursor_load(worker);
-        message = RED_WORKER_MESSAGE_READY;
-        write_message(worker->channel, &message);
-        break;
-        case RED_WORKER_MESSAGE_STOP: {
+    case RED_WORKER_MESSAGE_STOP: {
         int x;
 
         red_printf("stop");
@@ -9403,6 +9336,38 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     case RED_WORKER_MESSAGE_RESET_MEMSLOTS:
         red_memslot_info_reset(&worker->mem_slots);
         break;
+    case RED_WORKER_MESSAGE_LOADVM_COMMANDS: {
+        uint32_t count;
+        QXLCommandExt ext;
+        QXLCursorCmd *cursor_cmd;
+        QXLSurfaceCmd *surface_cmd;
+
+        red_printf("loadvm_commands");
+        receive_data(worker->channel, &count, sizeof(uint32_t));
+        while (count > 0) {
+            receive_data(worker->channel, &ext, sizeof(QXLCommandExt));
+            switch (ext.cmd.type) {
+            case QXL_CMD_CURSOR:
+                cursor_cmd = (QXLCursorCmd *)get_virt(&worker->mem_slots,
+                                                      ext.cmd.data,
+                                                      sizeof(QXLCursorCmd),
+                                                      ext.group_id);
+                qxl_process_cursor(worker, cursor_cmd, ext.group_id);
+                break;
+            case QXL_CMD_SURFACE:
+                surface_cmd = (QXLSurfaceCmd *)get_virt(&worker->mem_slots,
+                                                        ext.cmd.data,
+                                                        sizeof(QXLSurfaceCmd),
+                                                        ext.group_id);
+                red_process_surface(worker, surface_cmd, ext.group_id, 1);
+                break;
+            }
+            count--;
+        }
+        message = RED_WORKER_MESSAGE_READY;
+        write_message(worker->channel, &message);
+        break;
+    }
     default:
         red_error("message error");
     }
diff --git a/server/red_worker.h b/server/red_worker.h
index e53d518..88c1e90 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -50,8 +50,6 @@ enum {
     RED_WORKER_MESSAGE_DISPLAY_CONNECT,
     RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
     RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
-    RED_WORKER_MESSAGE_SAVE,
-    RED_WORKER_MESSAGE_LOAD,
     RED_WORKER_MESSAGE_START,
     RED_WORKER_MESSAGE_STOP,
     RED_WORKER_MESSAGE_CURSOR_CONNECT,
@@ -69,6 +67,7 @@ enum {
     RED_WORKER_MESSAGE_RESET_CURSOR,
     RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
     RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
+    RED_WORKER_MESSAGE_LOADVM_COMMANDS,
 };
 
 typedef uint32_t RedWorkeMessage;
diff --git a/server/vd_interface.h b/server/vd_interface.h
index 0f26822..d3cf5cb 100644
--- a/server/vd_interface.h
+++ b/server/vd_interface.h
@@ -103,8 +103,6 @@ struct QXLWorker {
     uint32_t major_version;
     void (*wakeup)(QXLWorker *worker);
     void (*oom)(QXLWorker *worker);
-    void (*save)(QXLWorker *worker);
-    void (*load)(QXLWorker *worker);
     void (*start)(QXLWorker *worker);
     void (*stop)(QXLWorker *worker);
     void (*update_area)(QXLWorker *qxl_worker, uint32_t surface_id,
@@ -120,6 +118,7 @@ struct QXLWorker {
     void (*reset_image_cache)(QXLWorker *worker);
     void (*reset_cursor)(QXLWorker *worker);
     void (*destroy_surface_wait)(QXLWorker *worker, uint32_t surface_id);
+    void (*loadvm_commands)(QXLWorker *worker, struct QXLCommandExt *ext, uint32_t count);
 };
 
 typedef struct DrawArea {
@@ -196,8 +195,6 @@ struct QXLInterface {
     int (*get_cursor_command)(QXLInstance *qin, struct QXLCommandExt *cmd);
     int (*req_cursor_notification)(QXLInstance *qin);
     void (*notify_update)(QXLInstance *qin, uint32_t update_id);
-    void (*set_save_data)(QXLInstance *qin, void *data, int size);
-    void *(*get_save_data)(QXLInstance *qin);
     int (*flush_resources)(QXLInstance *qin);
 };
 
-- 
1.6.6.1



More information about the Spice-devel mailing list