On 07/19/2011 11:52 AM, Alon Levy wrote:
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.

A cookie has been added to each async call to QXLWorker, and is passed back via
async_complete.

Added api:

QXLWorker:
     update_area_async
     add_memslot_async
     destroy_surfaces_async
     destroy_primary_surface_async
     create_primary_surface_async
     destroy_surface_wait_async

QXLInterface:
     async_complete
---
  server/red_dispatcher.c |  242 ++++++++++++++++++++++++++++++++++++++++------
  server/red_dispatcher.h |    3 +-
  server/red_parse_qxl.c  |    2 +-
  server/red_parse_qxl.h  |    2 +-
  server/red_worker.c     |  158 +++++++++++++++++++++---------
  server/red_worker.h     |   10 ++
  server/spice.h          |   11 ++
  7 files changed, 345 insertions(+), 83 deletions(-)

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 56446ab..f0af364 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -43,7 +43,6 @@ static int num_active_workers = 0;

  //volatile

-typedef struct RedDispatcher RedDispatcher;
  struct RedDispatcher {
      QXLWorker base;
      QXLInstance *qxl;
@@ -55,6 +54,9 @@ struct RedDispatcher {
      int y_res;
      int use_hardware_cursor;
      RedDispatcher *next;
+    RedWorkerMessage async_message;
+    pthread_mutex_t  async_lock;
+    QXLDevSurfaceCreate *surface_create;
  };

  typedef struct RedWorkeState {
@@ -215,30 +217,50 @@ static void qxl_worker_update_area(QXLWorker *qxl_worker, 
uint32_t surface_id,
  {
      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);

      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));
      read_message(dispatcher->channel,&message);
      ASSERT(message == RED_WORKER_MESSAGE_READY);
+}
+
+static RedWorkerMessage red_dispatcher_async_start(RedDispatcher *dispatcher,
+                                                   RedWorkerMessage message)
+{
+    pthread_mutex_lock(&dispatcher->async_lock);
+    if (dispatcher->async_message != RED_WORKER_MESSAGE_NOP) {
+        red_printf("error: async clash. second async ignored");
+        pthread_mutex_unlock(&dispatcher->async_lock);
+        return RED_WORKER_MESSAGE_NOP;
+    }
+    dispatcher->async_message = message;
+    pthread_mutex_unlock(&dispatcher->async_lock);
+    return 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 void qxl_worker_update_area_async(QXLWorker *qxl_worker,
+                                         uint32_t surface_id,
+                                         QXLRect *qxl_area,
+                                         uint32_t clear_dirty_region,
+                                         uint64_t cookie)
+{
+    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                          
RED_WORKER_MESSAGE_UPDATE_ASYNC);
+
+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
      }

-    free(dirty_rects);
-    free(area);
+    write_message(dispatcher->channel,&message);
+    send_data(dispatcher->channel,&cookie, sizeof(cookie));
+    send_data(dispatcher->channel,&surface_id, sizeof(uint32_t));
+    send_data(dispatcher->channel, qxl_area, sizeof(QXLRect));
+    send_data(dispatcher->channel,&clear_dirty_region, sizeof(uint32_t));
  }

  static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot 
*mem_slot)
@@ -252,6 +274,20 @@ 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, uint64_t cookie)
+{
+    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                          
RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC);
+
+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
+    }
+    write_message(dispatcher->channel,&message);
+    send_data(dispatcher->channel,&cookie, sizeof(cookie));
+    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 +308,21 @@ 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, uint64_t 
cookie)
  {
      RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                      
RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC);

+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
+    }
      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);
+    send_data(dispatcher->channel,&cookie, sizeof(cookie));
+}

+static void red_dispatcher_destroy_primary_surface_complete(RedDispatcher 
*dispatcher)
+{
      dispatcher->x_res = 0;
      dispatcher->y_res = 0;
      dispatcher->use_hardware_cursor = FALSE;
@@ -290,24 +331,97 @@ 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_helper(QXLWorker *qxl_worker, 
uint32_t surface_id,
+                                              int async, uint64_t cookie)
  {
      RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkerMessage message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
+    RedWorkerMessage message;
+
+    if (async) {
+        message = red_dispatcher_async_start(dispatcher,
+                                             
RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC);
+        if (message == RED_WORKER_MESSAGE_NOP) {
+            return;
+        }
+    } else {
+        message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
+    }
+
+    write_message(dispatcher->channel,&message);
+    if (async) {
+        send_data(dispatcher->channel,&cookie, sizeof(cookie));
+    }
+    send_data(dispatcher->channel,&surface_id, sizeof(uint32_t));
+    if (!async) {
+        read_message(dispatcher->channel,&message);
+        ASSERT(message == RED_WORKER_MESSAGE_READY);
+        red_dispatcher_destroy_primary_surface_complete(dispatcher);
+    }
+}
+
+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, 0);
+}
+
+static void qxl_worker_destroy_primary_surface_async(QXLWorker *qxl_worker, 
uint32_t surface_id, uint64_t cookie)
+{
+    qxl_worker_destroy_primary_surface_helper(qxl_worker, surface_id, 1, 
cookie);
+}
+
+static void red_dispatcher_create_primary_surface_complete(RedDispatcher 
*dispatcher)
+{
+    QXLDevSurfaceCreate *surface = dispatcher->surface_create;

      dispatcher->x_res = surface->width;
      dispatcher->y_res = surface->height;
      dispatcher->use_hardware_cursor = surface->mouse_mode;
      dispatcher->primary_active = TRUE;

+    update_client_mouse_allowed();
+    dispatcher->surface_create = NULL;
+}
+
+static void qxl_worker_create_primary_surface_helper(QXLWorker *qxl_worker, 
uint32_t surface_id,
+                                      QXLDevSurfaceCreate *surface, int async, 
uint64_t cookie)
+{
+    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
+    RedWorkerMessage message;
+
+    if (async) {
+        message = red_dispatcher_async_start(dispatcher,
+                                             
RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC);
+        if (message == RED_WORKER_MESSAGE_NOP) {
+            return;
+        }
+    } else {
+        message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
+    }
+    dispatcher->surface_create = surface;
+
      write_message(dispatcher->channel,&message);
+    if (async) {
+        send_data(dispatcher->channel,&cookie, sizeof(cookie));
+    }
      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);
+        red_dispatcher_create_primary_surface_complete(dispatcher);
+    }
+}

-    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, 0);
+}
+
+static void qxl_worker_create_primary_surface_async(QXLWorker *qxl_worker, 
uint32_t surface_id,
+                                      QXLDevSurfaceCreate *surface, uint64_t 
cookie)
+{
+    qxl_worker_create_primary_surface_helper(qxl_worker, surface_id, surface, 
1, cookie);
  }

  static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
@@ -330,17 +444,44 @@ 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, uint64_t cookie)
  {
      RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
-    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
+    RedWorkerMessage message;
+
+    if (async ) {
+        message = red_dispatcher_async_start(dispatcher,
+                                             
RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC);
+        if (message == RED_WORKER_MESSAGE_NOP) {
+            return;
+        }
+    } else {
+        message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
+    }

      write_message(dispatcher->channel,&message);
+    if (async) {
+        send_data(dispatcher->channel,&cookie, sizeof(cookie));
+    }
      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, 0);
+}
+
+static void qxl_worker_destroy_surface_wait_async(QXLWorker *qxl_worker, 
uint32_t surface_id, uint64_t cookie)
+{
+    qxl_worker_destroy_surface_wait_helper(qxl_worker, surface_id, 1, cookie);
+}
+
  static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
  {
      RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
@@ -363,8 +504,9 @@ static void qxl_worker_wakeup(QXLWorker *qxl_worker)
  static void qxl_worker_oom(QXLWorker *qxl_worker)
  {
      RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
+    RedWorkerMessage message = RED_WORKER_MESSAGE_OOM;
+
      if (!test_bit(RED_WORKER_PENDING_OOM, dispatcher->pending)) {
-        RedWorkerMessage message = RED_WORKER_MESSAGE_OOM;
          set_bit(RED_WORKER_PENDING_OOM,&dispatcher->pending);
          write_message(dispatcher->channel,&message);
      }
@@ -482,6 +624,32 @@ uint32_t red_dispatcher_qxl_ram_size(void)
      return qxl_info.qxl_ram_size;
  }

+void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t 
cookie)
+{
+    pthread_mutex_lock(&dispatcher->async_lock);
+    switch (dispatcher->async_message) {
+    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
+        break;
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
+        break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
+        break;
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
+        red_dispatcher_create_primary_surface_complete(dispatcher);
+        break;
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
+        red_dispatcher_destroy_primary_surface_complete(dispatcher);
+        break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
+        break;
+    default:
+        red_printf("unexpected message");
+    }
+    dispatcher->async_message = RED_WORKER_MESSAGE_NOP;
+    pthread_mutex_unlock(&dispatcher->async_lock);
+    dispatcher->qxl->st->qif->async_complete(dispatcher->qxl, cookie);
+}
+
  RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
  {
      RedDispatcher *dispatcher;
@@ -514,6 +682,8 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
      init_data.num_renderers = num_renderers;
      memcpy(init_data.renderers, renderers, sizeof(init_data.renderers));

+    dispatcher->async_message = RED_WORKER_MESSAGE_NOP;
+    pthread_mutex_init(&dispatcher->async_lock, NULL);
      init_data.image_compression = image_compression;
      init_data.jpeg_state = jpeg_state;
      init_data.zlib_glz_state = zlib_glz_state;
@@ -530,14 +700,22 @@ 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;
+
      qxl->st->qif->get_init_info(qxl,&init_info);

      init_data.memslot_id_bits = init_info.memslot_id_bits;
@@ -546,6 +724,7 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
      init_data.num_memslots_groups = init_info.num_memslots_groups;
      init_data.internal_groupslot_id = init_info.internal_groupslot_id;
      init_data.n_surfaces = init_info.n_surfaces;
+    init_data.dispatcher = dispatcher;

      num_active_workers = 1;

@@ -586,4 +765,3 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
      dispatchers = dispatcher;
      return dispatcher;
  }
-
diff --git a/server/red_dispatcher.h b/server/red_dispatcher.h
index 3f3c1ae..fa347f1 100644
--- a/server/red_dispatcher.h
+++ b/server/red_dispatcher.h
@@ -18,7 +18,6 @@
  #ifndef _H_RED_DISPATCHER
  #define _H_RED_DISPATCHER

-
  struct RedDispatcher *red_dispatcher_init(QXLInstance *qxl);

  void red_dispatcher_set_mm_time(uint32_t);
@@ -29,5 +28,7 @@ int red_dispatcher_count(void);
  int red_dispatcher_add_renderer(const char *name);
  uint32_t red_dispatcher_qxl_ram_size(void);
  int red_dispatcher_qxl_count(void);
+void red_dispatcher_async_complete(struct RedDispatcher*, uint64_t);
+
  #endif

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 2349ac5..5a8431a 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -61,6 +61,7 @@
  #include "generated_marshallers.h"
  #include "zlib_encoder.h"
  #include "red_channel.h"
+#include "red_dispatcher.h"

  //#define COMPRESS_STAT
  //#define DUMP_BITMAP
@@ -805,6 +806,7 @@ typedef struct RedWorker {
      DisplayChannel *display_channel;
      CursorChannel *cursor_channel;
      QXLInstance *qxl;
+    RedDispatcher *dispatcher;
      int id;
      int channel;
      int running;
@@ -9424,22 +9426,46 @@ static void red_wait_pipe_item_sent(RedChannel 
*channel, PipeItem *item)
      red_unref_channel(channel);
  }

+static inline void handle_dev_update_async(RedWorker *worker)
+{
+    QXLRect qxl_rect;
+    SpiceRect rect;
+    uint32_t surface_id;
+    uint32_t clear_dirty_region;
+
+    receive_data(worker->channel,&surface_id, sizeof(uint32_t));
+    receive_data(worker->channel,&qxl_rect, sizeof(QXLRect));
+    receive_data(worker->channel,&clear_dirty_region, sizeof(uint32_t));
+
+    red_get_rect_ptr(&rect,&qxl_rect);
+    flush_display_commands(worker);
+
+    ASSERT(worker->running);
+
+    validate_surface(worker, surface_id);
+    red_update_area(worker,&rect, surface_id);
+}
+
  static inline void handle_dev_update(RedWorker *worker)
  {
-    RedWorkerMessage message;
-    const SpiceRect *rect;
+    const QXLRect *qxl_rect;
+    SpiceRect *rect = spice_new0(SpiceRect, 1);

Hi,

Ack all except: (1) missing free for rect (and also dirty_rects bellow, but a following patch fix it) (2) missing patch for resending surfaces that are reloaded to the worker after S3 (3) probably need to open a bug for calling reds_set_client_mouse_allowed from the dispatcher (looks like an ancient bug), from vcpu thread, while reds runs in io thread. And now with async, it can also be called from red_worker thread.

Cheers,
Yonit.

+    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);
@@ -9453,15 +9479,16 @@ 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));
@@ -9469,9 +9496,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)
@@ -9507,7 +9531,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));
@@ -9519,9 +9542,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)
@@ -9549,7 +9569,6 @@ static inline void red_cursor_reset(RedWorker *worker)
  static inline void handle_dev_destroy_surfaces(RedWorker *worker)
  {
      int i;
-    RedWorkerMessage message;

      flush_all_qxl_commands(worker);
      //to handle better
@@ -9572,14 +9591,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;
@@ -9609,14 +9624,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));
@@ -9632,22 +9643,78 @@ 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_stop(RedWorker *worker)
+{
+    int x;
+
+    ASSERT(worker->running);
+    worker->running = FALSE;
+    red_display_clear_glz_drawables(worker->display_channel);
+    for (x = 0; x<  NUM_SURFACES; ++x) {
+        if (worker->surfaces[x].context.canvas) {
+            red_current_flush(worker, x);
+        }
+    }
+    red_wait_outgoing_item((RedChannel *)worker->display_channel);
+    red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
+}
+
+static void handle_dev_start(RedWorker *worker)
+{
+    RedChannel *cursor_red_channel =&worker->cursor_channel->common.base;
+    RedChannel *display_red_channel =&worker->display_channel->common.base;
+
+    ASSERT(!worker->running);
+    if (worker->cursor_channel) {
+        cursor_red_channel->migrate = FALSE;
+    }
+    if (worker->display_channel) {
+        display_red_channel->migrate = FALSE;
+    }
+    worker->running = TRUE;
  }

  static void handle_dev_input(EventListener *listener, uint32_t events)
  {
      RedWorker *worker = SPICE_CONTAINEROF(listener, RedWorker, dev_listener);
      RedWorkerMessage message;
-    RedChannel *cursor_red_channel =&worker->cursor_channel->common.base;
      RedChannel *display_red_channel =&worker->display_channel->common.base;
      int ring_is_empty;
+    int call_async_complete = 0;
+    int write_ready = 0;
+    uint64_t cookie;

      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:
+        call_async_complete = 1;
+        receive_data(worker->channel,&cookie, sizeof(cookie));
+        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:
+        handle_dev_update_async(worker);
+        break;
      case RED_WORKER_MESSAGE_UPDATE:
          handle_dev_update(worker);
          break;
@@ -9679,15 +9746,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;
@@ -9706,33 +9777,15 @@ static void handle_dev_input(EventListener *listener, 
uint32_t events)
          red_disconnect_display((RedChannel *)worker->display_channel);
          break;
      case RED_WORKER_MESSAGE_STOP: {
-        int x;
-
          red_printf("stop");
-        ASSERT(worker->running);
-        worker->running = FALSE;
-        red_display_clear_glz_drawables(worker->display_channel);
-        for (x = 0; x<  NUM_SURFACES; ++x) {
-            if (worker->surfaces[x].context.canvas) {
-                red_current_flush(worker, x);
-            }
-        }
-        red_wait_outgoing_item((RedChannel *)worker->display_channel);
-        red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
+        handle_dev_stop(worker);
          message = RED_WORKER_MESSAGE_READY;
          write_message(worker->channel,&message);
          break;
      }
      case RED_WORKER_MESSAGE_START:
          red_printf("start");
-        ASSERT(!worker->running);
-        if (worker->cursor_channel) {
-            cursor_red_channel->migrate = FALSE;
-        }
-        if (worker->display_channel) {
-            display_red_channel->migrate = FALSE;
-        }
-        worker->running = TRUE;
+        handle_dev_start(worker);
          break;
      case RED_WORKER_MESSAGE_DISPLAY_MIGRATE:
          red_printf("migrate");
@@ -9814,6 +9867,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;
@@ -9859,6 +9913,13 @@ static void handle_dev_input(EventListener *listener, 
uint32_t events)
      default:
          red_error("message error");
      }
+    if (call_async_complete) {
+        red_dispatcher_async_complete(worker->dispatcher, cookie);
+    }
+    if (write_ready) {
+        message = RED_WORKER_MESSAGE_READY;
+        write_message(worker->channel,&message);
+    }
  }

  static void handle_dev_free(EventListener *ctx)
@@ -9875,6 +9936,7 @@ static void red_init(RedWorker *worker, WorkerInitData 
*init_data)
      ASSERT(sizeof(CursorItem)<= QXL_CURSUR_DEVICE_DATA_SIZE);

      memset(worker, 0, sizeof(RedWorker));
+    worker->dispatcher = init_data->dispatcher;
      worker->qxl = init_data->qxl;
      worker->id = init_data->id;
      worker->channel = init_data->channel;
diff --git a/server/red_worker.h b/server/red_worker.h
index b4e2ed2..604437b 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -70,6 +70,13 @@ 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,
  };

  typedef uint32_t RedWorkerMessage;
@@ -83,6 +90,8 @@ enum {
      RED_RENDERER_OGL_PIXMAP,
  };

+typedef struct RedDispatcher RedDispatcher;
+
  typedef struct WorkerInitData {
      struct QXLInstance *qxl;
      int id;
@@ -100,6 +109,7 @@ typedef struct WorkerInitData {
      uint8_t memslot_id_bits;
      uint8_t internal_groupslot_id;
      uint32_t n_surfaces;
+    RedDispatcher *dispatcher;
  } WorkerInitData;

  void *red_worker_main(void *arg);
diff --git a/server/spice.h b/server/spice.h
index f64ff41..544166b 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -122,6 +122,16 @@ 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, uint32_t clear_dirty_region,
+                       uint64_t cookie);
+    void (*add_memslot_async)(QXLWorker *worker, QXLDevMemSlot *slot, uint64_t 
cookie);
+    void (*destroy_surfaces_async)(QXLWorker *worker, uint64_t cookie);
+    void (*destroy_primary_surface_async)(QXLWorker *worker, uint32_t 
surface_id, uint64_t cookie);
+    void (*create_primary_surface_async)(QXLWorker *worker, uint32_t 
surface_id,
+                                   QXLDevSurfaceCreate *surface, uint64_t 
cookie);
+    void (*destroy_surface_wait_async)(QXLWorker *worker, uint32_t surface_id, 
uint64_t cookie);
  };

  typedef struct QXLDrawArea {
@@ -192,6 +202,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, uint64_t cookie);
  };

  struct QXLInstance {

_______________________________________________
Spice-devel mailing list
Spice-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/spice-devel

Reply via email to