[Spice-devel] [PATCH 2/2] red_dispatcher: support concurrent asyncs

Alon Levy alevy at redhat.com
Mon Oct 24 05:09:52 PDT 2011


Allows doing async commands from the monitor and from any vcpu thread
independently, i.e. red_dispatcher can have multiple commands pending
completion. red_worker still handles them sequentially off it's pipe, no
magical gain here.

RHBZ: 747011
FDBZ: 41622
---
 server/red_dispatcher.c |   85 ++++++++++++++++++++++++++++++++++------------
 server/red_worker.c     |   15 ++++++++
 2 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 6731727..86da0b6 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -43,6 +43,13 @@ static int num_active_workers = 0;
 
 //volatile
 
+typedef struct AsyncCommand AsyncCommand;
+struct AsyncCommand {
+    AsyncCommand *next;
+    RedWorkerMessage message;
+    uint64_t cookie;
+};
+
 struct RedDispatcher {
     QXLWorker base;
     QXLInstance *qxl;
@@ -54,7 +61,7 @@ struct RedDispatcher {
     int y_res;
     int use_hardware_cursor;
     RedDispatcher *next;
-    RedWorkerMessage async_message;
+    AsyncCommand* async_commands;
     pthread_mutex_t  async_lock;
     QXLDevSurfaceCreate surface_create;
 };
@@ -263,18 +270,26 @@ static void red_dispatcher_update_area(RedDispatcher *dispatcher, uint32_t surfa
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static RedWorkerMessage red_dispatcher_async_start(RedDispatcher *dispatcher,
-                                                   RedWorkerMessage message)
+static AsyncCommand *push_async_command(RedDispatcher *dispatcher,
+                                        RedWorkerMessage message,
+                                        uint64_t cookie)
 {
+    AsyncCommand *async_command = spice_new(AsyncCommand, 1);
+
     pthread_mutex_lock(&dispatcher->async_lock);
-    if (dispatcher->async_message != RED_WORKER_MESSAGE_NOP) {
-        red_printf("warning: async clash. have %d, ignoring %d",
-                 dispatcher->async_message, message);
-        pthread_mutex_unlock(&dispatcher->async_lock);
-        return RED_WORKER_MESSAGE_NOP;
-    }
-    dispatcher->async_message = message;
+    async_command->cookie = cookie;
+    async_command->message = message;
+    async_command->next = dispatcher->async_commands;
+    dispatcher->async_commands = async_command;
     pthread_mutex_unlock(&dispatcher->async_lock);
+    return async_command;
+}
+
+static RedWorkerMessage red_dispatcher_async_start(RedDispatcher *dispatcher,
+                                                   RedWorkerMessage message,
+                                                   uint64_t cookie)
+{
+    push_async_command(dispatcher, message, cookie);
     return message;
 }
 
@@ -285,7 +300,8 @@ static void red_dispatcher_update_area_async(RedDispatcher *dispatcher,
                                          uint64_t cookie)
 {
     RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
-                                                          RED_WORKER_MESSAGE_UPDATE_ASYNC);
+                                                          RED_WORKER_MESSAGE_UPDATE_ASYNC,
+                                                          cookie);
 
     if (message == RED_WORKER_MESSAGE_NOP) {
         return;
@@ -304,7 +320,7 @@ static void red_dispatcher_update_area_dirty_async(RedDispatcher *dispatcher,
                                        uint32_t clear_dirty_region, uint64_t cookie)
 {
     RedWorkerMessage message = red_dispatcher_async_start(
-            dispatcher, RED_WORKER_MESSAGE_UPDATE_DIRTY_ASYNC);
+            dispatcher, RED_WORKER_MESSAGE_UPDATE_DIRTY_ASYNC, cookie);
 
     if (message == RED_WORKER_MESSAGE_NOP) {
         return;
@@ -345,7 +361,8 @@ static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slo
 static void red_dispatcher_add_memslot_async(RedDispatcher *dispatcher, QXLDevMemSlot *mem_slot, uint64_t cookie)
 {
     RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
-                                                          RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC);
+                                                          RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC,
+                                                          cookie);
 
     if (message == RED_WORKER_MESSAGE_NOP) {
         return;
@@ -386,7 +403,8 @@ static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
 static void red_dispatcher_destroy_surfaces_async(RedDispatcher *dispatcher, uint64_t cookie)
 {
     RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
-                                                      RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC);
+                                                      RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC,
+                                                      cookie);
 
     if (message == RED_WORKER_MESSAGE_NOP) {
         return;
@@ -413,7 +431,8 @@ red_dispatcher_destroy_primary_surface(RedDispatcher *dispatcher,
 
     if (async) {
         message = red_dispatcher_async_start(dispatcher,
-                                             RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC);
+                                             RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC,
+                                             cookie);
         if (message == RED_WORKER_MESSAGE_NOP) {
             return;
         }
@@ -459,7 +478,8 @@ red_dispatcher_create_primary_surface(RedDispatcher *dispatcher, uint32_t surfac
 
     if (async) {
         message = red_dispatcher_async_start(dispatcher,
-                                             RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC);
+                                             RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC,
+                                             cookie);
         if (message == RED_WORKER_MESSAGE_NOP) {
             return;
         }
@@ -522,7 +542,8 @@ static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint3
 
     if (async ) {
         message = red_dispatcher_async_start(dispatcher,
-                                             RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC);
+                                             RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC,
+                                             cookie);
         if (message == RED_WORKER_MESSAGE_NOP) {
             return;
         }
@@ -602,7 +623,8 @@ static void qxl_worker_start(QXLWorker *qxl_worker)
 static void red_dispatcher_flush_surfaces_async(RedDispatcher *dispatcher, uint64_t cookie)
 {
     RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
-                                                          RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC);
+                                                          RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC,
+                                                          cookie);
 
     if (message == RED_WORKER_MESSAGE_NOP) {
         return;
@@ -875,8 +897,27 @@ void spice_qxl_flush_surfaces_async(QXLInstance *instance, uint64_t cookie)
 
 void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t cookie)
 {
+    AsyncCommand *async_command;
+    AsyncCommand *prev;
+
     pthread_mutex_lock(&dispatcher->async_lock);
-    switch (dispatcher->async_message) {
+    async_command = dispatcher->async_commands;
+    prev = NULL;
+    while (async_command && async_command->cookie != cookie) {
+         prev = async_command;
+         async_command = async_command->next;
+    };
+    if (!async_command) {
+        WARN("unknown cookie");
+        goto end;
+    }
+    if (!prev) {
+        red_printf_debug(2, "%s: no more async commands\n", __func__);
+        dispatcher->async_commands = NULL;
+    } else {
+        prev->next = async_command->next;
+    }
+    switch (async_command->message) {
     case RED_WORKER_MESSAGE_UPDATE_ASYNC:
     case RED_WORKER_MESSAGE_UPDATE_DIRTY_ASYNC:
         break;
@@ -895,9 +936,10 @@ void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t co
     case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
         break;
     default:
-        red_printf("unexpected message");
+        WARN("unexpected message");
     }
-    dispatcher->async_message = RED_WORKER_MESSAGE_NOP;
+end:
+    free(async_command);
     pthread_mutex_unlock(&dispatcher->async_lock);
     dispatcher->qxl->st->qif->async_complete(dispatcher->qxl, cookie);
 }
@@ -961,7 +1003,6 @@ 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;
diff --git a/server/red_worker.c b/server/red_worker.c
index 5a77f35..5f74417 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -10112,6 +10112,7 @@ static inline void handle_dev_update_async(RedWorker *worker, int with_dirty)
     QXLRect *qxl_dirty_rects = NULL;
     uint32_t num_dirty_rects;
     RedSurface *surface;
+    int i;
 
     red_printf_debug(2, "");
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
@@ -10139,6 +10140,7 @@ static inline void handle_dev_update_async(RedWorker *worker, int with_dirty)
             qxl_dirty_rects = spice_new0(QXLRect, num_dirty_rects);
         }
     }
+    red_printf_debug(2, "num_dirty_rects = %d, with_dirty = %d", num_dirty_rects, with_dirty);
     if (num_dirty_rects > 0) {
         surface_dirty_region_to_rects(surface, qxl_dirty_rects, num_dirty_rects,
                                       clear_dirty_region);
@@ -10150,6 +10152,19 @@ static inline void handle_dev_update_async(RedWorker *worker, int with_dirty)
     if (!with_dirty) {
         free(qxl_dirty_rects);
     }
+    for (i = 0 ; i < num_dirty_rects; ++i) {
+        if (qxl_dirty_rects[i].top == 0 &&
+            qxl_dirty_rects[i].bottom == 0 &&
+            qxl_dirty_rects[i].left == 0 &&
+            qxl_dirty_rects[i].right == 0) {
+            break;
+        }
+        red_printf_debug(3, "dirty %d: %d %d %d %d", i,
+                qxl_dirty_rects[i].top,
+                qxl_dirty_rects[i].bottom,
+                qxl_dirty_rects[i].left,
+                qxl_dirty_rects[i].right);
+    }
 }
 
 static inline void handle_dev_update(RedWorker *worker)
-- 
1.7.7



More information about the Spice-devel mailing list