[Spice-devel] [RFC 3/3] server/red_worker: reuse dispatcher
Yonit Halperin
yhalperi at redhat.com
Wed Nov 2 09:00:46 PDT 2011
On 11/01/2011 10:10 AM, Alon Levy wrote:
> This patch reuses Dispatcher in RedDispatcher. It adds two helpers
> to red_worker to keep RedWorker opaque to the outside. The dispatcher is
> abused in three places that use the underlying socket directly:
> once sending a READY after red_init completes
> once for each channel creation, replying with the RedChannel instance
> for cursor and display.
>
exploit this opportunity to rename red_dispatcher? ->worker_dispatcher?
display_dispatcher?
> Code is being added, not removed.
>
> Readability?
wrote a script to review the patch :)
> ---
> server/red_dispatcher.c | 585 +++++++++++++++++++++++++++------------
> server/red_dispatcher.h | 182 ++++++++++++
> server/red_worker.c | 716 +++++++++++++++++++++++++----------------------
> server/red_worker.h | 2 +
> 4 files changed, 979 insertions(+), 506 deletions(-)
>
> diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
> index 7a0033f..4680b50 100644
> --- a/server/red_dispatcher.c
> +++ b/server/red_dispatcher.c
> @@ -37,6 +37,7 @@
> #include "reds_gl_canvas.h"
> #endif // USE_OPENGL
> #include "reds.h"
> +#include "dispatcher.h"
> #include "red_dispatcher.h"
> #include "red_parse_qxl.h"
>
> @@ -53,7 +54,7 @@ struct AsyncCommand {
> struct RedDispatcher {
> QXLWorker base;
> QXLInstance *qxl;
> - int channel;
> + Dispatcher dispatcher;
> pthread_t worker_thread;
> uint32_t pending;
> int primary_active;
> @@ -83,24 +84,196 @@ extern spice_wan_compression_t zlib_glz_state;
>
> static RedDispatcher *dispatchers = NULL;
>
> +static void register_callbacks(RedDispatcher *dispatcher)
> +{
> + dispatcher_register_handler(&dispatcher->dispatcher,
> + RED_WORKER_MESSAGE_DISPLAY_CONNECT,
> + handle_dev_display_connect,
> + sizeof(RedWorkerMessageDisplayConnect),
> + 0);
> + dispatcher_register_handler(&dispatcher->dispatcher,
> + RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
> + handle_dev_display_disconnect,
> + sizeof(RedWorkerMessageDisplayDisconnect),
> + 1);
> + dispatcher_register_handler(&dispatcher->dispatcher,
> + RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
> + handle_dev_display_migrate,
> + sizeof(RedWorkerMessageDisplayMigrate),
> + 0);
<snip>
.
.
.
> + dispatcher_register_handler(&dispatcher->dispatcher,
> + RED_WORKER_MESSAGE_RESET_MEMSLOTS,
> + handle_dev_reset_memslots,
> + sizeof(RedWorkerMessageResetMemslots),
> + 0);
> +}
> +
What do you think about moving the registering the cbs to red_worker?
Then you will not need to add all the cbs prototype to red_dispatcher.h
(but you will need to expose Dispatcher to red_worker)
> static void red_dispatcher_set_display_peer(RedChannel *channel, RedClient *client,
> RedsStream *stream, int migration,
> int num_common_caps, uint32_t *common_caps, int num_caps,
> uint32_t *caps)
> {
> + RedWorkerMessageDisplayConnect payload;
> RedDispatcher *dispatcher;
>
> red_printf("");
> dispatcher = (RedDispatcher *)channel->data;
> - RedWorkerMessage message = RED_WORKER_MESSAGE_DISPLAY_CONNECT;
> - write_message(dispatcher->channel,&message);
> - send_data(dispatcher->channel,&client, sizeof(RedClient *));
> - send_data(dispatcher->channel,&stream, sizeof(RedsStream *));
> - send_data(dispatcher->channel,&migration, sizeof(int));
> + payload.client = client;
> + payload.stream = stream;
> + payload.migration = migration;
> + dispatcher_send_message(&dispatcher->dispatcher,
> + RED_WORKER_MESSAGE_DISPLAY_CONNECT,
> +&payload);
> }
>
<snip>
> diff --git a/server/red_worker.c b/server/red_worker.c
> index 00efc05..6e5a238 100644
> --- a/server/red_worker.c
> +++ b/server/red_worker.c
> @@ -866,8 +866,8 @@ typedef struct RedWorker {
> CursorChannel *cursor_channel;
> QXLInstance *qxl;
> RedDispatcher *dispatcher;
> - int id;
> int channel;
> + int id;
> int running;
> uint32_t *pending;
> int epoll;
> @@ -10102,21 +10102,19 @@ static void surface_dirty_region_to_rects(RedSurface *surface,
> free(dirty_rects);
> }
>
> -static inline void handle_dev_update_async(RedWorker *worker)
> +void handle_dev_update_async(void *opaque, void *payload)
> {
> - QXLRect qxl_rect;
> + RedWorker *worker = opaque;
> + RedWorkerMessageUpdateAsync *msg = payload;
> SpiceRect rect;
> - uint32_t surface_id;
> - uint32_t clear_dirty_region;
> QXLRect *qxl_dirty_rects;
> uint32_t num_dirty_rects;
> RedSurface *surface;
> + uint32_t surface_id = msg->surface_id;
> + QXLRect qxl_area = msg->qxl_area;
> + uint32_t clear_dirty_region = msg->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);
> + red_get_rect_ptr(&rect,&qxl_area);
> flush_display_commands(worker);
>
> ASSERT(worker->running);
> @@ -10124,12 +10122,12 @@ static inline void handle_dev_update_async(RedWorker *worker)
> validate_surface(worker, surface_id);
> red_update_area(worker,&rect, surface_id);
> if (!worker->qxl->st->qif->update_area_complete) {
> - return;
> + goto complete;
> }
> surface =&worker->surfaces[surface_id];
> num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
> if (num_dirty_rects == 0) {
> - return;
> + goto complete;
> }
> qxl_dirty_rects = spice_new0(QXLRect, num_dirty_rects);
> surface_dirty_region_to_rects(surface, qxl_dirty_rects, num_dirty_rects,
> @@ -10137,26 +10135,25 @@ static inline void handle_dev_update_async(RedWorker *worker)
> worker->qxl->st->qif->update_area_complete(worker->qxl, surface_id,
> qxl_dirty_rects, num_dirty_rects);
> free(qxl_dirty_rects);
> +
> +complete:
> + red_dispatcher_async_complete(worker->dispatcher, msg->cmd);
You can register only one callback to all the async messages, and then
handle each one differently, but call red_dispatcher_async_complete for
all of them.
Thanks,
Yonit.
More information about the Spice-devel
mailing list