[Spice-devel] [PATCH v2] server: add async io support
Alon Levy
alevy at redhat.com
Thu Jul 7 00:30:20 PDT 2011
On Thu, Jul 07, 2011 at 09:16:33AM +0300, Yonit Halperin wrote:
> On 07/06/2011 08:37 PM, 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.
> >
> >Added api:
> >
> >QXLWorker:
> > update_area_async
> > add_memslot_async
> > destroy_surfaces_async
> > destroy_primary_surface_async
> > create_primary_surface_async
> > destroy_surface_wait_async
> > oom_async
> >
> >QXLInterface:
> > async_complete
> >---
> > server/red_dispatcher.c | 179 ++++++++++++++++++++++++++++++++++++++---------
> > server/red_parse_qxl.c | 2 +-
> > server/red_parse_qxl.h | 2 +-
> > server/red_worker.c | 80 ++++++++++++++-------
> > server/red_worker.h | 8 ++
> > server/spice.h | 12 +++
> > 6 files changed, 221 insertions(+), 62 deletions(-)
> >
> >diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
> >index 56446ab..74c7af2 100644
> >--- a/server/red_dispatcher.c
> >+++ b/server/red_dispatcher.c
> >@@ -209,38 +209,49 @@ static void update_client_mouse_allowed(void)
> > }
> > }
> >
> >-static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
> >+static void qxl_worker_update_area_helper(QXLWorker *qxl_worker, uint32_t surface_id,
> > QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
> >- uint32_t num_dirty_rects, uint32_t clear_dirty_region)
> >+ uint32_t num_dirty_rects, uint32_t clear_dirty_region,
> >+ int async)
> > {
> > 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);
> >+ RedWorkerMessage message;
> >
> >+ if (async) {
> >+ message = RED_WORKER_MESSAGE_UPDATE_ASYNC;
> >+ } else {
> >+ message = RED_WORKER_MESSAGE_UPDATE;
> >+ }
> > 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));
> >+ if (async) {
> >+ return;
> >+ }
>
> Hi,
> I find it problematic to decouple the qxl operations upon QXL_IO and
> the worker operations. For example: upon destroy_surfaces, the qxl
> resets the tracked guest commands. However, since destroy_surfaces
> is asynced, the worker might read commands from the ring before
> handling destroy surfaces, and then the qxl guest commands will be
> modified.
> I suggest a partial decoupling: on async io, the dispatcher will
> still wait for RED_WORKER_MESSAGE_READY, but the server will set it
> immediately when it receives the async message.
>
ok, I guess I see two solutions:
1. doing a stop on async, and a start on async_complete (a little heavy handed)
2. use the remembered io and do the "after completion" part in it, not on the io
call, so from async_complete.
I'll do 2.
> > 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 void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
> >+ QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
> >+ uint32_t num_dirty_rects, uint32_t clear_dirty_region)
> >+{
> >+ qxl_worker_update_area_helper(qxl_worker, surface_id, qxl_area, qxl_dirty_rects, num_dirty_rects,
> >+ clear_dirty_region, 0);
> >+}
> >
> >- free(dirty_rects);
> >- free(area);
> >+static void qxl_worker_update_area_async(QXLWorker *qxl_worker, uint32_t surface_id,
> >+ QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
> >+ uint32_t num_dirty_rects, uint32_t clear_dirty_region)
> >+{
> >+ qxl_worker_update_area_helper(qxl_worker, surface_id, qxl_area, qxl_dirty_rects, num_dirty_rects,
> >+ clear_dirty_region, 1);
> > }
> >
> >+
> > static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot)
> > {
> > RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
> >@@ -252,6 +263,15 @@ 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)
> >+{
> >+ RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
> >+ RedWorkerMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC;
> >+
> >+ write_message(dispatcher->channel,&message);
> >+ 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 +292,34 @@ 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)
> > {
> > RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
> >- RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
> >+ RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC;
> >+
> >+ write_message(dispatcher->channel,&message);
> >+}
> >+
> >+static void qxl_worker_destroy_primary_surface_helper(QXLWorker *qxl_worker, uint32_t surface_id,
> >+ int async)
> >+{
> >+ RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
> >+ RedWorkerMessage message;
> >+
> >+ if (async) {
> >+ message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC;
> >+ } else {
> >+ message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
> >+ }
> >
> > 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);
> >+ if (!async) {
> >+ read_message(dispatcher->channel,&message);
> >+ ASSERT(message == RED_WORKER_MESSAGE_READY);
> >+ }
> >
> >+ /* in async case this is set before primary is destroyed in worker */
> > dispatcher->x_res = 0;
> > dispatcher->y_res = 0;
> > dispatcher->use_hardware_cursor = FALSE;
> >@@ -290,11 +328,27 @@ 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(QXLWorker *qxl_worker, uint32_t surface_id)
> >+{
> >+ qxl_worker_destroy_primary_surface_helper(qxl_worker, surface_id, 0);
> >+}
> >+
> >+static void qxl_worker_destroy_primary_surface_async(QXLWorker *qxl_worker, uint32_t surface_id)
> >+{
> >+ qxl_worker_destroy_primary_surface_helper(qxl_worker, surface_id, 1);
> >+}
> >+
> >+static void qxl_worker_create_primary_surface_helper(QXLWorker *qxl_worker, uint32_t surface_id,
> >+ QXLDevSurfaceCreate *surface, int async)
> > {
> > RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
> >- RedWorkerMessage message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
> >+ RedWorkerMessage message;
> >+
> >+ if (async) {
> >+ message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC;
> >+ } else {
> >+ message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
> >+ }
> >
> > dispatcher->x_res = surface->width;
> > dispatcher->y_res = surface->height;
> >@@ -304,12 +358,26 @@ static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id
> > write_message(dispatcher->channel,&message);
> > 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);
> >+ }
> >
> > 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);
> >+}
> >+
> >+static void qxl_worker_create_primary_surface_async(QXLWorker *qxl_worker, uint32_t surface_id,
> >+ QXLDevSurfaceCreate *surface)
> >+{
> >+ qxl_worker_create_primary_surface_helper(qxl_worker, surface_id, surface, 1);
> >+}
> >+
> > static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
> > {
> > RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
> >@@ -330,17 +398,37 @@ 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)
> > {
> > RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
> >- RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
> >+ RedWorkerMessage message;
> >+
> >+ if (async ) {
> >+ message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC;
> >+ } else {
> >+ message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
> >+ }
> >
> > write_message(dispatcher->channel,&message);
> > 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);
> >+}
> >+
> >+static void qxl_worker_destroy_surface_wait_async(QXLWorker *qxl_worker, uint32_t surface_id)
> >+{
> >+ qxl_worker_destroy_surface_wait_helper(qxl_worker, surface_id, 1);
> >+}
> >+
> > static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
> > {
> > RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
> >@@ -360,16 +448,32 @@ static void qxl_worker_wakeup(QXLWorker *qxl_worker)
> > }
> > }
> >
> >-static void qxl_worker_oom(QXLWorker *qxl_worker)
> >+static void qxl_worker_oom_helper(QXLWorker *qxl_worker, int async)
> > {
> > RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
> >+ RedWorkerMessage message;
> >+
> > if (!test_bit(RED_WORKER_PENDING_OOM, dispatcher->pending)) {
> >- RedWorkerMessage message = RED_WORKER_MESSAGE_OOM;
> >+ if (async) {
> >+ message = RED_WORKER_MESSAGE_OOM_ASYNC;
> >+ } else {
> >+ message = RED_WORKER_MESSAGE_OOM;
> >+ }
> > set_bit(RED_WORKER_PENDING_OOM,&dispatcher->pending);
> > write_message(dispatcher->channel,&message);
> > }
> > }
> >
> >+static void qxl_worker_oom(QXLWorker *qxl_worker)
> >+{
> >+ qxl_worker_oom_helper(qxl_worker, 0);
> >+}
> >+
> >+static void qxl_worker_oom_async(QXLWorker *qxl_worker)
> >+{
> >+ qxl_worker_oom_helper(qxl_worker, 1);
> >+}
> >+
> > static void qxl_worker_start(QXLWorker *qxl_worker)
> > {
> > RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
> >@@ -530,14 +634,23 @@ 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;
> >+ dispatcher->base.oom_async = qxl_worker_oom_async;
> >+
> > qxl->st->qif->get_init_info(qxl,&init_info);
> >
> > init_data.memslot_id_bits = init_info.memslot_id_bits;
> >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 9a61e86..1480218 100644
> >--- a/server/red_worker.c
> >+++ b/server/red_worker.c
> >@@ -9417,20 +9417,24 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
> >
> > static inline void handle_dev_update(RedWorker *worker)
> > {
> >- RedWorkerMessage message;
> >- const SpiceRect *rect;
> >+ const QXLRect *qxl_rect;
> >+ SpiceRect *rect = spice_new0(SpiceRect, 1);
> >+ 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);
> >@@ -9444,15 +9448,17 @@ 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));
> >@@ -9460,9 +9466,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)
> >@@ -9498,7 +9501,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));
> >@@ -9510,9 +9512,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)
> >@@ -9540,7 +9539,6 @@ static inline void red_cursor_reset(RedWorker *worker)
> > static inline void handle_dev_destroy_surfaces(RedWorker *worker)
> > {
> > int i;
> >- RedWorkerMessage message;
> > red_printf("");
> > flush_all_qxl_commands(worker);
> > //to handle better
> >@@ -9563,14 +9561,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;
> >@@ -9600,14 +9594,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));
> >@@ -9623,9 +9613,6 @@ 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_input(EventListener *listener, uint32_t events)
> >@@ -9635,10 +9622,36 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> > RedChannel *cursor_red_channel =&worker->cursor_channel->common.base;
> > RedChannel *display_red_channel =&worker->display_channel->common.base;
> > int ring_is_empty;
> >+ int async = 0;
> >+ int write_ready = 0;
> >
> > 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:
> >+ case RED_WORKER_MESSAGE_OOM_ASYNC:
> >+ async = 1;
> >+ 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:
> > case RED_WORKER_MESSAGE_UPDATE:
> > handle_dev_update(worker);
> > break;
> >@@ -9646,6 +9659,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> > clear_bit(RED_WORKER_PENDING_WAKEUP, worker->pending);
> > stat_inc_counter(worker->wakeup_counter, 1);
> > break;
> >+ case RED_WORKER_MESSAGE_OOM_ASYNC:
> > case RED_WORKER_MESSAGE_OOM:
> > ASSERT(worker->running);
> > while (red_process_commands(worker, MAX_PIPE_SIZE,&ring_is_empty)) {
> >@@ -9670,15 +9684,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;
> >@@ -9805,6 +9823,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;
> >@@ -9850,6 +9869,13 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
> > default:
> > red_error("message error");
> > }
> >+ if (async) {
> >+ worker->qxl->st->qif->async_complete(worker->qxl);
> >+ }
> >+ if (write_ready) {
> >+ message = RED_WORKER_MESSAGE_READY;
> >+ write_message(worker->channel,&message);
> >+ }
> > }
> >
> > static void handle_dev_free(EventListener *ctx)
> >diff --git a/server/red_worker.h b/server/red_worker.h
> >index b4e2ed2..9ed7156 100644
> >--- a/server/red_worker.h
> >+++ b/server/red_worker.h
> >@@ -70,6 +70,14 @@ 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,
> >+ RED_WORKER_MESSAGE_OOM_ASYNC,
> > };
> >
> > typedef uint32_t RedWorkerMessage;
> >diff --git a/server/spice.h b/server/spice.h
> >index f64ff41..f0d5685 100644
> >--- a/server/spice.h
> >+++ b/server/spice.h
> >@@ -122,6 +122,17 @@ 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, struct QXLRect *dirty_rects,
> >+ uint32_t num_dirty_rects, uint32_t clear_dirty_region);
> >+ void (*add_memslot_async)(QXLWorker *worker, QXLDevMemSlot *slot);
> >+ void (*destroy_surfaces_async)(QXLWorker *worker);
> >+ void (*destroy_primary_surface_async)(QXLWorker *worker, uint32_t surface_id);
> >+ void (*create_primary_surface_async)(QXLWorker *worker, uint32_t surface_id,
> >+ QXLDevSurfaceCreate *surface);
> >+ void (*destroy_surface_wait_async)(QXLWorker *worker, uint32_t surface_id);
> >+ void (*oom_async)(QXLWorker *worker);
> > };
> >
> > typedef struct QXLDrawArea {
> >@@ -192,6 +203,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);
> > };
> >
> > struct QXLInstance {
>
More information about the Spice-devel
mailing list