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

Alon Levy alevy at redhat.com
Thu Feb 10 06:54:40 PST 2011


On Tue, Feb 08, 2011 at 10:07:54PM +0100, Marc-André Lureau wrote:
> 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)
> 
Will do.

> 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..

I prefer CONTAINEROF. It's properly intimidating, and it checks that
the cast-to struct has a field of the correct type, so it is much
safer then just (X*). There is an UPCAST macro in use by qemu and kernel
too I think that is basically the same as CONTAINEROF with the addition
of enforcing an offset 0 of the base type, in effect the same as what
you think as an upcast. We should probably add that and use it. There
are later places where I have
struct ChannelClient {
 RingItem client_link;
 RingItem channel_link;
}

So I actually need sometimes to do a CONTAINEROF with non zero offset (can't
make both client_link and channel_link first in the list..)

> 
> 
> 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