[Spice-devel] [PATCH 03/18] server/red_worker: introduce CommonChannel

Marc-André Lureau marcandre.lureau at gmail.com
Tue Feb 8 13:07:54 PST 2011


Argh, I just lost some time understanding the crash that happen at
free(evt_listener);... Please squash the patches 03 and 04, it makes
reviewing easier (and bisect as well)

This patch makes use of this "downcasting" idiom, which I am not fond of:

func (RedChannel *channel) {
     common = SPICE_CONTAINEROF(channel, CommonChannel, base);
}

Can we change the functions argument to take a CommonChannel: func
(CommonChannel *common) ?

A simple cast makes it clear that we are dealing with inherited
structure, resulting in the same pointer. We might argue that it's
more unsafe than using CONTAINEROF though..


On Mon, Feb 7, 2011 at 7:19 PM, Alon Levy <alevy at redhat.com> wrote:
> with everything (almost) not in red_channel's RedChannel
> ---
>  server/red_client_cache.h        |    2 +-
>  server/red_client_shared_cache.h |   20 +-
>  server/red_worker.c              |  363 ++++++++++++++++++++------------------
>  3 files changed, 204 insertions(+), 181 deletions(-)
>
> diff --git a/server/red_client_cache.h b/server/red_client_cache.h
> index 15c63d8..28f9955 100644
> --- a/server/red_client_cache.h
> +++ b/server/red_client_cache.h
> @@ -74,7 +74,7 @@ static void FUNC_NAME(remove)(CHANNEL *channel, CacheItem *item)
>     channel->VAR_NAME(available) += item->size;
>
>     red_pipe_item_init(&item->u.pipe_data, PIPE_ITEM_TYPE_INVAL_ONE);
> -    red_pipe_add_tail(&channel->base, &item->u.pipe_data); // for now
> +    red_pipe_add_tail(&channel->common.base, &item->u.pipe_data); // for now
>  }
>
>  static int FUNC_NAME(add)(CHANNEL *channel, uint64_t id, size_t size)
> diff --git a/server/red_client_shared_cache.h b/server/red_client_shared_cache.h
> index 716b812..4d50fe4 100644
> --- a/server/red_client_shared_cache.h
> +++ b/server/red_client_shared_cache.h
> @@ -48,9 +48,9 @@ static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, CHANNEL *channe
>         if (item->id == id) {
>             ring_remove(&item->lru_link);
>             ring_add(&cache->lru, &item->lru_link);
> -            ASSERT(channel->base.id < MAX_CACHE_CLIENTS)
> -            item->sync[channel->base.id] = serial;
> -            cache->sync[channel->base.id] = serial;
> +            ASSERT(channel->common.id < MAX_CACHE_CLIENTS)
> +            item->sync[channel->common.id] = serial;
> +            cache->sync[channel->common.id] = serial;
>             *lossy = item->lossy;
>             break;
>         }
> @@ -108,7 +108,7 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, C
>         NewCacheItem **now;
>
>         if (!(tail = (NewCacheItem *)ring_get_tail(&cache->lru)) ||
> -                                                   tail->sync[channel->base.id] == serial) {
> +                                                   tail->sync[channel->common.id] == serial) {
>             cache->available += size;
>             pthread_mutex_unlock(&cache->lock);
>             free(item);
> @@ -127,7 +127,7 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, C
>         ring_remove(&tail->lru_link);
>         cache->items--;
>         cache->available += tail->size;
> -        cache->sync[channel->base.id] = serial;
> +        cache->sync[channel->common.id] = serial;
>         display_channel_push_release(channel, SPICE_RES_TYPE_PIXMAP, tail->id, tail->sync);
>         free(tail);
>     }
> @@ -140,8 +140,8 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, C
>     item->size = size;
>     item->lossy = lossy;
>     memset(item->sync, 0, sizeof(item->sync));
> -    item->sync[channel->base.id] = serial;
> -    cache->sync[channel->base.id] = serial;
> +    item->sync[channel->common.id] = serial;
> +    cache->sync[channel->common.id] = serial;
>     pthread_mutex_unlock(&cache->lock);
>     return TRUE;
>  }
> @@ -177,13 +177,13 @@ static void FUNC_NAME(reset)(CACHE *cache, CHANNEL *channel, SpiceMsgWaitForChan
>     PRIVATE_FUNC_NAME(clear)(cache);
>
>     channel->CACH_GENERATION = ++cache->generation;
> -    cache->generation_initiator.client = channel->base.id;
> +    cache->generation_initiator.client = channel->common.id;
>     cache->generation_initiator.message = serial;
> -    cache->sync[channel->base.id] = serial;
> +    cache->sync[channel->common.id] = serial;
>
>     wait_count = 0;
>     for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
> -        if (cache->sync[i] && i != channel->base.id) {
> +        if (cache->sync[i] && i != channel->common.id) {
>             sync_data->wait_list[wait_count].channel_type = SPICE_CHANNEL_DISPLAY;
>             sync_data->wait_list[wait_count].channel_id = i;
>             sync_data->wait_list[wait_count++].message_serial = cache->sync[i];
> diff --git a/server/red_worker.c b/server/red_worker.c
> index 97f5e70..ba04a72 100644
> --- a/server/red_worker.c
> +++ b/server/red_worker.c
> @@ -352,10 +352,7 @@ typedef void (*release_item_proc)(RedChannel *channel, void *item);
>  typedef int (*handle_message_proc)(RedChannel *channel, size_t size, uint32_t type, void *message);
>
>  struct RedChannel {
> -    EventListener listener;
> -    uint32_t id;
>     spice_parse_channel_func_t parser;
> -    struct RedWorker *worker;
>     RedsStreamContext *peer;
>     int migrate;
>
> @@ -605,8 +602,16 @@ typedef struct GlzSharedDictionary {
>
>  #define NUM_SURFACES 10000
>
> +typedef struct CommonChannel {
> +    RedChannel base; // Must be the first thing
> +    EventListener listener;
> +    uint32_t id;
> +    struct RedWorker *worker;
> +} CommonChannel;
> +
> +
>  struct DisplayChannel {
> -    RedChannel base;
> +    CommonChannel common; // Must be the first thing
>
>     int expect_init;
>     int expect_migrate_mark;
> @@ -666,7 +671,7 @@ struct DisplayChannel {
>  };
>
>  typedef struct CursorChannel {
> -    RedChannel base;
> +    CommonChannel common; // Must be the first thing
>
>     CacheItem *cursor_cache[CURSOR_CACHE_HASH_SIZE];
>     Ring cursor_cache_lru;
> @@ -1003,7 +1008,7 @@ static void print_compress_stats(DisplayChannel *display_channel)
>                        display_channel->zlib_glz_stat.comp_size :
>                        display_channel->glz_stat.comp_size;
>
> -    red_printf("==> Compression stats for display %u", display_channel->base.id);
> +    red_printf("==> Compression stats for display %u", display_channel->common.id);
>     red_printf("Method   \t  count  \torig_size(MB)\tenc_size(MB)\tenc_time(s)");
>     red_printf("QUIC     \t%8d\t%13.2f\t%12.2f\t%12.2f",
>                display_channel->quic_stat.count,
> @@ -1260,7 +1265,7 @@ static inline void red_pipe_add_drawable(RedWorker *worker, Drawable *drawable)
>     red_handle_drawable_surfaces_client_synced(worker, drawable);
>
>     drawable->refs++;
> -    red_pipe_add(&worker->display_channel->base, &drawable->pipe_item);
> +    red_pipe_add(&worker->display_channel->common.base, &drawable->pipe_item);
>  }
>
>  static inline void red_pipe_add_drawable_to_tail(RedWorker *worker, Drawable *drawable)
> @@ -1269,7 +1274,7 @@ static inline void red_pipe_add_drawable_to_tail(RedWorker *worker, Drawable *dr
>         return;
>     }
>     drawable->refs++;
> -    red_pipe_add_tail(&worker->display_channel->base, &drawable->pipe_item);
> +    red_pipe_add_tail(&worker->display_channel->common.base, &drawable->pipe_item);
>  }
>
>  static inline void red_pipe_add_drawable_after(RedWorker *worker, Drawable *drawable,
> @@ -1284,7 +1289,7 @@ static inline void red_pipe_add_drawable_after(RedWorker *worker, Drawable *draw
>         return;
>     }
>     drawable->refs++;
> -    red_pipe_add_after(&worker->display_channel->base, &drawable->pipe_item, &pos_after->pipe_item);
> +    red_pipe_add_after(&worker->display_channel->common.base, &drawable->pipe_item, &pos_after->pipe_item);
>  }
>
>  static inline PipeItem *red_pipe_get_tail(RedWorker *worker)
> @@ -1293,7 +1298,7 @@ static inline PipeItem *red_pipe_get_tail(RedWorker *worker)
>         return NULL;
>     }
>
> -    return (PipeItem*)ring_get_tail(&worker->display_channel->base.pipe);
> +    return (PipeItem*)ring_get_tail(&worker->display_channel->common.base.pipe);
>  }
>
>  static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id);
> @@ -1301,7 +1306,7 @@ static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id);
>  static inline void red_pipe_remove_drawable(RedWorker *worker, Drawable *drawable)
>  {
>     if (ring_item_is_linked(&drawable->pipe_item.link)) {
> -        worker->display_channel->base.pipe_size--;
> +        worker->display_channel->common.base.pipe_size--;
>         ring_remove(&drawable->pipe_item.link);
>         release_drawable(worker, drawable);
>     }
> @@ -1313,7 +1318,7 @@ static inline void red_pipe_add_image_item(RedWorker *worker, ImageItem *item)
>         return;
>     }
>     item->refs++;
> -    red_pipe_add(&worker->display_channel->base, &item->link);
> +    red_pipe_add(&worker->display_channel->common.base, &item->link);
>  }
>
>  static inline void red_pipe_add_image_item_after(RedWorker *worker, ImageItem *item,
> @@ -1323,7 +1328,7 @@ static inline void red_pipe_add_image_item_after(RedWorker *worker, ImageItem *i
>         return;
>     }
>     item->refs++;
> -    red_pipe_add_after(&worker->display_channel->base, &item->link, pos);
> +    red_pipe_add_after(&worker->display_channel->common.base, &item->link, pos);
>  }
>
>  static inline uint64_t channel_message_serial(RedChannel *channel)
> @@ -1350,19 +1355,20 @@ static void release_upgrade_item(RedWorker* worker, UpgradeItem *item)
>  static void red_pipe_clear(RedChannel *channel)
>  {
>     PipeItem *item;
> +    CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
>
>     ASSERT(channel);
>     while ((item = (PipeItem *)ring_get_head(&channel->pipe))) {
>         ring_remove(&item->link);
>         switch (item->type) {
>         case PIPE_ITEM_TYPE_DRAW:
> -            release_drawable(channel->worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
> +            release_drawable(common->worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
>             break;
>         case PIPE_ITEM_TYPE_CURSOR:
> -            red_release_cursor(channel->worker, (CursorItem *)item);
> +            red_release_cursor(common->worker, (CursorItem *)item);
>             break;
>         case PIPE_ITEM_TYPE_UPGRADE:
> -            release_upgrade_item(channel->worker, (UpgradeItem *)item);
> +            release_upgrade_item(common->worker, (UpgradeItem *)item);
>             break;
>         case PIPE_ITEM_TYPE_PIXMAP_RESET:
>         case PIPE_ITEM_TYPE_PIXMAP_SYNC:
> @@ -1485,7 +1491,7 @@ static inline void red_destroy_surface_item(RedWorker *worker, uint32_t surface_
>
>     destroy = get_surface_destroy_item(surface_id);
>
> -    red_pipe_add(&worker->display_channel->base, &destroy->pipe_item);
> +    red_pipe_add(&worker->display_channel->common.base, &destroy->pipe_item);
>  }
>
>  static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id)
> @@ -1801,7 +1807,7 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface
>     /* removing the newest drawables that their destination is surface_id and
>        no other drawable depends on them */
>
> -    ring = &worker->display_channel->base.pipe;
> +    ring = &worker->display_channel->common.base.pipe;
>     item = (PipeItem *) ring;
>     while ((item = (PipeItem *)ring_next(ring, (RingItem *)item))) {
>         Drawable *drawable;
> @@ -1818,8 +1824,8 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface
>             PipeItem *tmp_item = item;
>             item = (PipeItem *)ring_prev(ring, (RingItem *)item);
>             ring_remove(&tmp_item->link);
> -            worker->display_channel->base.release_item(&worker->display_channel->base, tmp_item);
> -            worker->display_channel->base.pipe_size--;
> +            worker->display_channel->common.base.release_item(&worker->display_channel->common.base, tmp_item);
> +            worker->display_channel->common.base.pipe_size--;
>
>             if (!item) {
>                 item = (PipeItem *)ring;
> @@ -1844,7 +1850,7 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface
>     }
>
>     if (item) {
> -        red_wait_pipe_item_sent(&worker->display_channel->base, item);
> +        red_wait_pipe_item_sent(&worker->display_channel->common.base, item);
>     }
>  }
>
> @@ -2341,7 +2347,7 @@ static void red_stop_stream(RedWorker *worker, Stream *stream)
>         region_clear(&stream_agent->vis_region);
>         ASSERT(!pipe_item_is_linked(&stream_agent->destroy_item));
>         stream->refs++;
> -        red_pipe_add(&channel->base, &stream_agent->destroy_item);
> +        red_pipe_add(&channel->common.base, &stream_agent->destroy_item);
>     }
>     ring_remove(&stream->link);
>     red_release_stream(worker, stream);
> @@ -2481,7 +2487,7 @@ static inline void red_handle_streams_timout(RedWorker *worker)
>  static void red_display_release_stream(DisplayChannel *display, StreamAgent *agent)
>  {
>     ASSERT(agent->stream);
> -    red_release_stream(display->base.worker, agent->stream);
> +    red_release_stream(display->common.worker, agent->stream);
>  }
>
>  static inline Stream *red_alloc_stream(RedWorker *worker)
> @@ -2507,7 +2513,7 @@ static int get_bit_rate(int width, int height)
>
>  static void red_display_create_stream(DisplayChannel *display, Stream *stream)
>  {
> -    StreamAgent *agent = &display->stream_agents[stream - display->base.worker->streams_buf];
> +    StreamAgent *agent = &display->stream_agents[stream - display->common.worker->streams_buf];
>     stream->refs++;
>     ASSERT(region_is_empty(&agent->vis_region));
>     if (stream->current) {
> @@ -2519,7 +2525,7 @@ static void red_display_create_stream(DisplayChannel *display, Stream *stream)
>     agent->drops = 0;
>     agent->fps = MAX_FPS;
>     reset_rate(agent);
> -    red_pipe_add(&display->base, &agent->create_item);
> +    red_pipe_add(&display->common.base, &agent->create_item);
>  }
>
>  static void red_create_stream(RedWorker *worker, Drawable *drawable)
> @@ -2563,7 +2569,7 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable)
>
>  static void red_disply_start_streams(DisplayChannel *display_channel)
>  {
> -    Ring *ring = &display_channel->base.worker->streams;
> +    Ring *ring = &display_channel->common.worker->streams;
>     RingItem *item = ring;
>
>     while ((item = ring_next(ring, item))) {
> @@ -2577,7 +2583,7 @@ static void red_display_init_streams(DisplayChannel *display)
>     int i;
>     for (i = 0; i < NUM_STREAMS; i++) {
>         StreamAgent *agent = &display->stream_agents[i];
> -        agent->stream = &display->base.worker->streams_buf[i];
> +        agent->stream = &display->common.worker->streams_buf[i];
>         region_init(&agent->vis_region);
>         red_pipe_item_init(&agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
>         red_pipe_item_init(&agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
> @@ -4279,7 +4285,7 @@ void qxl_process_cursor(RedWorker *worker, RedCursorCmd *cursor_cmd, uint32_t gr
>
>     if (worker->cursor_channel && (worker->mouse_mode == SPICE_MOUSE_MODE_SERVER ||
>                                    cursor_cmd->type != QXL_CURSOR_MOVE || cursor_show)) {
> -        red_pipe_add(&worker->cursor_channel->base, &item->pipe_data);
> +        red_pipe_add(&worker->cursor_channel->common.base, &item->pipe_data);
>     } else {
>         red_release_cursor(worker, item);
>     }
> @@ -4300,7 +4306,7 @@ static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ri
>     int n = 0;
>
>     *ring_is_empty = FALSE;
> -    while (!worker->cursor_channel || worker->cursor_channel->base.pipe_size <= max_pipe_size) {
> +    while (!worker->cursor_channel || worker->cursor_channel->common.base.pipe_size <= max_pipe_size) {
>         if (!worker->qxl->st->qif->get_cursor_command(worker->qxl, &ext_cmd)) {
>             *ring_is_empty = TRUE;
>             if (worker->repoll_cursor_ring < CMD_RING_POLL_RETRIES) {
> @@ -4340,7 +4346,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
>     uint64_t start = red_now();
>
>     *ring_is_empty = FALSE;
> -    while (!worker->display_channel || worker->display_channel->base.pipe_size <= max_pipe_size) {
> +    while (!worker->display_channel || worker->display_channel->common.base.pipe_size <= max_pipe_size) {
>         if (!worker->qxl->st->qif->get_command(worker->qxl, &ext_cmd)) {
>             *ring_is_empty = TRUE;;
>             if (worker->repoll_cmd_ring < CMD_RING_POLL_RETRIES) {
> @@ -4409,7 +4415,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
>             red_error("bad command type");
>         }
>         n++;
> -        if ((worker->display_channel && worker->display_channel->base.send_data.blocked) ||
> +        if ((worker->display_channel && worker->display_channel->common.base.send_data.blocked) ||
>             red_now() - start > 10 * 1000 * 1000) {
>             worker->epoll_timeout = 0;
>             return n;
> @@ -4576,7 +4582,7 @@ static inline void fill_rects_clip(SpiceMarshaller *m, SpiceClipRects *data)
>
>  static void fill_base(DisplayChannel *display_channel, Drawable *drawable)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     SpiceMsgDisplayBase base;
>
>     base.surface_id = drawable->surface_id;
> @@ -4735,7 +4741,7 @@ static void red_display_free_glz_drawable_instance(DisplayChannel *channel,
>         if (drawable) {
>             drawable->red_glz_drawable = NULL;
>         } else { // no reference to the qxl drawable left
> -            free_red_drawable(channel->base.worker, glz_drawable->red_drawable,
> +            free_red_drawable(channel->common.worker, glz_drawable->red_drawable,
>                               glz_drawable->group_id, glz_drawable->self_bitmap);
>         }
>
> @@ -5302,7 +5308,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
>                                          SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
>                                          compress_send_data_t* o_comp_data)
>  {
> -    RedWorker *worker = (RedWorker *)display_channel->base.worker;
> +    RedWorker *worker = (RedWorker *)display_channel->common.worker;
>  #ifdef COMPRESS_STAT
>     stat_time_t start_time = stat_now();
>  #endif
> @@ -5402,7 +5408,7 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
>                                         SpiceImage *dest, SpiceBitmap *src,
>                                         compress_send_data_t* o_comp_data, uint32_t group_id)
>  {
> -    RedWorker *worker = display_channel->base.worker;
> +    RedWorker *worker = display_channel->common.worker;
>     LzData *lz_data = &worker->lz_data;
>     LzContext *lz = worker->lz;
>     LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format];
> @@ -5477,7 +5483,7 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *
>                                    SpiceBitmap *src, compress_send_data_t* o_comp_data,
>                                    uint32_t group_id)
>  {
> -    RedWorker *worker = display_channel->base.worker;
> +    RedWorker *worker = display_channel->common.worker;
>     JpegData *jpeg_data = &worker->jpeg_data;
>     LzData *lz_data = &worker->lz_data;
>     JpegEncoderContext *jpeg = worker->jpeg;
> @@ -5618,7 +5624,7 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, Spice
>                                           SpiceBitmap *src, compress_send_data_t* o_comp_data,
>                                           uint32_t group_id)
>  {
> -    RedWorker *worker = display_channel->base.worker;
> +    RedWorker *worker = display_channel->common.worker;
>     QuicData *quic_data = &worker->quic_data;
>     QuicContext *quic = worker->quic;
>     QuicImageType type;
> @@ -5708,7 +5714,7 @@ static inline int red_compress_image(DisplayChannel *display_channel,
>                                      compress_send_data_t* o_comp_data)
>  {
>     spice_image_compression_t image_compression =
> -        display_channel->base.worker->image_compression;
> +        display_channel->common.worker->image_compression;
>     int quic_compress = FALSE;
>
>     if ((image_compression == SPICE_IMAGE_COMPRESS_OFF) ||
> @@ -5741,7 +5747,7 @@ static inline int red_compress_image(DisplayChannel *display_channel,
>                 } else {
>                     if (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_INVALID) {
>                         quic_compress = BITMAP_FMT_IS_RGB[src->format] &&
> -                           (_get_bitmap_graduality_level(display_channel->base.worker, src, drawable->group_id) ==
> +                           (_get_bitmap_graduality_level(display_channel->common.worker, src, drawable->group_id) ==
>                              BITMAP_GRADUAL_HIGH);
>                     } else {
>                         quic_compress = (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_HIGH);
> @@ -5848,8 +5854,7 @@ typedef enum {
>  static FillBitsType fill_bits(DisplayChannel *display_channel, SpiceMarshaller *m,
>                               SpiceImage *simage, Drawable *drawable, int can_lossy)
>  {
> -    RedChannel *channel = &display_channel->base;
> -    RedWorker *worker = channel->worker;
> +    RedWorker *worker = display_channel->common.worker;
>     SpiceImage image;
>     compress_send_data_t comp_send_data = {0};
>     SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out;
> @@ -5912,7 +5917,7 @@ static FillBitsType fill_bits(DisplayChannel *display_channel, SpiceMarshaller *
>     case SPICE_IMAGE_TYPE_BITMAP: {
>         SpiceBitmap *bitmap = &image.u.bitmap;
>  #ifdef DUMP_BITMAP
> -        dump_bitmap(display_channel->base.worker, &simage->u.bitmap, drawable->group_id);
> +        dump_bitmap(display_channel->common.worker, &simage->u.bitmap, drawable->group_id);
>  #endif
>         /* Images must be added to the cache only after they are compressed
>            in order to prevent starvation in the client between pixmap_cache and
> @@ -5977,12 +5982,12 @@ static void fill_mask(DisplayChannel *display_channel, SpiceMarshaller *m,
>                       SpiceImage *mask_bitmap, Drawable *drawable)
>  {
>     if (mask_bitmap && m) {
> -        if (display_channel->base.worker->image_compression != SPICE_IMAGE_COMPRESS_OFF) {
> +        if (display_channel->common.worker->image_compression != SPICE_IMAGE_COMPRESS_OFF) {
>             spice_image_compression_t save_img_comp =
> -                display_channel->base.worker->image_compression;
> -            display_channel->base.worker->image_compression = SPICE_IMAGE_COMPRESS_OFF;
> +                display_channel->common.worker->image_compression;
> +            display_channel->common.worker->image_compression = SPICE_IMAGE_COMPRESS_OFF;
>             fill_bits(display_channel, m, mask_bitmap, drawable, FALSE);
> -            display_channel->base.worker->image_compression = save_img_comp;
> +            display_channel->common.worker->image_compression = save_img_comp;
>         } else {
>             fill_bits(display_channel, m, mask_bitmap, drawable, FALSE);
>         }
> @@ -6070,8 +6075,8 @@ static int is_surface_area_lossy(DisplayChannel *display_channel, uint32_t surfa
>     QRegion *surface_lossy_region;
>     QRegion lossy_region;
>
> -    validate_surface(display_channel->base.worker, surface_id);
> -    surface = &display_channel->base.worker->surfaces[surface_id];
> +    validate_surface(display_channel->common.worker, surface_id);
> +    surface = &display_channel->common.worker->surfaces[surface_id];
>     surface_lossy_region = &display_channel->surface_client_lossy_region[surface_id];
>
>     if (!area) {
> @@ -6281,7 +6286,7 @@ static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
>     Ring *pipe;
>
>     ASSERT(num_surfaces);
> -    pipe = &display_channel->base.pipe;
> +    pipe = &display_channel->common.base.pipe;
>
>     for (pipe_item = (PipeItem *)ring_get_head(pipe);
>          pipe_item;
> @@ -6319,7 +6324,7 @@ static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
>     resent_areas[0] = *first_area;
>     num_resent = 1;
>
> -    pipe = &display_channel->base.pipe;
> +    pipe = &display_channel->common.base.pipe;
>
>     // going from the oldest to the newest
>     for (pipe_item = (PipeItem *)ring_get_tail(pipe);
> @@ -6430,7 +6435,7 @@ static void red_send_qxl_draw_fill(RedWorker *worker,
>                                    DisplayChannel *display_channel,
>                                    Drawable *item)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     RedDrawable *drawable = item->red_drawable;
>     SpiceMarshaller *brush_pat_out;
>     SpiceMarshaller *mask_bitmap_out;
> @@ -6513,7 +6518,7 @@ static FillBitsType red_send_qxl_draw_opaque(RedWorker *worker,
>                                              DisplayChannel *display_channel,
>                                              Drawable *item, int src_allowed_lossy)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     RedDrawable *drawable = item->red_drawable;
>     SpiceMarshaller *brush_pat_out;
>     SpiceMarshaller *src_bitmap_out;
> @@ -6610,7 +6615,7 @@ static FillBitsType red_send_qxl_draw_copy(RedWorker *worker,
>                                            DisplayChannel *display_channel,
>                                            Drawable *item, int src_allowed_lossy)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     RedDrawable *drawable = item->red_drawable;
>     SpiceMarshaller *src_bitmap_out;
>     SpiceMarshaller *mask_bitmap_out;
> @@ -6662,7 +6667,7 @@ static void red_send_qxl_draw_transparent(RedWorker *worker,
>                                           DisplayChannel *display_channel,
>                                           Drawable *item)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     RedDrawable *drawable = item->red_drawable;
>     SpiceMarshaller *src_bitmap_out;
>     SpiceTransparent transparent;
> @@ -6708,7 +6713,7 @@ static FillBitsType red_send_qxl_draw_alpha_blend(RedWorker *worker,
>                                                   Drawable *item,
>                                                   int src_allowed_lossy)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     RedDrawable *drawable = item->red_drawable;
>     SpiceMarshaller *src_bitmap_out;
>     SpiceAlphaBlend alpha_blend;
> @@ -6754,7 +6759,7 @@ static void red_send_qxl_copy_bits(RedWorker *worker,
>                                    DisplayChannel *display_channel,
>                                    Drawable *item)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     RedDrawable *drawable = item->red_drawable;
>     SpicePoint copy_bits;
>
> @@ -6797,7 +6802,7 @@ static void red_send_qxl_draw_blend(RedWorker *worker,
>                                     DisplayChannel *display_channel,
>                                     Drawable *item)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     RedDrawable *drawable = item->red_drawable;
>     SpiceMarshaller *src_bitmap_out;
>     SpiceMarshaller *mask_bitmap_out;
> @@ -6860,7 +6865,7 @@ static void red_send_qxl_draw_blackness(RedWorker *worker,
>                                         DisplayChannel *display_channel,
>                                         Drawable *item)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     RedDrawable *drawable = item->red_drawable;
>     SpiceMarshaller *mask_bitmap_out;
>     SpiceBlackness blackness;
> @@ -6892,7 +6897,7 @@ static void red_send_qxl_draw_whiteness(RedWorker *worker,
>                                         DisplayChannel *display_channel,
>                                         Drawable *item)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     RedDrawable *drawable = item->red_drawable;
>     SpiceMarshaller *mask_bitmap_out;
>     SpiceWhiteness whiteness;
> @@ -6926,7 +6931,7 @@ static void red_send_qxl_draw_inverse(RedWorker *worker,
>  {
>     RedDrawable *drawable = item->red_drawable;
>     SpiceMarshaller *mask_bitmap_out;
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     SpiceInvers inverse;
>
>     fill_base(display_channel, item);
> @@ -6952,7 +6957,7 @@ static void red_send_qxl_draw_rop3(RedWorker *worker,
>                                    Drawable *item)
>  {
>     RedDrawable *drawable = item->red_drawable;
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     SpiceRop3 rop3;
>     SpiceMarshaller *src_bitmap_out;
>     SpiceMarshaller *brush_pat_out;
> @@ -7034,7 +7039,7 @@ static void red_send_qxl_draw_stroke(RedWorker *worker,
>                                      Drawable *item)
>  {
>     RedDrawable *drawable = item->red_drawable;
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     SpiceStroke stroke;
>     SpiceMarshaller *brush_pat_out;
>     SpiceMarshaller *style_out;
> @@ -7113,7 +7118,7 @@ static void red_send_qxl_draw_text(RedWorker *worker,
>                                    Drawable *item)
>  {
>     RedDrawable *drawable = item->red_drawable;
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     SpiceText text;
>     SpiceMarshaller *brush_pat_out;
>     SpiceMarshaller *back_brush_pat_out;
> @@ -7248,7 +7253,7 @@ static void red_lossy_send_qxl_drawable(RedWorker *worker, DisplayChannel *displ
>     }
>
>     // a message is pending
> -    if (display_channel->base.send_data.header->type != 0) {
> +    if (display_channel->common.base.send_data.header->type != 0) {
>         display_begin_send_message(display_channel, &item->pipe_item);
>     }
>  }
> @@ -7404,7 +7409,7 @@ static inline void display_begin_send_message(DisplayChannel *channel, void *ite
>         int sync_count = 0;
>         int i;
>
> -        inval_m = spice_marshaller_get_submarshaller(channel->base.send_data.marshaller);
> +        inval_m = spice_marshaller_get_submarshaller(channel->common.base.send_data.marshaller);
>
>         /* type + size + submessage */
>         spice_marshaller_add_uint16(inval_m, SPICE_MSG_DISPLAY_INVAL_LIST);
> @@ -7413,7 +7418,7 @@ static inline void display_begin_send_message(DisplayChannel *channel, void *ite
>         spice_marshall_msg_display_inval_list(inval_m, free_list->res);
>
>         for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
> -            if (i != channel->base.id && free_list->sync[i] != 0) {
> +            if (i != channel->common.id && free_list->sync[i] != 0) {
>                 free_list->wait.header.wait_list[sync_count].channel_type = SPICE_CHANNEL_DISPLAY;
>                 free_list->wait.header.wait_list[sync_count].channel_id = i;
>                 free_list->wait.header.wait_list[sync_count++].message_serial = free_list->sync[i];
> @@ -7422,7 +7427,7 @@ static inline void display_begin_send_message(DisplayChannel *channel, void *ite
>         free_list->wait.header.wait_count = sync_count;
>
>         if (sync_count) {
> -            wait_m = spice_marshaller_get_submarshaller(channel->base.send_data.marshaller);
> +            wait_m = spice_marshaller_get_submarshaller(channel->common.base.send_data.marshaller);
>
>             /* type + size + submessage */
>             spice_marshaller_add_uint16(wait_m, SPICE_MSG_WAIT_FOR_CHANNELS);
> @@ -7432,30 +7437,36 @@ static inline void display_begin_send_message(DisplayChannel *channel, void *ite
>             sub_list_len++;
>         }
>
> -        SpiceMarshaller *sub_list_m = spice_marshaller_get_submarshaller(channel->base.send_data.marshaller);
> +        SpiceMarshaller *sub_list_m = spice_marshaller_get_submarshaller(channel->common.base.send_data.marshaller);
>         spice_marshaller_add_uint16(sub_list_m, sub_list_len);
>         if (wait_m) {
>             spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(wait_m));
>         }
>         spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m));
> -        channel->base.send_data.header->sub_list = spice_marshaller_get_offset(sub_list_m);
> +        channel->common.base.send_data.header->sub_list = spice_marshaller_get_offset(sub_list_m);
>     }
>     red_begin_send_message((RedChannel *)channel, item);
>  }
>
>  static inline RedChannel *red_ref_channel(RedChannel *channel)
>  {
> +    CommonChannel *common;
> +
>     if (!channel) {
>         return NULL;
>     }
> -    ++channel->listener.refs;
> +    common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> +    ++common->listener.refs;
>     return channel;
>  }
>
>  static inline void red_unref_channel(RedChannel *channel)
>  {
> +    CommonChannel *common;
> +
>     ASSERT(channel);
> -    if (!--channel->listener.refs) {
> +    common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> +    if (!--common->listener.refs) {
>         spice_marshaller_destroy(channel->send_data.marshaller);
>         free(channel);
>     }
> @@ -7649,8 +7660,8 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
>     ASSERT(stream);
>     ASSERT(drawable->red_drawable->type == QXL_DRAW_COPY);
>
> -    channel = &display_channel->base;
> -    worker = channel->worker;
> +    channel = &display_channel->common.base;
> +    worker = display_channel->common.worker;
>     image = drawable->red_drawable->u.copy.src_bitmap;
>
>     if (image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP) {
> @@ -7733,9 +7744,9 @@ static inline void send_qxl_drawable(DisplayChannel *display_channel, Drawable *
>         return;
>     }
>     if (!display_channel->enable_jpeg)
> -        red_send_qxl_drawable(display_channel->base.worker, display_channel, item);
> +        red_send_qxl_drawable(display_channel->common.worker, display_channel, item);
>     else
> -        red_lossy_send_qxl_drawable(display_channel->base.worker, display_channel, item);
> +        red_lossy_send_qxl_drawable(display_channel->common.worker, display_channel, item);
>  }
>
>  static void red_send_set_ack(RedChannel *channel)
> @@ -7763,7 +7774,7 @@ static inline void red_send_verb(RedChannel *channel, uint16_t verb)
>  static inline void display_send_verb(DisplayChannel *channel, uint16_t verb)
>  {
>     ASSERT(channel);
> -    channel->base.send_data.header->type = verb;
> +    channel->common.base.send_data.header->type = verb;
>     display_begin_send_message(channel, NULL);
>  }
>
> @@ -7793,9 +7804,9 @@ static void display_channel_send_migrate(DisplayChannel *display_channel)
>  {
>     SpiceMsgMigrate migrate;
>
> -    display_channel->base.send_data.header->type = SPICE_MSG_MIGRATE;
> +    display_channel->common.base.send_data.header->type = SPICE_MSG_MIGRATE;
>     migrate.flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
> -    spice_marshall_msg_migrate(display_channel->base.send_data.marshaller, &migrate);
> +    spice_marshall_msg_migrate(display_channel->common.base.send_data.marshaller, &migrate);
>     display_channel->expect_migrate_mark = TRUE;
>     display_begin_send_message(display_channel, NULL);
>  }
> @@ -7804,7 +7815,7 @@ static void display_channel_send_migrate_data(DisplayChannel *display_channel)
>  {
>     DisplayChannelMigrateData display_data;
>
> -    display_channel->base.send_data.header->type = SPICE_MSG_MIGRATE_DATA;
> +    display_channel->common.base.send_data.header->type = SPICE_MSG_MIGRATE_DATA;
>
>     ASSERT(display_channel->pixmap_cache);
>     display_data.magic = DISPLAY_MIGRATE_DATA_MAGIC;
> @@ -7826,7 +7837,7 @@ static void display_channel_send_migrate_data(DisplayChannel *display_channel)
>                                         &display_data.glz_dict_restore_data,
>                                         &display_channel->glz_data.usr);
>
> -    spice_marshaller_add_ref(display_channel->base.send_data.marshaller,
> +    spice_marshaller_add_ref(display_channel->common.base.send_data.marshaller,
>                              (uint8_t *)&display_data, sizeof(display_data));
>     display_begin_send_message(display_channel, NULL);
>  }
> @@ -7837,7 +7848,7 @@ static void display_channel_pixmap_sync(DisplayChannel *display_channel)
>     PixmapCache *pixmap_cache;
>
>
> -    display_channel->base.send_data.header->type = SPICE_MSG_WAIT_FOR_CHANNELS;
> +    display_channel->common.base.send_data.header->type = SPICE_MSG_WAIT_FOR_CHANNELS;
>     pixmap_cache = display_channel->pixmap_cache;
>
>
> @@ -7852,7 +7863,7 @@ static void display_channel_pixmap_sync(DisplayChannel *display_channel)
>
>     pthread_mutex_unlock(&pixmap_cache->lock);
>
> -    spice_marshall_msg_wait_for_channels(display_channel->base.send_data.marshaller, &wait);
> +    spice_marshall_msg_wait_for_channels(display_channel->common.base.send_data.marshaller, &wait);
>
>     display_begin_send_message(display_channel, NULL);
>  }
> @@ -7861,10 +7872,10 @@ static void display_channel_reset_cache(DisplayChannel *display_channel)
>  {
>     SpiceMsgWaitForChannels wait;
>
> -    display_channel->base.send_data.header->type = SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS;
> +    display_channel->common.base.send_data.header->type = SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS;
>     pixmap_cache_reset(display_channel->pixmap_cache, display_channel, &wait);
>
> -    spice_marshall_msg_display_inval_all_pixmaps(display_channel->base.send_data.marshaller,
> +    spice_marshall_msg_display_inval_all_pixmaps(display_channel->common.base.send_data.marshaller,
>                                                  &wait);
>     display_begin_send_message(display_channel, NULL);
>  }
> @@ -7886,8 +7897,8 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
>     SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out;
>
>     ASSERT(display_channel && item);
> -    channel = &display_channel->base;
> -    worker = channel->worker;
> +    channel = &display_channel->common.base;
> +    worker = display_channel->common.worker;
>
>     QXL_SET_IMAGE_ID(&red_image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique);
>     red_image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
> @@ -7937,14 +7948,14 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
>
>     compress_send_data_t comp_send_data = {0};
>
> -    comp_mode = display_channel->base.worker->image_compression;
> +    comp_mode = display_channel->common.worker->image_compression;
>
>     if ((comp_mode == SPICE_IMAGE_COMPRESS_AUTO_LZ) ||
>         (comp_mode == SPICE_IMAGE_COMPRESS_AUTO_GLZ)) {
>         if (BITMAP_FMT_IS_RGB[item->image_format]) {
>             if (!_stride_is_extra(&bitmap)) {
>                 BitmapGradualType grad_level;
> -                grad_level = _get_bitmap_graduality_level(display_channel->base.worker,
> +                grad_level = _get_bitmap_graduality_level(display_channel->common.worker,
>                                                           &bitmap,
>                                                           worker->mem_slots.internal_groupslot_id);
>                 if (grad_level == BITMAP_GRADUAL_HIGH) {
> @@ -8015,7 +8026,7 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
>     SpiceMarshaller *src_bitmap_out, *mask_bitmap_out;
>
>     ASSERT(display_channel && item && item->drawable);
> -    channel = &display_channel->base;
> +    channel = &display_channel->common.base;
>
>     channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_COPY;
>
> @@ -8042,7 +8053,7 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
>
>  static void red_display_send_stream_start(DisplayChannel *display_channel, StreamAgent *agent)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     Stream *stream = agent->stream;
>
>     agent->lats_send_time = 0;
> @@ -8084,7 +8095,7 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea
>  static void red_display_send_stream_clip(DisplayChannel *display_channel,
>                                          StreamClipItem *item)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>
>     StreamAgent *agent = item->stream_agent;
>     Stream *stream = agent->stream;
> @@ -8105,7 +8116,7 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
>
>  static void red_display_send_stream_end(DisplayChannel *display_channel, StreamAgent* agent)
>  {
> -    RedChannel *channel = &display_channel->base;
> +    RedChannel *channel = &display_channel->common.base;
>     SpiceMsgDisplayStreamDestroy destroy;
>
>     channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_DESTROY;
> @@ -8130,19 +8141,19 @@ static void red_send_cursor_init(CursorChannel *channel)
>
>     ASSERT(channel);
>
> -    worker = channel->base.worker;
> +    worker = channel->common.worker;
>
> -    channel->base.send_data.header->type = SPICE_MSG_CURSOR_INIT;
> +    channel->common.base.send_data.header->type = SPICE_MSG_CURSOR_INIT;
>     msg.visible = worker->cursor_visible;
>     msg.position = worker->cursor_position;
>     msg.trail_length = worker->cursor_trail_length;
>     msg.trail_frequency = worker->cursor_trail_frequency;
>
>     fill_cursor(channel, &msg.cursor, worker->cursor, &info);
> -    spice_marshall_msg_cursor_init(channel->base.send_data.marshaller, &msg);
> -    add_buf_from_info(&channel->base, channel->base.send_data.marshaller, &info);
> +    spice_marshall_msg_cursor_init(channel->common.base.send_data.marshaller, &msg);
> +    add_buf_from_info(&channel->common.base, channel->common.base.send_data.marshaller, &info);
>
> -    red_begin_send_message(&channel->base, worker->cursor);
> +    red_begin_send_message(&channel->common.base, worker->cursor);
>  }
>
>  static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cursor)
> @@ -8153,10 +8164,10 @@ static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cu
>
>     ASSERT(cursor_channel);
>
> -    channel = &cursor_channel->base;
> +    channel = &cursor_channel->common.base;
>     channel->send_data.header->type = SPICE_MSG_CURSOR_SET;
>     cursor_set.position = cursor->position;
> -    cursor_set.visible = channel->worker->cursor_visible;
> +    cursor_set.visible = cursor_channel->common.worker->cursor_visible;
>
>     fill_cursor(cursor_channel, &cursor_set.cursor, &cursor->base, &info);
>     spice_marshall_msg_cursor_set(channel->send_data.marshaller, &cursor_set);
> @@ -8164,17 +8175,17 @@ static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cu
>
>     red_begin_send_message(channel, cursor);
>
> -    red_release_cursor(channel->worker, (CursorItem *)cursor);
> +    red_release_cursor(cursor_channel->common.worker, (CursorItem *)cursor);
>  }
>
>  static void cursor_channel_send_migrate(CursorChannel *cursor_channel)
>  {
>     SpiceMsgMigrate migrate;
>
> -    cursor_channel->base.send_data.header->type = SPICE_MSG_MIGRATE;
> +    cursor_channel->common.base.send_data.header->type = SPICE_MSG_MIGRATE;
>     migrate.flags = 0;
>
> -    spice_marshall_msg_migrate(cursor_channel->base.send_data.marshaller, &migrate);
> +    spice_marshall_msg_migrate(cursor_channel->common.base.send_data.marshaller, &migrate);
>     red_begin_send_message((RedChannel*)cursor_channel, NULL);
>  }
>
> @@ -8186,7 +8197,7 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
>
>     ASSERT(cursor_channel);
>
> -    channel = &cursor_channel->base;
> +    channel = &cursor_channel->common.base;
>     m = channel->send_data.marshaller;
>
>     cmd = cursor->red_cursor;
> @@ -8206,7 +8217,7 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
>
>             channel->send_data.header->type = SPICE_MSG_CURSOR_SET;
>             cursor_set.position = cmd->u.set.position;
> -            cursor_set.visible = channel->worker->cursor_visible;
> +            cursor_set.visible = cursor_channel->common.worker->cursor_visible;
>
>             fill_cursor(cursor_channel, &cursor_set.cursor, cursor, &info);
>             spice_marshall_msg_cursor_set(m, &cursor_set);
> @@ -8232,7 +8243,7 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
>
>     red_begin_send_message(channel, cursor);
>
> -    red_release_cursor(channel->worker, cursor);
> +    red_release_cursor(cursor_channel->common.worker, cursor);
>  }
>
>  static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCreate *surface_create)
> @@ -8240,7 +8251,7 @@ static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCrea
>     RedChannel *channel;
>
>     ASSERT(display);
> -    channel = &display->base;
> +    channel = &display->common.base;
>
>     region_init(&display->surface_client_lossy_region[surface_create->surface_id]);
>     channel->send_data.header->type = SPICE_MSG_DISPLAY_SURFACE_CREATE;
> @@ -8256,7 +8267,7 @@ static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_i
>     SpiceMsgSurfaceDestroy surface_destroy;
>
>     ASSERT(display);
> -    channel = &display->base;
> +    channel = &display->common.base;
>
>     region_destroy(&display->surface_client_lossy_region[surface_id]);
>     channel->send_data.header->type = SPICE_MSG_DISPLAY_SURFACE_DESTROY;
> @@ -8533,11 +8544,11 @@ static void red_disconnect_display(RedChannel *channel)
>     }
>
>     display_channel = (DisplayChannel *)channel;
> -    ASSERT(display_channel == channel->worker->display_channel);
> +    ASSERT(display_channel == display_channel->common.worker->display_channel);
>  #ifdef COMPRESS_STAT
>     print_compress_stats(display_channel);
>  #endif
> -    channel->worker->display_channel = NULL;
> +    display_channel->common.worker->display_channel = NULL;
>     red_display_unshare_stream_buf(display_channel);
>     red_release_pixmap_cache(display_channel);
>     red_release_glz(display_channel);
> @@ -8557,8 +8568,8 @@ static void red_disconnect_display(RedChannel *channel)
>  static void red_migrate_display(RedWorker *worker)
>  {
>     if (worker->display_channel) {
> -        red_pipe_add_verb(&worker->display_channel->base, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
> -        red_pipe_add_type(&worker->display_channel->base, PIPE_ITEM_TYPE_MIGRATE);
> +        red_pipe_add_verb(&worker->display_channel->common.base, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
> +        red_pipe_add_type(&worker->display_channel->common.base, PIPE_ITEM_TYPE_MIGRATE);
>     }
>  }
>
> @@ -8684,7 +8695,7 @@ static inline void __red_create_surface_item(RedWorker *worker, int surface_id,
>
>     worker->display_channel->surface_client_created[surface_id] = TRUE;
>
> -    red_pipe_add(&worker->display_channel->base, &create->pipe_item);
> +    red_pipe_add(&worker->display_channel->common.base, &create->pipe_item);
>  }
>
>  static inline void red_create_surface_item(RedWorker *worker, int surface_id)
> @@ -8774,7 +8785,7 @@ static inline void flush_display_commands(RedWorker *worker)
>         for (;;) {
>             display_channel_push(worker);
>             if (!worker->display_channel ||
> -                                         worker->display_channel->base.pipe_size <= MAX_PIPE_SIZE) {
> +                                         worker->display_channel->common.base.pipe_size <= MAX_PIPE_SIZE) {
>                 break;
>             }
>             RedChannel *channel = (RedChannel *)worker->display_channel;
> @@ -8816,7 +8827,7 @@ static inline void flush_cursor_commands(RedWorker *worker)
>         for (;;) {
>             cursor_channel_push(worker);
>             if (!worker->cursor_channel ||
> -                                        worker->cursor_channel->base.pipe_size <= MAX_PIPE_SIZE) {
> +                                        worker->cursor_channel->common.base.pipe_size <= MAX_PIPE_SIZE) {
>                 break;
>             }
>             RedChannel *channel = (RedChannel *)worker->cursor_channel;
> @@ -8846,8 +8857,8 @@ static void push_new_primary_surface(RedWorker *worker)
>     DisplayChannel *display_channel;
>
>     if ((display_channel = worker->display_channel)) {
> -        red_pipe_add_type(&display_channel->base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
> -        if (!display_channel->base.migrate) {
> +        red_pipe_add_type(&display_channel->common.base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
> +        if (!display_channel->common.base.migrate) {
>             red_create_surface_item(worker, 0);
>         }
>         display_channel_push(worker);
> @@ -8860,12 +8871,12 @@ static int display_channel_wait_for_init(DisplayChannel *display_channel)
>     uint64_t end_time = red_now() + DISPLAY_CLIENT_TIMEOUT;
>     for (;;) {
>         red_receive((RedChannel *)display_channel);
> -        if (!display_channel->base.peer) {
> +        if (!display_channel->common.base.peer) {
>             break;
>         }
>         if (display_channel->pixmap_cache && display_channel->glz_dict) {
>             display_channel->pixmap_cache_generation = display_channel->pixmap_cache->generation;
> -            display_channel->glz = glz_encoder_create(display_channel->base.id,
> +            display_channel->glz = glz_encoder_create(display_channel->common.id,
>                                                       display_channel->glz_dict->dict,
>                                                       &display_channel->glz_data.usr);
>             if (!display_channel->glz) {
> @@ -8888,9 +8899,9 @@ static void on_new_display_channel(RedWorker *worker)
>     DisplayChannel *display_channel = worker->display_channel;
>     ASSERT(display_channel);
>
> -    red_pipe_add_type(&display_channel->base, PIPE_ITEM_TYPE_SET_ACK);
> +    red_pipe_add_type(&display_channel->common.base, PIPE_ITEM_TYPE_SET_ACK);
>
> -    if (display_channel->base.migrate) {
> +    if (display_channel->common.base.migrate) {
>         display_channel->expect_migrate_data = TRUE;
>         return;
>     }
> @@ -8898,13 +8909,13 @@ static void on_new_display_channel(RedWorker *worker)
>     if (!display_channel_wait_for_init(display_channel)) {
>         return;
>     }
> -    display_channel->base.ack_data.messages_window = 0;
> +    display_channel->common.base.ack_data.messages_window = 0;
>     if (worker->surfaces[0].context.canvas) {
>         red_current_flush(worker, 0);
>         push_new_primary_surface(worker);
>         red_add_surface_image(worker, 0);
> -        if (channel_is_connected(&display_channel->base)) {
> -            red_pipe_add_verb(&display_channel->base, SPICE_MSG_DISPLAY_MARK);
> +        if (channel_is_connected(&display_channel->common.base)) {
> +            red_pipe_add_verb(&display_channel->common.base, SPICE_MSG_DISPLAY_MARK);
>             red_disply_start_streams(display_channel);
>         }
>     }
> @@ -9184,8 +9195,8 @@ static int display_channel_handle_migrate_data(DisplayChannel *channel, size_t s
>         red_printf("invalid content");
>         return FALSE;
>     }
> -    ASSERT(channel->base.send_data.serial == 0);
> -    channel->base.send_data.serial = migrate_data->message_serial;
> +    ASSERT(channel->common.base.send_data.serial == 0);
> +    channel->common.base.send_data.serial = migrate_data->message_serial;
>     if (!(channel->pixmap_cache = red_get_pixmap_cache(migrate_data->pixmap_cache_id, -1))) {
>         return FALSE;
>     }
> @@ -9202,7 +9213,7 @@ static int display_channel_handle_migrate_data(DisplayChannel *channel, size_t s
>     }
>
>     if (display_channel_handle_migrate_glz_dictionary(channel, migrate_data)) {
> -        channel->glz = glz_encoder_create(channel->base.id,
> +        channel->glz = glz_encoder_create(channel->common.id,
>                                           channel->glz_dict->dict, &channel->glz_data.usr);
>         if (!channel->glz) {
>             PANIC("create global lz failed");
> @@ -9213,7 +9224,7 @@ static int display_channel_handle_migrate_data(DisplayChannel *channel, size_t s
>
>     red_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
>
> -    channel->base.ack_data.messages_window = 0;
> +    channel->common.base.ack_data.messages_window = 0;
>     return TRUE;
>  }
>
> @@ -9318,6 +9329,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
>  {
>     struct epoll_event event;
>     RedChannel *channel;
> +    CommonChannel *common;
>     int flags;
>     int delay_val;
>
> @@ -9337,17 +9349,19 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
>     }
>
>     ASSERT(size >= sizeof(*channel));
> -    channel = spice_malloc0(size);
> -    channel->id = worker->id;
> +    common = spice_malloc0(size);
> +    channel = &common->base;
> +    ASSERT(common == (CommonChannel*)channel);
> +    common->id = worker->id;
>     channel->parser = spice_get_client_channel_parser(channel_id, NULL);
> -    channel->listener.refs = 1;
> -    channel->listener.action = handler;
> +    common->listener.refs = 1;
> +    common->listener.action = handler;
>     channel->disconnect = disconnect;
>     channel->hold_item = hold_item;
>     channel->release_item = release_item;
>     channel->handle_message = handle_message;
>     channel->peer = peer;
> -    channel->worker = worker;
> +    common->worker = worker;
>     channel->ack_data.messages_window = ~0;  // blocks send message (maybe use send_data.blocked +
>                                     // block flags)
>     channel->ack_data.client_window = IS_LOW_BANDWIDTH() ? WIDE_CLIENT_ACK_WINDOW :
> @@ -9360,7 +9374,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
>     channel->send_data.marshaller = spice_marshaller_new();
>
>     event.events = EPOLLIN | EPOLLOUT | EPOLLET;
> -    event.data.ptr = channel;
> +    event.data.ptr = &common->listener;
>     if (epoll_ctl(worker->epoll, EPOLL_CTL_ADD, peer->socket, &event) == -1) {
>         red_printf("epoll_ctl failed, %s", strerror(errno));
>         goto error2;
> @@ -9380,7 +9394,8 @@ error1:
>
>  static void handle_channel_events(EventListener *in_listener, uint32_t events)
>  {
> -    RedChannel *channel = (RedChannel *)in_listener;
> +    CommonChannel *common = SPICE_CONTAINEROF(in_listener, CommonChannel, listener);
> +    RedChannel *channel = &common->base;
>
>     if ((events & EPOLLIN)) {
>         red_receive(channel);
> @@ -9415,17 +9430,19 @@ static void display_channel_hold_pipe_item(PipeItem *item)
>
>  static void display_channel_release_item(RedChannel *channel, void *item)
>  {
> +    CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> +
>     ASSERT(item);
>     switch (((PipeItem *)item)->type) {
>     case PIPE_ITEM_TYPE_DRAW:
>     case PIPE_ITEM_TYPE_STREAM_CREATE:
> -        release_drawable(channel->worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
> +        release_drawable(common->worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
>         break;
>     case PIPE_ITEM_TYPE_STREAM_CLIP:
>         red_display_release_stream_clip((DisplayChannel *)channel, (StreamClipItem *)item);
>         break;
>     case PIPE_ITEM_TYPE_UPGRADE:
> -        release_upgrade_item(channel->worker, (UpgradeItem *)item);
> +        release_upgrade_item(common->worker, (UpgradeItem *)item);
>         break;
>     case PIPE_ITEM_TYPE_IMAGE:
>         release_image_item((ImageItem *)item);
> @@ -9453,7 +9470,7 @@ static void handle_new_display_channel(RedWorker *worker, RedsStreamContext *pee
>     }
>  #ifdef RED_STATISTICS
>     display_channel->stat = stat_add_node(worker->stat, "display_channel", TRUE);
> -    display_channel->base.out_bytes_counter = stat_add_counter(display_channel->stat,
> +    display_channel->common.base.out_bytes_counter = stat_add_counter(display_channel->stat,
>                                                                "out_bytes", TRUE);
>     display_channel->cache_hits_counter = stat_add_counter(display_channel->stat,
>                                                            "cache_hits", TRUE);
> @@ -9515,12 +9532,14 @@ static void handle_new_display_channel(RedWorker *worker, RedsStreamContext *pee
>
>  static void red_disconnect_cursor(RedChannel *channel)
>  {
> +    CommonChannel *common;
> +
>     if (!channel || !channel->peer) {
>         return;
>     }
> -
> -    ASSERT(channel == (RedChannel *)channel->worker->cursor_channel);
> -    channel->worker->cursor_channel = NULL;
> +    common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> +    ASSERT(channel == (RedChannel *)common->worker->cursor_channel);
> +    common->worker->cursor_channel = NULL;
>     red_reset_cursor_cache((CursorChannel *)channel);
>     red_disconnect_channel(channel);
>  }
> @@ -9528,8 +9547,8 @@ static void red_disconnect_cursor(RedChannel *channel)
>  static void red_migrate_cursor(RedWorker *worker)
>  {
>     if (worker->cursor_channel) {
> -        red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> -        red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_MIGRATE);
> +        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> +        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_MIGRATE);
>     }
>  }
>
> @@ -9539,10 +9558,10 @@ static void on_new_cursor_channel(RedWorker *worker)
>
>     ASSERT(channel);
>
> -    channel->base.ack_data.messages_window = 0;
> -    red_pipe_add_type(&channel->base, PIPE_ITEM_TYPE_SET_ACK);
> -    if (worker->surfaces[0].context.canvas && !channel->base.migrate) {
> -        red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_CURSOR_INIT);
> +    channel->common.base.ack_data.messages_window = 0;
> +    red_pipe_add_type(&channel->common.base, PIPE_ITEM_TYPE_SET_ACK);
> +    if (worker->surfaces[0].context.canvas && !channel->common.base.migrate) {
> +        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
>     }
>  }
>
> @@ -9554,8 +9573,10 @@ static void cursor_channel_hold_pipe_item(PipeItem *item)
>
>  static void cursor_channel_release_item(RedChannel *channel, void *item)
>  {
> +    CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
> +
>     ASSERT(item);
> -    red_release_cursor(channel->worker, item);
> +    red_release_cursor(common->worker, item);
>  }
>
>  static void red_connect_cursor(RedWorker *worker, RedsStreamContext *peer, int migrate)
> @@ -9575,7 +9596,7 @@ static void red_connect_cursor(RedWorker *worker, RedsStreamContext *peer, int m
>     }
>  #ifdef RED_STATISTICS
>     channel->stat = stat_add_node(worker->stat, "cursor_channel", TRUE);
> -    channel->base.out_bytes_counter = stat_add_counter(channel->stat, "out_bytes", TRUE);
> +    channel->common.base.out_bytes_counter = stat_add_counter(channel->stat, "out_bytes", TRUE);
>  #endif
>     ring_init(&channel->cursor_cache_lru);
>     channel->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE;
> @@ -9666,6 +9687,7 @@ static void red_wait_outgoing_item(RedChannel *channel)
>
>  static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
>  {
> +    CommonChannel *common;
>     uint64_t end_time;
>     int item_in_pipe;
>
> @@ -9674,6 +9696,7 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
>     }
>
>     red_printf("");
> +    common = SPICE_CONTAINEROF(channel, CommonChannel, base);
>     red_ref_channel(channel);
>     channel->hold_item(item);
>
> @@ -9684,13 +9707,13 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
>         red_send_data(channel, NULL);
>     }
>     // todo: different push for each channel
> -    red_push(channel->worker);
> +    red_push(common->worker);
>
>     while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) {
>         usleep(CHANNEL_PUSH_SLEEP_DURATION);
>         red_receive(channel);
>         red_send_data(channel, NULL);
> -        red_push(channel->worker);
> +        red_push(common->worker);
>     }
>
>     if (item_in_pipe) {
> @@ -9783,7 +9806,7 @@ static inline void destroy_surface_wait(RedWorker *worker, int surface_id)
>     // there is one during sending.
>     red_wait_outgoing_item((RedChannel *)worker->display_channel);
>     if (worker->display_channel) {
> -        ASSERT(!worker->display_channel->base.send_data.item);
> +        ASSERT(!worker->display_channel->common.base.send_data.item);
>     }
>  }
>
> @@ -9827,16 +9850,16 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
>
>     red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
>     if (worker->cursor_channel) {
> -        red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> -        if (!worker->cursor_channel->base.migrate) {
> -            red_pipe_add_verb(&worker->cursor_channel->base, SPICE_MSG_CURSOR_RESET);
> +        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> +        if (!worker->cursor_channel->common.base.migrate) {
> +            red_pipe_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
>         }
> -        ASSERT(!worker->cursor_channel->base.send_data.item);
> +        ASSERT(!worker->cursor_channel->common.base.send_data.item);
>     }
>
>     if (worker->display_channel) {
> -        red_pipe_add_type(&worker->display_channel->base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
> -        red_pipe_add_verb(&worker->display_channel->base, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
> +        red_pipe_add_type(&worker->display_channel->common.base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
> +        red_pipe_add_verb(&worker->display_channel->common.base, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
>     }
>
>     red_display_clear_glz_drawables(worker->display_channel);
> @@ -9874,12 +9897,12 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
>                        line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA);
>
>     if (worker->display_channel) {
> -        red_pipe_add_verb(&worker->display_channel->base, SPICE_MSG_DISPLAY_MARK);
> +        red_pipe_add_verb(&worker->display_channel->common.base, SPICE_MSG_DISPLAY_MARK);
>         display_channel_push(worker);
>     }
>
>     if (worker->cursor_channel) {
> -        red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_CURSOR_INIT);
> +        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_CURSOR_INIT);
>     }
>
>     message = RED_WORKER_MESSAGE_READY;
> @@ -9903,11 +9926,11 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
>
>     red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
>     if (worker->cursor_channel) {
> -        red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> -        if (!worker->cursor_channel->base.migrate) {
> -            red_pipe_add_verb(&worker->cursor_channel->base, SPICE_MSG_CURSOR_RESET);
> +        red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> +        if (!worker->cursor_channel->common.base.migrate) {
> +            red_pipe_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
>         }
> -        ASSERT(!worker->cursor_channel->base.send_data.item);
> +        ASSERT(!worker->cursor_channel->common.base.send_data.item);
>     }
>
>     flush_all_qxl_commands(worker);
> @@ -9948,7 +9971,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
>         }
>         if (worker->qxl->st->qif->flush_resources(worker->qxl) == 0) {
>             red_printf("oom current %u pipe %u", worker->current_size, worker->display_channel ?
> -                       worker->display_channel->base.pipe_size : 0);
> +                       worker->display_channel->common.base.pipe_size : 0);
>             red_free_some(worker);
>             worker->qxl->st->qif->flush_resources(worker->qxl);
>         }
> @@ -9962,11 +9985,11 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
>
>         red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
>         if (worker->cursor_channel) {
> -            red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> -            if (!worker->cursor_channel->base.migrate) {
> -                red_pipe_add_verb(&worker->cursor_channel->base, SPICE_MSG_CURSOR_RESET);
> +            red_pipe_add_type(&worker->cursor_channel->common.base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> +            if (!worker->cursor_channel->common.base.migrate) {
> +                red_pipe_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
>             }
> -            ASSERT(!worker->cursor_channel->base.send_data.item);
> +            ASSERT(!worker->cursor_channel->common.base.send_data.item);
>
>             worker->cursor_visible = TRUE;
>             worker->cursor_position.x = worker->cursor_position.y = 0;
> @@ -10030,10 +10053,10 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
>         red_printf("start");
>         ASSERT(!worker->running);
>         if (worker->cursor_channel) {
> -            worker->cursor_channel->base.migrate = FALSE;
> +            worker->cursor_channel->common.base.migrate = FALSE;
>         }
>         if (worker->display_channel) {
> -            worker->display_channel->base.migrate = FALSE;
> +            worker->display_channel->common.base.migrate = FALSE;
>         }
>         worker->running = TRUE;
>         break;
> --
> 1.7.4
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
>



-- 
Marc-André Lureau


More information about the Spice-devel mailing list