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

Alon Levy alevy at redhat.com
Fri Feb 11 04:43:46 PST 2011


with everything (almost) not in red_channel's RedChannel

As a result of CommonChannel a free cb is added to EventHandler,
to take care of non zero offset for embedded EventHandler.
---
 server/red_client_cache.h        |    2 +-
 server/red_client_shared_cache.h |   20 +-
 server/red_worker.c              |  382 +++++++++++++++++++++-----------------
 3 files changed, 222 insertions(+), 182 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..0ed46e9 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -218,9 +218,11 @@ double inline stat_byte_to_mega(uint64_t size)
 
 typedef struct EventListener EventListener;
 typedef void (*event_listener_action_proc)(EventListener *ctx, uint32_t events);
+typedef void (*event_listener_free_proc)(EventListener *ctx);
 struct EventListener {
     uint32_t refs;
     event_listener_action_proc action;
+    event_listener_free_proc free;
 };
 
 enum {
@@ -352,10 +354,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 +604,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 +673,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 +1010,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 +1267,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 +1276,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 +1291,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 +1300,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 +1308,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 +1320,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 +1330,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 +1357,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 +1493,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 +1809,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 +1826,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 +1852,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 +2349,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 +2489,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 +2515,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 +2527,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 +2571,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 +2585,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 +4287,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 +4308,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 +4348,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 +4417,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 +4584,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 +4743,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 +5310,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 +5410,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 +5485,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 +5626,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 +5716,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 +5749,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 +5856,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 +5919,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 +5984,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 +6077,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 +6288,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 +6326,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 +6437,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 +6520,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 +6617,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 +6669,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 +6715,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 +6761,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 +6804,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 +6867,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 +6899,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 +6933,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 +6959,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 +7041,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 +7120,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 +7255,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 +7411,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 +7420,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 +7429,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 +7439,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 +7662,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 +7746,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 +7776,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 +7806,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 +7817,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 +7839,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 +7850,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 +7865,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 +7874,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 +7899,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 +7950,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 +8028,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 +8055,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 +8097,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 +8118,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 +8143,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 +8166,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 +8177,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 +8199,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 +8219,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 +8245,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 +8253,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 +8269,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 +8546,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 +8570,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 +8697,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 +8787,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 +8829,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 +8859,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 +8873,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 +8901,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 +8911,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 +9197,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 +9215,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 +9226,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;
 }
 
@@ -9308,6 +9321,13 @@ static void red_receive(RedChannel *channel)
     }
 }
 
+static void free_common_channel_from_listener(EventListener *ctx)
+{
+    CommonChannel* common = SPICE_CONTAINEROF(ctx, CommonChannel, listener);
+
+    free(common);
+}
+
 static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id,
                                  RedsStreamContext *peer, int migrate,
                                  event_listener_action_proc handler,
@@ -9318,6 +9338,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 +9358,20 @@ 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;
+    common->listener.free = free_common_channel_from_listener;
     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 +9384,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 +9404,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 +9440,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 +9480,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 +9542,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 +9557,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 +9568,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 +9583,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 +9606,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 +9697,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 +9706,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 +9717,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 +9816,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 +9860,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 +9907,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 +9936,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 +9981,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 +9995,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 +10063,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;
@@ -10164,6 +10197,11 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     }
 }
 
+static void handle_dev_free(EventListener *ctx)
+{
+    free(ctx);
+}
+
 static void red_init(RedWorker *worker, WorkerInitData *init_data)
 {
     struct epoll_event event;
@@ -10179,6 +10217,7 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
     worker->pending = init_data->pending;
     worker->dev_listener.refs = 1;
     worker->dev_listener.action = handle_dev_input;
+    worker->dev_listener.free = handle_dev_free;
     worker->cursor_visible = TRUE;
     ASSERT(init_data->num_renderers > 0);
     worker->num_renderers = init_data->num_renderers;
@@ -10290,7 +10329,8 @@ void *red_worker_main(void *arg)
                     continue;
                 }
             }
-            free(evt_listener);
+            red_printf("freeing event listener");
+            evt_listener->free(evt_listener);
         }
 
         if (worker.running) {
-- 
1.7.4



More information about the Spice-devel mailing list