diff options
author | Alon Levy <alevy@redhat.com> | 2011-07-06 02:12:19 +0200 |
---|---|---|
committer | Alon Levy <alevy@redhat.com> | 2011-07-20 16:00:19 +0300 |
commit | 096f49afbf4e83ccee80f58479b3ff05bd355660 (patch) | |
tree | 7f8df1ea290e3ed23b0a34a82ae0f22aaf8cbc38 /server/red_dispatcher.c | |
parent | 4db8f5efdda91acf3b94c6c104d48438f6f4e85d (diff) | |
download | spice-096f49afbf4e83ccee80f58479b3ff05bd355660.tar.gz spice-096f49afbf4e83ccee80f58479b3ff05bd355660.tar.xz spice-096f49afbf4e83ccee80f58479b3ff05bd355660.zip |
server: add async io support
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
Diffstat (limited to 'server/red_dispatcher.c')
-rw-r--r-- | server/red_dispatcher.c | 255 |
1 files changed, 215 insertions, 40 deletions
diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c index aa1990e0..7f3efe87 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 { @@ -214,30 +216,49 @@ static void red_dispatcher_update_area(RedDispatcher *dispatcher, uint32_t surfa uint32_t num_dirty_rects, uint32_t clear_dirty_region) { 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); +} - 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 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; +} + +static void red_dispatcher_update_area_async(RedDispatcher *dispatcher, + uint32_t surface_id, + QXLRect *qxl_area, + uint32_t clear_dirty_region, + uint64_t cookie) +{ + RedWorkerMessage message = red_dispatcher_async_start(dispatcher, + RED_WORKER_MESSAGE_UPDATE_ASYNC); - free(dirty_rects); - free(area); + if (message == RED_WORKER_MESSAGE_NOP) { + return; + } + + 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_update_area(QXLWorker *qxl_worker, uint32_t surface_id, @@ -263,6 +284,19 @@ static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slo red_dispatcher_add_memslot((RedDispatcher*)qxl_worker, mem_slot); } +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); + + 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 red_dispatcher_del_memslot(RedDispatcher *dispatcher, uint32_t slot_group_id, uint32_t slot_id) { RedWorkerMessage message = RED_WORKER_MESSAGE_DEL_MEMSLOT; @@ -291,15 +325,20 @@ static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker) red_dispatcher_destroy_surfaces((RedDispatcher*)qxl_worker); } -static void red_dispatcher_destroy_primary(RedDispatcher *dispatcher, uint32_t surface_id) +static void red_dispatcher_destroy_surfaces_async(RedDispatcher *dispatcher, uint64_t cookie) { - 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; @@ -308,34 +347,86 @@ static void red_dispatcher_destroy_primary(RedDispatcher *dispatcher, uint32_t s update_client_mouse_allowed(); } -static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_id) +static void +red_dispatcher_destroy_primary_surface(RedDispatcher *dispatcher, + uint32_t surface_id, int async, uint64_t cookie) { - red_dispatcher_destroy_primary((RedDispatcher*)qxl_worker, surface_id); + 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 red_dispatcher_create_primary(RedDispatcher *dispatcher, uint32_t surface_id, - QXLDevSurfaceCreate *surface) +static void qxl_worker_destroy_primary_surface(QXLWorker *qxl_worker, uint32_t surface_id) +{ + red_dispatcher_destroy_primary_surface((RedDispatcher*)qxl_worker, surface_id, 0, 0); +} + +static void red_dispatcher_create_primary_surface_complete(RedDispatcher *dispatcher) { - RedWorkerMessage message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE; + 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 +red_dispatcher_create_primary_surface(RedDispatcher *dispatcher, uint32_t surface_id, + QXLDevSurfaceCreate *surface, int async, uint64_t cookie) +{ + 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); - - update_client_mouse_allowed(); + if (!async) { + read_message(dispatcher->channel, &message); + ASSERT(message == RED_WORKER_MESSAGE_READY); + red_dispatcher_create_primary_surface_complete(dispatcher); + } } -static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id, +static void qxl_worker_create_primary_surface(QXLWorker *qxl_worker, uint32_t surface_id, QXLDevSurfaceCreate *surface) { - red_dispatcher_create_primary((RedDispatcher*)qxl_worker, surface_id, surface); + red_dispatcher_create_primary_surface((RedDispatcher*)qxl_worker, surface_id, surface, 0, 0); } static void red_dispatcher_reset_image_cache(RedDispatcher *dispatcher) @@ -366,19 +457,36 @@ static void qxl_worker_reset_cursor(QXLWorker *qxl_worker) red_dispatcher_reset_cursor((RedDispatcher*)qxl_worker); } -static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint32_t surface_id) +static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint32_t surface_id, + int async, uint64_t cookie) { - 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) { - red_dispatcher_destroy_surface_wait((RedDispatcher*)qxl_worker, surface_id); + red_dispatcher_destroy_surface_wait((RedDispatcher*)qxl_worker, surface_id, 0, 0); } static void red_dispatcher_reset_memslots(RedDispatcher *dispatcher) @@ -607,14 +715,14 @@ void spice_qxl_destroy_surfaces(QXLInstance *instance) SPICE_GNUC_VISIBLE void spice_qxl_destroy_primary_surface(QXLInstance *instance, uint32_t surface_id) { - red_dispatcher_destroy_primary(instance->st->dispatcher, surface_id); + red_dispatcher_destroy_primary_surface(instance->st->dispatcher, surface_id, 0, 0); } SPICE_GNUC_VISIBLE void spice_qxl_create_primary_surface(QXLInstance *instance, uint32_t surface_id, QXLDevSurfaceCreate *surface) { - red_dispatcher_create_primary(instance->st->dispatcher, surface_id, surface); + red_dispatcher_create_primary_surface(instance->st->dispatcher, surface_id, surface, 0, 0); } SPICE_GNUC_VISIBLE @@ -632,7 +740,7 @@ void spice_qxl_reset_cursor(QXLInstance *instance) SPICE_GNUC_VISIBLE void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t surface_id) { - red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id); + red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id, 0, 0); } SPICE_GNUC_VISIBLE @@ -641,6 +749,71 @@ void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt *ext, red_dispatcher_loadvm_commands(instance->st->dispatcher, ext, count); } +SPICE_GNUC_VISIBLE +void spice_qxl_update_area_async(QXLInstance *instance, uint32_t surface_id, QXLRect *qxl_area, + uint32_t clear_dirty_region, uint64_t cookie) +{ + red_dispatcher_update_area_async(instance->st->dispatcher, surface_id, qxl_area, + clear_dirty_region, cookie); +} + +SPICE_GNUC_VISIBLE +void spice_qxl_add_memslot_async(QXLInstance *instance, QXLDevMemSlot *slot, uint64_t cookie) +{ + red_dispatcher_add_memslot_async(instance->st->dispatcher, slot, cookie); +} + +SPICE_GNUC_VISIBLE +void spice_qxl_destroy_surfaces_async(QXLInstance *instance, uint64_t cookie) +{ + red_dispatcher_destroy_surfaces_async(instance->st->dispatcher, cookie); +} + +SPICE_GNUC_VISIBLE +void spice_qxl_destroy_primary_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie) +{ + red_dispatcher_destroy_primary_surface(instance->st->dispatcher, surface_id, 1, cookie); +} + +SPICE_GNUC_VISIBLE +void spice_qxl_create_primary_surface_async(QXLInstance *instance, uint32_t surface_id, + QXLDevSurfaceCreate *surface, uint64_t cookie) +{ + red_dispatcher_create_primary_surface(instance->st->dispatcher, surface_id, surface, 1, cookie); +} + +SPICE_GNUC_VISIBLE +void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie) +{ + red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id, 1, cookie); +} + +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; @@ -673,6 +846,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; @@ -689,8 +864,8 @@ 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; @@ -705,6 +880,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; @@ -745,4 +921,3 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl) dispatchers = dispatcher; return dispatcher; } - |