[Spice-devel] [PATCH v2] server: add async io support

Alon Levy alevy at redhat.com
Wed Jul 6 10:37:16 PDT 2011


The new _ASYNC io's in qxl_dev listed at the end get six new api
functions, and an additional callback function "async_complete". When
the async version of a specific io is used, completion is notified by
calling async_complete, and no READY message is written or expected by
the dispatcher.

update_area has been changed to push QXLRects to the worker thread, where
the conversion to SpiceRect takes place.

Added api:

QXLWorker:
    update_area_async
    add_memslot_async
    destroy_surfaces_async
    destroy_primary_surface_async
    create_primary_surface_async
    destroy_surface_wait_async
    oom_async

QXLInterface:
    async_complete
---
 server/red_dispatcher.c |  179 ++++++++++++++++++++++++++++++++++++++---------
 server/red_parse_qxl.c  |    2 +-
 server/red_parse_qxl.h  |    2 +-
 server/red_worker.c     |   80 ++++++++++++++-------
 server/red_worker.h     |    8 ++
 server/spice.h          |   12 +++
 6 files changed, 221 insertions(+), 62 deletions(-)

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 56446ab..74c7af2 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -209,38 +209,49 @@ static void update_client_mouse_allowed(void)
     }
 }
 
-static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
+static void qxl_worker_update_area_helper(QXLWorker *qxl_worker, uint32_t surface_id,
                                    QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
-                                   uint32_t num_dirty_rects, uint32_t clear_dirty_region)
+                                   uint32_t num_dirty_rects, uint32_t clear_dirty_region,
+                                   int async)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE;
-    SpiceRect *dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
-    SpiceRect *area = spice_new0(SpiceRect, 1);
-    int i;
-
-    red_get_rect_ptr(area, qxl_area);
+    RedWorkerMessage message;
 
+    if (async) {
+         message = RED_WORKER_MESSAGE_UPDATE_ASYNC;
+    } else {
+         message = RED_WORKER_MESSAGE_UPDATE;
+    }
     write_message(dispatcher->channel, &message);
     send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
-    send_data(dispatcher->channel, &area, sizeof(SpiceRect *));
-    send_data(dispatcher->channel, &dirty_rects, sizeof(SpiceRect *));
+    send_data(dispatcher->channel, &qxl_area, sizeof(QXLRect *));
+    send_data(dispatcher->channel, &qxl_dirty_rects, sizeof(QXLRect *));
     send_data(dispatcher->channel, &num_dirty_rects, sizeof(uint32_t));
     send_data(dispatcher->channel, &clear_dirty_region, sizeof(uint32_t));
+    if (async) {
+        return;
+    }
     read_message(dispatcher->channel, &message);
     ASSERT(message == RED_WORKER_MESSAGE_READY);
+}
 
-    for (i = 0; i < num_dirty_rects; i++) {
-        qxl_dirty_rects[i].top    = dirty_rects[i].top;
-        qxl_dirty_rects[i].left   = dirty_rects[i].left;
-        qxl_dirty_rects[i].bottom = dirty_rects[i].bottom;
-        qxl_dirty_rects[i].right  = dirty_rects[i].right;
-    }
+static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
+                                   QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
+                                   uint32_t num_dirty_rects, uint32_t clear_dirty_region)
+{
+    qxl_worker_update_area_helper(qxl_worker, surface_id, qxl_area, qxl_dirty_rects, num_dirty_rects,
+        clear_dirty_region, 0);
+}
 
-    free(dirty_rects);
-    free(area);
+static void qxl_worker_update_area_async(QXLWorker *qxl_worker, uint32_t surface_id,
+                                   QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
+                                   uint32_t num_dirty_rects, uint32_t clear_dirty_region)
+{
+    qxl_worker_update_area_helper(qxl_worker, surface_id, qxl_area, qxl_dirty_rects, num_dirty_rects,
+        clear_dirty_region, 1);
 }
 
+
 static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
@@ -252,6 +263,15 @@ static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slo
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
+static void qxl_worker_add_memslot_async(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot)
+{
+    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
+    RedWorkerMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC;
+
+    write_message(dispatcher->channel, &message);
+    send_data(dispatcher->channel, mem_slot, sizeof(QXLDevMemSlot));
+}
+
 static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id, uint32_t slot_id)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
@@ -272,16 +292,34 @@ static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_id)
+static void qxl_worker_destroy_surfaces_async(QXLWorker *qxl_worker)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
+    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC;
+
+    write_message(dispatcher->channel, &message);
+}
+
+static void qxl_worker_destroy_primary_surface_helper(QXLWorker *qxl_worker, uint32_t surface_id,
+                                              int async)
+{
+    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
+    RedWorkerMessage message;
+
+    if (async) {
+        message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC;
+    } else {
+        message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
+    }
 
     write_message(dispatcher->channel, &message);
     send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
-    read_message(dispatcher->channel, &message);
-    ASSERT(message == RED_WORKER_MESSAGE_READY);
+    if (!async) {
+        read_message(dispatcher->channel, &message);
+        ASSERT(message == RED_WORKER_MESSAGE_READY);
+    }
 
+    /* in async case this is set before primary is destroyed in worker */
     dispatcher->x_res = 0;
     dispatcher->y_res = 0;
     dispatcher->use_hardware_cursor = FALSE;
@@ -290,11 +328,27 @@ static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_i
     update_client_mouse_allowed();
 }
 
-static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id,
-                                      QXLDevSurfaceCreate *surface)
+static void qxl_worker_destroy_primary_surface(QXLWorker *qxl_worker, uint32_t surface_id)
+{
+    qxl_worker_destroy_primary_surface_helper(qxl_worker, surface_id, 0);
+}
+
+static void qxl_worker_destroy_primary_surface_async(QXLWorker *qxl_worker, uint32_t surface_id)
+{
+    qxl_worker_destroy_primary_surface_helper(qxl_worker, surface_id, 1);
+}
+
+static void qxl_worker_create_primary_surface_helper(QXLWorker *qxl_worker, uint32_t surface_id,
+                                      QXLDevSurfaceCreate *surface, int async)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkerMessage message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
+    RedWorkerMessage message;
+
+    if (async) {
+        message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC;
+    } else {
+        message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
+    }
 
     dispatcher->x_res = surface->width;
     dispatcher->y_res = surface->height;
@@ -304,12 +358,26 @@ static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id
     write_message(dispatcher->channel, &message);
     send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
     send_data(dispatcher->channel, surface, sizeof(QXLDevSurfaceCreate));
-    read_message(dispatcher->channel, &message);
-    ASSERT(message == RED_WORKER_MESSAGE_READY);
+    if (!async) {
+        read_message(dispatcher->channel, &message);
+        ASSERT(message == RED_WORKER_MESSAGE_READY);
+    }
 
     update_client_mouse_allowed();
 }
 
+static void qxl_worker_create_primary_surface(QXLWorker *qxl_worker, uint32_t surface_id,
+                                      QXLDevSurfaceCreate *surface)
+{
+    qxl_worker_create_primary_surface_helper(qxl_worker, surface_id, surface, 0);
+}
+
+static void qxl_worker_create_primary_surface_async(QXLWorker *qxl_worker, uint32_t surface_id,
+                                      QXLDevSurfaceCreate *surface)
+{
+    qxl_worker_create_primary_surface_helper(qxl_worker, surface_id, surface, 1);
+}
+
 static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
@@ -330,17 +398,37 @@ static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surface_id)
+static void qxl_worker_destroy_surface_wait_helper(QXLWorker *qxl_worker, uint32_t surface_id,
+                                                   int async)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
+    RedWorkerMessage message;
+
+    if (async ) {
+        message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC;
+    } else {
+        message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
+    }
 
     write_message(dispatcher->channel, &message);
     send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
+    if (async) {
+        return;
+    }
     read_message(dispatcher->channel, &message);
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
+static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surface_id)
+{
+    qxl_worker_destroy_surface_wait_helper(qxl_worker, surface_id, 0);
+}
+
+static void qxl_worker_destroy_surface_wait_async(QXLWorker *qxl_worker, uint32_t surface_id)
+{
+    qxl_worker_destroy_surface_wait_helper(qxl_worker, surface_id, 1);
+}
+
 static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
@@ -360,16 +448,32 @@ static void qxl_worker_wakeup(QXLWorker *qxl_worker)
     }
 }
 
-static void qxl_worker_oom(QXLWorker *qxl_worker)
+static void qxl_worker_oom_helper(QXLWorker *qxl_worker, int async)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
+    RedWorkerMessage message;
+
     if (!test_bit(RED_WORKER_PENDING_OOM, dispatcher->pending)) {
-        RedWorkerMessage message = RED_WORKER_MESSAGE_OOM;
+        if (async) {
+            message = RED_WORKER_MESSAGE_OOM_ASYNC;
+        } else {
+            message = RED_WORKER_MESSAGE_OOM;
+        }
         set_bit(RED_WORKER_PENDING_OOM, &dispatcher->pending);
         write_message(dispatcher->channel, &message);
     }
 }
 
+static void qxl_worker_oom(QXLWorker *qxl_worker)
+{
+    qxl_worker_oom_helper(qxl_worker, 0);
+}
+
+static void qxl_worker_oom_async(QXLWorker *qxl_worker)
+{
+    qxl_worker_oom_helper(qxl_worker, 1);
+}
+
 static void qxl_worker_start(QXLWorker *qxl_worker)
 {
     RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
@@ -530,14 +634,23 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     dispatcher->base.del_memslot = qxl_worker_del_memslot;
     dispatcher->base.reset_memslots = qxl_worker_reset_memslots;
     dispatcher->base.destroy_surfaces = qxl_worker_destroy_surfaces;
-    dispatcher->base.create_primary_surface = qxl_worker_create_primary;
-    dispatcher->base.destroy_primary_surface = qxl_worker_destroy_primary;
+    dispatcher->base.create_primary_surface = qxl_worker_create_primary_surface;
+    dispatcher->base.destroy_primary_surface = qxl_worker_destroy_primary_surface;
 
     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;
 
+    dispatcher->base.update_area_async = qxl_worker_update_area_async;
+    dispatcher->base.add_memslot_async = qxl_worker_add_memslot_async;
+    dispatcher->base.reset_memslots = qxl_worker_reset_memslots;
+    dispatcher->base.destroy_surfaces_async = qxl_worker_destroy_surfaces_async;
+    dispatcher->base.destroy_primary_surface_async = qxl_worker_destroy_primary_surface_async;
+    dispatcher->base.create_primary_surface_async = qxl_worker_create_primary_surface_async;
+    dispatcher->base.destroy_surface_wait_async = qxl_worker_destroy_surface_wait_async;
+    dispatcher->base.oom_async = qxl_worker_oom_async;
+
     qxl->st->qif->get_init_info(qxl, &init_info);
 
     init_data.memslot_id_bits = init_info.memslot_id_bits;
diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c
index 258a541..7737c04 100644
--- a/server/red_parse_qxl.c
+++ b/server/red_parse_qxl.c
@@ -148,7 +148,7 @@ static void red_get_point16_ptr(SpicePoint16 *red, QXLPoint16 *qxl)
     red->y = qxl->y;
 }
 
-void red_get_rect_ptr(SpiceRect *red, QXLRect *qxl)
+void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl)
 {
     red->top    = qxl->top;
     red->left   = qxl->left;
diff --git a/server/red_parse_qxl.h b/server/red_parse_qxl.h
index 5de0325..a713dcf 100644
--- a/server/red_parse_qxl.h
+++ b/server/red_parse_qxl.h
@@ -110,7 +110,7 @@ typedef struct RedCursorCmd {
     uint8_t *device_data;
 } RedCursorCmd;
 
-void red_get_rect_ptr(SpiceRect *red, QXLRect *qxl);
+void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl);
 
 void red_get_drawable(RedMemSlotInfo *slots, int group_id,
                       RedDrawable *red, QXLPHYSICAL addr, uint32_t flags);
diff --git a/server/red_worker.c b/server/red_worker.c
index 9a61e86..1480218 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9417,20 +9417,24 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
 
 static inline void handle_dev_update(RedWorker *worker)
 {
-    RedWorkerMessage message;
-    const SpiceRect *rect;
+    const QXLRect *qxl_rect;
+    SpiceRect *rect = spice_new0(SpiceRect, 1);
+    QXLRect *qxl_dirty_rects;
     SpiceRect *dirty_rects;
     RedSurface *surface;
     uint32_t num_dirty_rects;
     uint32_t surface_id;
     uint32_t clear_dirty_region;
+    int i;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
-    receive_data(worker->channel, &rect, sizeof(SpiceRect *));
-    receive_data(worker->channel, &dirty_rects, sizeof(SpiceRect *));
+    receive_data(worker->channel, &qxl_rect, sizeof(QXLRect *));
+    receive_data(worker->channel, &qxl_dirty_rects, sizeof(QXLRect *));
     receive_data(worker->channel, &num_dirty_rects, sizeof(uint32_t));
     receive_data(worker->channel, &clear_dirty_region, sizeof(uint32_t));
 
+    dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
+    red_get_rect_ptr(rect, qxl_rect);
     flush_display_commands(worker);
 
     ASSERT(worker->running);
@@ -9444,15 +9448,17 @@ static inline void handle_dev_update(RedWorker *worker)
     if (clear_dirty_region) {
         region_clear(&surface->draw_dirty_region);
     }
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
+    for (i = 0; i < num_dirty_rects; i++) {
+        qxl_dirty_rects[i].top    = dirty_rects[i].top;
+        qxl_dirty_rects[i].left   = dirty_rects[i].left;
+        qxl_dirty_rects[i].bottom = dirty_rects[i].bottom;
+        qxl_dirty_rects[i].right  = dirty_rects[i].right;
+    }
 }
 
 
 static inline void handle_dev_add_memslot(RedWorker *worker)
 {
-    RedWorkerMessage message;
     QXLDevMemSlot dev_slot;
 
     receive_data(worker->channel, &dev_slot, sizeof(QXLDevMemSlot));
@@ -9460,9 +9466,6 @@ static inline void handle_dev_add_memslot(RedWorker *worker)
     red_memslot_info_add_slot(&worker->mem_slots, dev_slot.slot_group_id, dev_slot.slot_id,
                               dev_slot.addr_delta, dev_slot.virt_start, dev_slot.virt_end,
                               dev_slot.generation);
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void handle_dev_del_memslot(RedWorker *worker)
@@ -9498,7 +9501,6 @@ static inline void destroy_surface_wait(RedWorker *worker, int surface_id)
 
 static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
 {
-    RedWorkerMessage message;
     uint32_t surface_id;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
@@ -9510,9 +9512,6 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
     if (worker->surfaces[0].context.canvas) {
         destroy_surface_wait(worker, 0);
     }
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void red_cursor_reset(RedWorker *worker)
@@ -9540,7 +9539,6 @@ static inline void red_cursor_reset(RedWorker *worker)
 static inline void handle_dev_destroy_surfaces(RedWorker *worker)
 {
     int i;
-    RedWorkerMessage message;
     red_printf("");
     flush_all_qxl_commands(worker);
     //to handle better
@@ -9563,14 +9561,10 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
     red_display_clear_glz_drawables(worker->display_channel);
 
     red_cursor_reset(worker);
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void handle_dev_create_primary_surface(RedWorker *worker)
 {
-    RedWorkerMessage message;
     uint32_t surface_id;
     QXLDevSurfaceCreate surface;
     uint8_t *line_0;
@@ -9600,14 +9594,10 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
     if (worker->cursor_channel) {
         red_channel_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
     }
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
 {
-    RedWorkerMessage message;
     uint32_t surface_id;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
@@ -9623,9 +9613,6 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
     ASSERT(!worker->surfaces[surface_id].context.canvas);
 
     red_cursor_reset(worker);
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static void handle_dev_input(EventListener *listener, uint32_t events)
@@ -9635,10 +9622,36 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     RedChannel *cursor_red_channel = &worker->cursor_channel->common.base;
     RedChannel *display_red_channel = &worker->display_channel->common.base;
     int ring_is_empty;
+    int async = 0;
+    int write_ready = 0;
 
     read_message(worker->channel, &message);
 
+    /* for async messages we do the common work in the handler, and
+     * send a ready or call async_complete from here, hence the added switch. */
     switch (message) {
+    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
+    case RED_WORKER_MESSAGE_OOM_ASYNC:
+        async = 1;
+        break;
+    case RED_WORKER_MESSAGE_UPDATE:
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES:
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE:
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT:
+        write_ready = 1;
+    default:
+        break;
+    }
+
+    switch (message) {
+    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
     case RED_WORKER_MESSAGE_UPDATE:
         handle_dev_update(worker);
         break;
@@ -9646,6 +9659,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         clear_bit(RED_WORKER_PENDING_WAKEUP, worker->pending);
         stat_inc_counter(worker->wakeup_counter, 1);
         break;
+    case RED_WORKER_MESSAGE_OOM_ASYNC:
     case RED_WORKER_MESSAGE_OOM:
         ASSERT(worker->running);
         while (red_process_commands(worker, MAX_PIPE_SIZE, &ring_is_empty)) {
@@ -9670,15 +9684,19 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         message = RED_WORKER_MESSAGE_READY;
         write_message(worker->channel, &message);
         break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT:
         handle_dev_destroy_surface_wait(worker);
         break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACES:
         handle_dev_destroy_surfaces(worker);
         break;
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
     case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE:
         handle_dev_create_primary_surface(worker);
         break;
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE:
         handle_dev_destroy_primary_surface(worker);
         break;
@@ -9805,6 +9823,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         receive_data(worker->channel, &worker->mouse_mode, sizeof(uint32_t));
         red_printf("mouse mode %u", worker->mouse_mode);
         break;
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
     case RED_WORKER_MESSAGE_ADD_MEMSLOT:
         handle_dev_add_memslot(worker);
         break;
@@ -9850,6 +9869,13 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     default:
         red_error("message error");
     }
+    if (async) {
+        worker->qxl->st->qif->async_complete(worker->qxl);
+    }
+    if (write_ready) {
+        message = RED_WORKER_MESSAGE_READY;
+        write_message(worker->channel, &message);
+    }
 }
 
 static void handle_dev_free(EventListener *ctx)
diff --git a/server/red_worker.h b/server/red_worker.h
index b4e2ed2..9ed7156 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -70,6 +70,14 @@ enum {
     RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
     RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
     RED_WORKER_MESSAGE_LOADVM_COMMANDS,
+    /* async commands */
+    RED_WORKER_MESSAGE_UPDATE_ASYNC,
+    RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC,
+    RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC,
+    RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC,
+    RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC,
+    RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC,
+    RED_WORKER_MESSAGE_OOM_ASYNC,
 };
 
 typedef uint32_t RedWorkerMessage;
diff --git a/server/spice.h b/server/spice.h
index f64ff41..f0d5685 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -122,6 +122,17 @@ struct QXLWorker {
     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);
+    /* async versions of commands. when complete spice calls async_complete */
+    void (*update_area_async)(QXLWorker *qxl_worker, uint32_t surface_id,
+                       struct QXLRect *area, struct QXLRect *dirty_rects,
+                       uint32_t num_dirty_rects, uint32_t clear_dirty_region);
+    void (*add_memslot_async)(QXLWorker *worker, QXLDevMemSlot *slot);
+    void (*destroy_surfaces_async)(QXLWorker *worker);
+    void (*destroy_primary_surface_async)(QXLWorker *worker, uint32_t surface_id);
+    void (*create_primary_surface_async)(QXLWorker *worker, uint32_t surface_id,
+                                   QXLDevSurfaceCreate *surface);
+    void (*destroy_surface_wait_async)(QXLWorker *worker, uint32_t surface_id);
+    void (*oom_async)(QXLWorker *worker);
 };
 
 typedef struct QXLDrawArea {
@@ -192,6 +203,7 @@ struct QXLInterface {
     int (*req_cursor_notification)(QXLInstance *qin);
     void (*notify_update)(QXLInstance *qin, uint32_t update_id);
     int (*flush_resources)(QXLInstance *qin);
+    void (*async_complete)(QXLInstance *qin);
 };
 
 struct QXLInstance {
-- 
1.7.5.4



More information about the Spice-devel mailing list