[Spice-devel] [PATCH v5 4/9] server: add async io support
Yonit Halperin
yhalperi at redhat.com
Tue Jul 19 03:12:26 PDT 2011
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 {
More information about the Spice-devel
mailing list