[Spice-devel] [RFC 1/3] server/red_dispatcher: support concurrent asyncs
Alon Levy
alevy at redhat.com
Tue Nov 1 01:10:01 PDT 2011
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;
+};
+
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;
--
1.7.7
More information about the Spice-devel
mailing list