[Spice-devel] [RFC 1/3] server/red_dispatcher: support concurrent asyncs
Alon Levy
alevy at redhat.com
Wed Nov 2 08:02:15 PDT 2011
On Wed, Nov 02, 2011 at 02:38:19PM +0200, Yonit Halperin wrote:
> Hi,
>
> One comment bellow. Besides that, Ack.
>
> On 11/01/2011 10:10 AM, Alon Levy wrote:
> >This is part of the dispatcher update, extracting the dispatcher routine
> >from red_dispatcher and main_dispatcher into dispatcher.
> >
> >Supporting multiple async operations will make it natural to support
> >async monitor commands and async guest io requests that could overlap in
> >time.
> >
> >Related bug: https://bugs.freedesktop.org/show_bug.cgi?id=41622
> >---
> > server/red_dispatcher.c | 138 ++++++++++++++++++++++++++--------------------
> > server/red_dispatcher.h | 3 +-
> > server/red_worker.c | 6 +-
> > 3 files changed, 83 insertions(+), 64 deletions(-)
> >
> >diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
> >index 721c79c..7a0033f 100644
> >--- a/server/red_dispatcher.c
> >+++ b/server/red_dispatcher.c
> >@@ -26,6 +26,7 @@
> > #include<pthread.h>
> > #include<sys/socket.h>
> > #include<signal.h>
> >+#include<inttypes.h>
> >
> > #include<spice/qxl_dev.h>
> > #include "spice.h"
> >@@ -43,6 +44,12 @@ static int num_active_workers = 0;
> >
> > //volatile
> >
> >+struct AsyncCommand {
> >+ AsyncCommand *next;
> >+ RedWorkerMessage message;
> >+ uint64_t cookie;
> >+};
> >+
> I find myself automatically using "*next" when I need a linked list
> in spice-server as well. But, I prefer using ring.h instead of
> mainting the linked list (as simple as it is); you will also be able
> to lose the code that removes the command from the list, in the
> async_complete_cb.
>
>
will do.
> > 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;
> > };
> >@@ -145,7 +152,7 @@ static void red_dispatcher_disconnect_cursor_peer(RedChannelClient *rcc)
> > RedDispatcher *dispatcher;
> >
> > if (!rcc->channel) {
> >- return;
> >+ return;
> > }
> >
> > dispatcher = (RedDispatcher *)rcc->channel->data;
> >@@ -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("error: async clash. second async ignored");
> >- 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 message;
> >+ return async_command;
> >+}
> >+
> >+static AsyncCommand *red_dispatcher_async_start(RedDispatcher *dispatcher,
> >+ RedWorkerMessage message,
> >+ uint64_t cookie)
> >+{
> >+ return push_async_command(dispatcher, message, cookie);
> > }
> >
> > static void red_dispatcher_update_area_async(RedDispatcher *dispatcher,
> >@@ -283,15 +298,11 @@ static void red_dispatcher_update_area_async(RedDispatcher *dispatcher,
> > uint32_t clear_dirty_region,
> > uint64_t cookie)
> > {
> >- RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
> >- RED_WORKER_MESSAGE_UPDATE_ASYNC);
> >-
> >- if (message == RED_WORKER_MESSAGE_NOP) {
> >- return;
> >- }
> >+ RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE_ASYNC;
> >+ AsyncCommand *cmd = red_dispatcher_async_start(dispatcher, message, cookie);
> >
> > write_message(dispatcher->channel,&message);
> >- send_data(dispatcher->channel,&cookie, sizeof(cookie));
> >+ send_data(dispatcher->channel, cmd, sizeof(cmd));
> > 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));
> >@@ -322,14 +333,11 @@ 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);
> >+ RedWorkerMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC;
> >+ AsyncCommand *cmd = red_dispatcher_async_start(dispatcher, message, cookie);
> >
> >- if (message == RED_WORKER_MESSAGE_NOP) {
> >- return;
> >- }
> > write_message(dispatcher->channel,&message);
> >- send_data(dispatcher->channel,&cookie, sizeof(cookie));
> >+ send_data(dispatcher->channel,&cmd, sizeof(cmd));
> > send_data(dispatcher->channel, mem_slot, sizeof(QXLDevMemSlot));
> > }
> >
> >@@ -363,14 +371,11 @@ 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);
> >+ RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC;
> >+ AsyncCommand *cmd = red_dispatcher_async_start(dispatcher, message, cookie);
> >
> >- if (message == RED_WORKER_MESSAGE_NOP) {
> >- return;
> >- }
> > write_message(dispatcher->channel,&message);
> >- send_data(dispatcher->channel,&cookie, sizeof(cookie));
> >+ send_data(dispatcher->channel,&cmd, sizeof(cmd));
> > }
> >
> > static void red_dispatcher_destroy_primary_surface_complete(RedDispatcher *dispatcher)
> >@@ -388,20 +393,18 @@ red_dispatcher_destroy_primary_surface(RedDispatcher *dispatcher,
> > uint32_t surface_id, int async, uint64_t cookie)
> > {
> > RedWorkerMessage message;
> >+ AsyncCommand *cmd;
> >
> > if (async) {
> >- message = red_dispatcher_async_start(dispatcher,
> >- RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC);
> >- if (message == RED_WORKER_MESSAGE_NOP) {
> >- return;
> >- }
> >+ message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC;
> >+ cmd = red_dispatcher_async_start(dispatcher, message, cookie);
> > } 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,&cmd, sizeof(cmd));
> > }
> > send_data(dispatcher->channel,&surface_id, sizeof(uint32_t));
> > if (!async) {
> >@@ -434,13 +437,11 @@ red_dispatcher_create_primary_surface(RedDispatcher *dispatcher, uint32_t surfac
> > QXLDevSurfaceCreate *surface, int async, uint64_t cookie)
> > {
> > RedWorkerMessage message;
> >+ AsyncCommand *cmd;
> >
> > if (async) {
> >- message = red_dispatcher_async_start(dispatcher,
> >- RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC);
> >- if (message == RED_WORKER_MESSAGE_NOP) {
> >- return;
> >- }
> >+ message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC;
> >+ cmd = red_dispatcher_async_start(dispatcher, message, cookie);
> > } else {
> > message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
> > }
> >@@ -448,7 +449,7 @@ red_dispatcher_create_primary_surface(RedDispatcher *dispatcher, uint32_t surfac
> >
> > write_message(dispatcher->channel,&message);
> > if (async) {
> >- send_data(dispatcher->channel,&cookie, sizeof(cookie));
> >+ send_data(dispatcher->channel,&cmd, sizeof(cmd));
> > }
> > send_data(dispatcher->channel,&surface_id, sizeof(uint32_t));
> > send_data(dispatcher->channel, surface, sizeof(QXLDevSurfaceCreate));
> >@@ -497,20 +498,18 @@ static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint3
> > int async, uint64_t cookie)
> > {
> > RedWorkerMessage message;
> >+ AsyncCommand *cmd;
> >
> > if (async ) {
> >- message = red_dispatcher_async_start(dispatcher,
> >- RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC);
> >- if (message == RED_WORKER_MESSAGE_NOP) {
> >- return;
> >- }
> >+ message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC;
> >+ cmd = red_dispatcher_async_start(dispatcher, message, cookie);
> > } 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,&cmd, sizeof(cmd));
> > }
> > send_data(dispatcher->channel,&surface_id, sizeof(uint32_t));
> > if (async) {
> >@@ -579,14 +578,11 @@ 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);
> >+ RedWorkerMessage message = RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC;
> >+ AsyncCommand *cmd = red_dispatcher_async_start(dispatcher, message, cookie);
> >
> >- if (message == RED_WORKER_MESSAGE_NOP) {
> >- return;
> >- }
> > write_message(dispatcher->channel,&message);
> >- send_data(dispatcher->channel,&cookie, sizeof(cookie));
> >+ send_data(dispatcher->channel,&cmd, sizeof(cmd));
> > }
> >
> > static void red_dispatcher_stop(RedDispatcher *dispatcher)
> >@@ -842,10 +838,31 @@ void spice_qxl_flush_surfaces_async(QXLInstance *instance, uint64_t cookie)
> > red_dispatcher_flush_surfaces_async(instance->st->dispatcher, cookie);
> > }
> >
> >-void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t cookie)
> >+void red_dispatcher_async_complete(struct RedDispatcher *dispatcher,
> >+ AsyncCommand *async_command)
> > {
> >+ AsyncCommand *cmd;
> >+ AsyncCommand *prev;
> >+
> > pthread_mutex_lock(&dispatcher->async_lock);
> >- switch (dispatcher->async_message) {
> >+ cmd = dispatcher->async_commands;
> >+ prev = NULL;
> >+ while (cmd&& async_command != cmd) {
> >+ prev = async_command;
> >+ cmd = cmd->next;
> >+ };
> >+ if (!cmd) {
> >+ WARN("unknown command");
> >+ goto end;
> >+ }
> >+ red_printf_debug(2, "%s: cookie %" PRId64, __func__, async_command->cookie);
> >+ if (!prev) {
> >+ red_printf_debug(2, "%s: no more async commands", __func__);
> >+ dispatcher->async_commands = NULL;
> >+ } else {
> >+ prev->next = async_command->next;
> >+ }
> >+ switch (async_command->message) {
> > case RED_WORKER_MESSAGE_UPDATE_ASYNC:
> > break;
> > case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
> >@@ -863,11 +880,13 @@ 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);
> >+ dispatcher->qxl->st->qif->async_complete(dispatcher->qxl,
> >+ async_command->cookie);
> > }
> >
> > static RedChannel *red_dispatcher_display_channel_create(RedDispatcher *dispatcher)
> >@@ -929,7 +948,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_dispatcher.h b/server/red_dispatcher.h
> >index 144a40e..c2582f4 100644
> >--- a/server/red_dispatcher.h
> >+++ b/server/red_dispatcher.h
> >@@ -19,6 +19,7 @@
> > #define _H_RED_DISPATCHER
> >
> > struct RedChannelClient;
> >+typedef struct AsyncCommand AsyncCommand;
> >
> > struct RedDispatcher *red_dispatcher_init(QXLInstance *qxl);
> >
> >@@ -30,6 +31,6 @@ 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);
> >+void red_dispatcher_async_complete(struct RedDispatcher *, AsyncCommand *);
> >
> > #endif
> >diff --git a/server/red_worker.c b/server/red_worker.c
> >index 6756af9..00efc05 100644
> >--- a/server/red_worker.c
> >+++ b/server/red_worker.c
> >@@ -10382,7 +10382,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> > int ring_is_empty;
> > int call_async_complete = 0;
> > int write_ready = 0;
> >- uint64_t cookie;
> >+ AsyncCommand *cmd;
> >
> > read_message(worker->channel,&message);
> >
> >@@ -10397,7 +10397,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> > case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
> > case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
> > call_async_complete = 1;
> >- receive_data(worker->channel,&cookie, sizeof(cookie));
> >+ receive_data(worker->channel,&cmd, sizeof(cmd));
> > break;
> > case RED_WORKER_MESSAGE_UPDATE:
> > case RED_WORKER_MESSAGE_ADD_MEMSLOT:
> >@@ -10666,7 +10666,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> > red_error("message error");
> > }
> > if (call_async_complete) {
> >- red_dispatcher_async_complete(worker->dispatcher, cookie);
> >+ red_dispatcher_async_complete(worker->dispatcher, cmd);
> > }
> > if (write_ready) {
> > message = RED_WORKER_MESSAGE_READY;
>
More information about the Spice-devel
mailing list