[Spice-commits] 14 commits - server/red_client_cache.h server/red_client_shared_cache.h server/red_worker.c

Alon Levy alon at kemper.freedesktop.org
Fri Feb 11 05:33:19 PST 2011


 server/red_client_cache.h        |    2 
 server/red_client_shared_cache.h |   20 
 server/red_worker.c              | 1026 ++++++++++++++++++++-------------------
 3 files changed, 558 insertions(+), 490 deletions(-)

New commits:
commit 0b687d9b23e375b13738a217e889e2f6b1c676f4
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Feb 10 18:13:49 2011 +0200

    server/red_worker: cursor_channel_send_item: don't downcast

diff --git a/server/red_worker.c b/server/red_worker.c
index 49dcad1..d75856e 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8411,9 +8411,11 @@ static void display_channel_push(RedWorker *worker)
     }
 }
 
-static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
+static void cursor_channel_send_item(CursorChannel *cursor_channel, PipeItem *pipe_item)
 {
-    CursorChannel *cursor_channel = (CursorChannel *)red_ref_channel(channel);
+    RedChannel *channel = &cursor_channel->common.base;
+
+    red_ref_channel(channel);
     red_channel_reset_send_data(channel);
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_CURSOR:
@@ -8460,7 +8462,7 @@ static void cursor_channel_push(RedWorker *worker)
     PipeItem *pipe_item;
 
     while ((pipe_item = red_pipe_get((RedChannel *)worker->cursor_channel))) {
-        cursor_channel_send_item((RedChannel *)worker->cursor_channel, pipe_item);
+        cursor_channel_send_item(worker->cursor_channel, pipe_item);
     }
 }
 
commit bb7cbceb9796fc5673656fc38ab4746e2e86647b
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Nov 8 01:41:59 2010 +0200

    server/red_worker: match channel_release_pipe_item_proc to red_channel

diff --git a/server/red_worker.c b/server/red_worker.c
index e692e82..49dcad1 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -350,7 +350,7 @@ typedef struct LocalCursor {
 typedef struct RedChannel RedChannel;
 typedef void (*channel_disconnect_proc)(RedChannel *channel);
 typedef void (*channel_hold_pipe_item_proc)(RedChannel *channel, PipeItem *item);
-typedef void (*channel_release_pipe_item_proc)(RedChannel *channel, void *item);
+typedef void (*channel_release_pipe_item_proc)(RedChannel *channel, PipeItem *item, int item_pushed);
 typedef int (*channel_handle_parsed_proc)(RedChannel *channel, uint32_t size, uint16_t type, void *message);
 
 struct RedChannel {
@@ -1845,7 +1845,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->common.base.release_item(&worker->display_channel->common.base, tmp_item);
+            worker->display_channel->common.base.release_item(
+                &worker->display_channel->common.base, tmp_item, FALSE);
             worker->display_channel->common.base.pipe_size--;
 
             if (!item) {
@@ -7331,7 +7332,7 @@ static void inline channel_release_res(RedChannel *channel)
     if (!channel->send_data.item) {
         return;
     }
-    channel->release_item(channel, channel->send_data.item);
+    channel->release_item(channel, channel->send_data.item, FALSE);
     channel->send_data.item = NULL;
 }
 
@@ -7345,7 +7346,7 @@ static void red_send_data(RedChannel *channel)
         if (!n) {
             channel->send_data.blocked = FALSE;
             if (channel->send_data.item) {
-                channel->release_item(channel, channel->send_data.item);
+                channel->release_item(channel, channel->send_data.item, FALSE);
                 channel->send_data.item = NULL;
             }
             break;
@@ -9458,12 +9459,12 @@ static void display_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
     }
 }
 
-static void display_channel_release_item(RedChannel *channel, void *item)
+static void display_channel_release_item(RedChannel *channel, PipeItem *item, int item_pushed /* ignored */)
 {
     CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
 
     ASSERT(item);
-    switch (((PipeItem *)item)->type) {
+    switch (item->type) {
     case PIPE_ITEM_TYPE_DRAW:
     case PIPE_ITEM_TYPE_STREAM_CREATE:
         release_drawable(common->worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
@@ -9601,12 +9602,12 @@ static void cursor_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
     ((CursorItem *)item)->refs++;
 }
 
-static void cursor_channel_release_item(RedChannel *channel, void *item)
+static void cursor_channel_release_item(RedChannel *channel, PipeItem *item, int item_pushed)
 {
     CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
 
     ASSERT(item);
-    red_release_cursor(common->worker, item);
+    red_release_cursor(common->worker, SPICE_CONTAINEROF(item, CursorItem, pipe_data));
 }
 
 static void red_connect_cursor(RedWorker *worker, RedsStreamContext *peer, int migrate)
@@ -9755,7 +9756,7 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
         }
     }
 
-    channel->release_item(channel, item);
+    channel->release_item(channel, item, FALSE);
     red_unref_channel(channel);
 }
 
commit 53f5cf43ce6c498831014735406732c76cd80c5e
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 19:44:39 2010 +0200

    server/red_worker: introduce an outgoing struct around out_bytes_counter

diff --git a/server/red_worker.c b/server/red_worker.c
index 2cf3031..e692e82 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -391,7 +391,9 @@ struct RedChannel {
     channel_handle_parsed_proc handle_parsed;
 
 #ifdef RED_STATISTICS
-    uint64_t *out_bytes_counter;
+    struct {
+        uint64_t *out_bytes_counter;
+    } outgoing;
 #endif
 };
 
@@ -7368,7 +7370,7 @@ static void red_send_data(RedChannel *channel)
             }
         } else {
             channel->send_data.pos += n;
-            stat_inc_counter(channel->out_bytes_counter, n);
+            stat_inc_counter(channel->outgoing.out_bytes_counter, n);
         }
     }
 }
@@ -9498,7 +9500,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->common.base.out_bytes_counter = stat_add_counter(display_channel->stat,
+    display_channel->common.base.outgoing.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);
@@ -9624,7 +9626,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->common.base.out_bytes_counter = stat_add_counter(channel->stat, "out_bytes", TRUE);
+    channel->common.base.outgoing.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;
commit d7521edac125cee5c95c7a1e27bf1866bdb2519d
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 19:24:41 2010 +0200

    server/red_worker: renames to add channel_ prefix and consistent sig
    
    s/disconnect_channel_proc/channel_disconnect_proc/
    s/release_item_proc/channel_release_pipe_item_proc/
    s/handle_message_proc/channel_handle_parsed_proc/
    
    Adds RedChannel* channel as first parameter to hold_pipe_item_proc

diff --git a/server/red_worker.c b/server/red_worker.c
index 1574b99..2cf3031 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -348,10 +348,10 @@ typedef struct LocalCursor {
 #define PALETTE_CACHE_HASH_KEY(id) ((id) & PALETTE_CACHE_HASH_MASK)
 
 typedef struct RedChannel RedChannel;
-typedef void (*disconnect_channel_proc)(RedChannel *channel);
-typedef void (*hold_pipe_item_proc)(PipeItem *item);
-typedef void (*release_item_proc)(RedChannel *channel, void *item);
-typedef int (*handle_message_proc)(RedChannel *channel, size_t size, uint32_t type, void *message);
+typedef void (*channel_disconnect_proc)(RedChannel *channel);
+typedef void (*channel_hold_pipe_item_proc)(RedChannel *channel, PipeItem *item);
+typedef void (*channel_release_pipe_item_proc)(RedChannel *channel, void *item);
+typedef int (*channel_handle_parsed_proc)(RedChannel *channel, uint32_t size, uint16_t type, void *message);
 
 struct RedChannel {
     spice_parse_channel_func_t parser;
@@ -385,10 +385,11 @@ struct RedChannel {
         uint8_t *end;
     } recive_data;
 
-    disconnect_channel_proc disconnect;
-    hold_pipe_item_proc hold_item;
-    release_item_proc release_item;
-    handle_message_proc handle_message;
+    channel_disconnect_proc disconnect;
+    channel_hold_pipe_item_proc hold_item;
+    channel_release_pipe_item_proc release_item;
+    channel_handle_parsed_proc handle_parsed;
+
 #ifdef RED_STATISTICS
     uint64_t *out_bytes_counter;
 #endif
@@ -1179,7 +1180,7 @@ static void show_draw_item(RedWorker *worker, DrawItem *draw_item, const char *p
 static void red_channel_init_send_data(RedChannel *channel, uint16_t type, PipeItem *item)
 {
     if (item) {
-        channel->hold_item(item);
+        channel->hold_item(channel, item);
         ASSERT(channel->send_data.item == NULL);
         channel->send_data.item = item;
     }
@@ -8940,7 +8941,7 @@ static void on_new_display_channel(RedWorker *worker)
     }
 }
 
-static int channel_handle_message(RedChannel *channel, size_t size, uint32_t type, void *message)
+static int channel_handle_message(RedChannel *channel, uint32_t size, uint16_t type, void *message)
 {
     switch (type) {
     case SPICE_MSGC_ACK_SYNC:
@@ -9247,7 +9248,7 @@ static int display_channel_handle_migrate_data(DisplayChannel *channel, size_t s
     return TRUE;
 }
 
-static int display_channel_handle_message(RedChannel *channel, size_t size, uint32_t type, void *message)
+static int display_channel_handle_message(RedChannel *channel, uint32_t size, uint16_t type, void *message)
 {
     switch (type) {
     case SPICE_MSGC_DISPLAY_INIT:
@@ -9315,7 +9316,7 @@ static void red_receive(RedChannel *channel)
                     return;
                 }
 
-                if (!channel->handle_message(channel, parsed_size, header->type, parsed)) {
+                if (!channel->handle_parsed(channel, parsed_size, header->type, parsed)) {
                     free(parsed);
                     channel->disconnect(channel);
                     return;
@@ -9348,10 +9349,10 @@ static void free_common_channel_from_listener(EventListener *ctx)
 static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id,
                                  RedsStreamContext *peer, int migrate,
                                  event_listener_action_proc handler,
-                                 disconnect_channel_proc disconnect,
-                                 hold_pipe_item_proc hold_item,
-                                 release_item_proc release_item,
-                                 handle_message_proc handle_message)
+                                 channel_disconnect_proc disconnect,
+                                 channel_hold_pipe_item_proc hold_item,
+                                 channel_release_pipe_item_proc release_item,
+                                 channel_handle_parsed_proc handle_parsed)
 {
     struct epoll_event event;
     RedChannel *channel;
@@ -9386,7 +9387,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     channel->disconnect = disconnect;
     channel->hold_item = hold_item;
     channel->release_item = release_item;
-    channel->handle_message = handle_message;
+    channel->handle_parsed = handle_parsed;
     channel->peer = peer;
     common->worker = worker;
     channel->ack_data.messages_window = ~0;  // blocks send message (maybe use send_data.blocked +
@@ -9433,7 +9434,7 @@ static void handle_channel_events(EventListener *in_listener, uint32_t events)
     }
 }
 
-static void display_channel_hold_pipe_item(PipeItem *item)
+static void display_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
 {
     ASSERT(item);
     switch (item->type) {
@@ -9592,7 +9593,7 @@ static void on_new_cursor_channel(RedWorker *worker)
     }
 }
 
-static void cursor_channel_hold_pipe_item(PipeItem *item)
+static void cursor_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
 {
     ASSERT(item);
     ((CursorItem *)item)->refs++;
@@ -9725,7 +9726,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);
+    channel->hold_item(channel, item);
 
     end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
 
commit f8d3345ef71ffb429c68d7bbd863204264ef3c8d
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 19:11:10 2010 +0200

    server/red_worker: split cursor_channel_send_item
    
    Split from cursor_channel_push

diff --git a/server/red_worker.c b/server/red_worker.c
index e8849a7..1574b99 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8407,53 +8407,56 @@ static void display_channel_push(RedWorker *worker)
     }
 }
 
+static void cursor_channel_send_item(RedChannel *channel, PipeItem *pipe_item)
+{
+    CursorChannel *cursor_channel = (CursorChannel *)red_ref_channel(channel);
+    red_channel_reset_send_data(channel);
+    switch (pipe_item->type) {
+    case PIPE_ITEM_TYPE_CURSOR:
+        red_send_cursor(cursor_channel, (CursorItem *)pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_LOCAL_CURSOR:
+        red_send_local_cursor(cursor_channel, (LocalCursor *)pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_INVAL_ONE:
+        red_cursor_send_inval(cursor_channel, (CacheItem *)pipe_item);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_VERB:
+        red_send_verb(channel, ((VerbItem*)pipe_item)->verb);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_MIGRATE:
+        red_printf("PIPE_ITEM_TYPE_MIGRATE");
+        cursor_channel_send_migrate(cursor_channel);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_SET_ACK:
+        red_send_set_ack(channel);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_CURSOR_INIT:
+        red_reset_cursor_cache(cursor_channel);
+        red_send_cursor_init(cursor_channel);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
+        red_reset_cursor_cache(cursor_channel);
+        red_send_verb(channel, SPICE_MSG_CURSOR_INVAL_ALL);
+        free(pipe_item);
+        break;
+    default:
+        red_error("invalid pipe item type");
+    }
+    red_unref_channel(channel);
+}
+
 static void cursor_channel_push(RedWorker *worker)
 {
     PipeItem *pipe_item;
 
     while ((pipe_item = red_pipe_get((RedChannel *)worker->cursor_channel))) {
-        CursorChannel *cursor_channel;
-
-        cursor_channel = (CursorChannel *)red_ref_channel((RedChannel *)worker->cursor_channel);
-        red_channel_reset_send_data((RedChannel*)cursor_channel);
-        switch (pipe_item->type) {
-        case PIPE_ITEM_TYPE_CURSOR:
-            red_send_cursor(cursor_channel, (CursorItem *)pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_LOCAL_CURSOR:
-            red_send_local_cursor(cursor_channel, (LocalCursor *)pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_INVAL_ONE:
-            red_cursor_send_inval(cursor_channel, (CacheItem *)pipe_item);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_VERB:
-            red_send_verb((RedChannel *)cursor_channel, ((VerbItem*)pipe_item)->verb);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_MIGRATE:
-            red_printf("PIPE_ITEM_TYPE_MIGRATE");
-            cursor_channel_send_migrate(cursor_channel);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_SET_ACK:
-            red_send_set_ack((RedChannel *)cursor_channel);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_CURSOR_INIT:
-            red_reset_cursor_cache(cursor_channel);
-            red_send_cursor_init(cursor_channel);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
-            red_reset_cursor_cache(cursor_channel);
-            red_send_verb((RedChannel *)cursor_channel, SPICE_MSG_CURSOR_INVAL_ALL);
-            free(pipe_item);
-            break;
-        default:
-            red_error("invalid pipe item type");
-        }
-        red_unref_channel((RedChannel *)cursor_channel);
+        cursor_channel_send_item((RedChannel *)worker->cursor_channel, pipe_item);
     }
 }
 
commit 67b3bf20d02bd9045776e3e1a22c20feee19e599
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 18:58:50 2010 +0200

    server/red_worker: use red_channel begin_send_message
    
    s/red_begin_send_message/red_channel_begin_send_message/

diff --git a/server/red_worker.c b/server/red_worker.c
index f306203..e8849a7 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -976,7 +976,7 @@ static void red_display_release_stream(DisplayChannel *display, StreamAgent *age
 static inline void red_detach_stream(RedWorker *worker, Stream *stream);
 static void red_stop_stream(RedWorker *worker, Stream *stream);
 static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate, Drawable *sect);
-static inline void red_begin_send_message(RedChannel *channel);
+static inline void red_channel_begin_send_message(RedChannel *channel);
 static inline void display_begin_send_message(DisplayChannel *channel);
 static void red_receive(RedChannel *channel);
 static void red_release_pixmap_cache(DisplayChannel *channel);
@@ -7396,7 +7396,7 @@ static void display_channel_push_release(DisplayChannel *channel, uint8_t type,
     free_list->res->resources[free_list->res->count++].id = id;
 }
 
-static inline void red_begin_send_message(RedChannel *channel)
+static inline void red_channel_begin_send_message(RedChannel *channel)
 {
     spice_marshaller_flush(channel->send_data.marshaller);
     channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
@@ -7453,7 +7453,7 @@ static inline void display_begin_send_message(DisplayChannel *channel)
         spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m));
         channel->common.base.send_data.header->sub_list = spice_marshaller_get_offset(sub_list_m);
     }
-    red_begin_send_message((RedChannel *)channel);
+    red_channel_begin_send_message((RedChannel *)channel);
 }
 
 static inline RedChannel *red_ref_channel(RedChannel *channel)
@@ -7769,14 +7769,14 @@ static void red_send_set_ack(RedChannel *channel)
 
     spice_marshall_msg_set_ack(channel->send_data.marshaller, &ack);
 
-    red_begin_send_message(channel);
+    red_channel_begin_send_message(channel);
 }
 
 static inline void red_send_verb(RedChannel *channel, uint16_t verb)
 {
     ASSERT(channel);
     red_channel_init_send_data(channel, verb, NULL);
-    red_begin_send_message(channel);
+    red_channel_begin_send_message(channel);
 }
 
 static inline void display_send_verb(DisplayChannel *channel, uint16_t verb)
@@ -7799,7 +7799,7 @@ static inline void __red_send_inval(RedChannel *channel, CacheItem *cach_item)
 static void red_send_inval(RedChannel *channel, CacheItem *cach_item)
 {
     __red_send_inval(channel, cach_item);
-    red_begin_send_message(channel);
+    red_channel_begin_send_message(channel);
 }
 
 static void red_display_send_inval(DisplayChannel *display_channel, CacheItem *cach_item)
@@ -8158,7 +8158,7 @@ static void red_send_cursor_init(CursorChannel *channel)
     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->common.base);
+    red_channel_begin_send_message(&channel->common.base);
 }
 
 static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cursor)
@@ -8179,7 +8179,7 @@ static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cu
     spice_marshall_msg_cursor_set(channel->send_data.marshaller, &cursor_set);
     add_buf_from_info(channel, channel->send_data.marshaller, &info);
 
-    red_begin_send_message(channel);
+    red_channel_begin_send_message(channel);
 
     red_release_cursor(worker, (CursorItem *)cursor);
 }
@@ -8192,7 +8192,7 @@ static void cursor_channel_send_migrate(CursorChannel *cursor_channel)
     migrate.flags = 0;
 
     spice_marshall_msg_migrate(cursor_channel->common.base.send_data.marshaller, &migrate);
-    red_begin_send_message((RedChannel*)cursor_channel);
+    red_channel_begin_send_message((RedChannel*)cursor_channel);
 }
 
 static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
@@ -8249,7 +8249,7 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
         red_error("bad cursor command %d", cmd->type);
     }
 
-    red_begin_send_message(channel);
+    red_channel_begin_send_message(channel);
 
     red_release_cursor(cursor_channel->common.worker, cursor);
 }
@@ -8266,7 +8266,7 @@ static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCrea
 
     spice_marshall_msg_display_surface_create(channel->send_data.marshaller, surface_create);
 
-    red_begin_send_message(channel);
+    red_channel_begin_send_message(channel);
 }
 
 static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_id)
@@ -8284,7 +8284,7 @@ static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_i
 
     spice_marshall_msg_display_surface_destroy(channel->send_data.marshaller, &surface_destroy);
 
-    red_begin_send_message(channel);
+    red_channel_begin_send_message(channel);
 }
 
 static inline PipeItem *red_pipe_get(RedChannel *channel)
commit 7d53a51da0943c71f190c64bf629b4b3f0d27e03
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 18:51:03 2010 +0200

    server/red_worker: add red_channel_init_send_data
    
    Changes semantics of send to always hold/release regardless of block, like
    red_channel. A hold is just a reference count increment or nop.

diff --git a/server/red_worker.c b/server/red_worker.c
index 6765d0f..f306203 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -976,8 +976,8 @@ static void red_display_release_stream(DisplayChannel *display, StreamAgent *age
 static inline void red_detach_stream(RedWorker *worker, Stream *stream);
 static void red_stop_stream(RedWorker *worker, Stream *stream);
 static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate, Drawable *sect);
-static inline void red_begin_send_message(RedChannel *channel, void *item);
-static inline void display_begin_send_message(DisplayChannel *channel, void *item);
+static inline void red_begin_send_message(RedChannel *channel);
+static inline void display_begin_send_message(DisplayChannel *channel);
 static void red_receive(RedChannel *channel);
 static void red_release_pixmap_cache(DisplayChannel *channel);
 static void red_release_glz(DisplayChannel *channel);
@@ -1176,6 +1176,16 @@ static void show_draw_item(RedWorker *worker, DrawItem *draw_item, const char *p
            draw_item->base.rgn.extents.y2);
 }
 
+static void red_channel_init_send_data(RedChannel *channel, uint16_t type, PipeItem *item)
+{
+    if (item) {
+        channel->hold_item(item);
+        ASSERT(channel->send_data.item == NULL);
+        channel->send_data.item = item;
+    }
+    channel->send_data.header->type = type;
+}
+
 static inline void red_pipe_item_init(PipeItem *item, int type)
 {
     ring_item_init(&item->link);
@@ -6449,9 +6459,8 @@ static void red_send_qxl_draw_fill(RedWorker *worker,
     SpiceMarshaller *mask_bitmap_out;
     SpiceFill fill;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_FILL, &item->pipe_item);
     fill_base(display_channel, item);
-
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_FILL;
     fill = drawable->u.fill;
     spice_marshall_Fill(channel->send_data.marshaller,
                         &fill,
@@ -6498,7 +6507,7 @@ static void red_lossy_send_qxl_draw_fill(RedWorker *worker,
 
         red_send_qxl_draw_fill(worker, display_channel, item);
 
-        // eitehr the brush operation is opaque, or the dest is not lossy
+        // either the brush operation is opaque, or the dest is not lossy
         surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
     } else {
         int resend_surface_ids[2];
@@ -6534,9 +6543,8 @@ static FillBitsType red_send_qxl_draw_opaque(RedWorker *worker,
     SpiceOpaque opaque;
     FillBitsType src_send_type;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_OPAQUE, &item->pipe_item);
     fill_base(display_channel, item);
-
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_OPAQUE;
     opaque = drawable->u.opaque;
     spice_marshall_Opaque(channel->send_data.marshaller,
                           &opaque,
@@ -6630,10 +6638,8 @@ static FillBitsType red_send_qxl_draw_copy(RedWorker *worker,
     SpiceCopy copy;
     FillBitsType src_send_type;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_COPY, &item->pipe_item);
     fill_base(display_channel, item);
-
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_COPY;
-
     copy = drawable->u.copy;
     spice_marshall_Copy(channel->send_data.marshaller,
                         &copy,
@@ -6680,8 +6686,8 @@ static void red_send_qxl_draw_transparent(RedWorker *worker,
     SpiceMarshaller *src_bitmap_out;
     SpiceTransparent transparent;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_TRANSPARENT, &item->pipe_item);
     fill_base(display_channel, item);
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_TRANSPARENT;
     transparent = drawable->u.transparent;
     spice_marshall_Transparent(channel->send_data.marshaller,
                                &transparent,
@@ -6727,8 +6733,8 @@ static FillBitsType red_send_qxl_draw_alpha_blend(RedWorker *worker,
     SpiceAlphaBlend alpha_blend;
     FillBitsType src_send_type;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND, &item->pipe_item);
     fill_base(display_channel, item);
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND;
     alpha_blend = drawable->u.alpha_blend;
     spice_marshall_AlphaBlend(channel->send_data.marshaller,
                               &alpha_blend,
@@ -6771,8 +6777,8 @@ static void red_send_qxl_copy_bits(RedWorker *worker,
     RedDrawable *drawable = item->red_drawable;
     SpicePoint copy_bits;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_COPY_BITS, &item->pipe_item);
     fill_base(display_channel, item);
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_COPY_BITS;
     copy_bits = drawable->u.copy_bits.src_pos;
     spice_marshall_Point(channel->send_data.marshaller,
                          &copy_bits);
@@ -6816,8 +6822,8 @@ static void red_send_qxl_draw_blend(RedWorker *worker,
     SpiceMarshaller *mask_bitmap_out;
     SpiceBlend blend;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_BLEND, &item->pipe_item);
     fill_base(display_channel, item);
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_BLEND;
     blend = drawable->u.blend;
     spice_marshall_Blend(channel->send_data.marshaller,
                          &blend,
@@ -6878,8 +6884,8 @@ static void red_send_qxl_draw_blackness(RedWorker *worker,
     SpiceMarshaller *mask_bitmap_out;
     SpiceBlackness blackness;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_BLACKNESS, &item->pipe_item);
     fill_base(display_channel, item);
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_BLACKNESS;
     blackness = drawable->u.blackness;
 
     spice_marshall_Blackness(channel->send_data.marshaller,
@@ -6910,8 +6916,8 @@ static void red_send_qxl_draw_whiteness(RedWorker *worker,
     SpiceMarshaller *mask_bitmap_out;
     SpiceWhiteness whiteness;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_WHITENESS, &item->pipe_item);
     fill_base(display_channel, item);
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_WHITENESS;
     whiteness = drawable->u.whiteness;
 
     spice_marshall_Whiteness(channel->send_data.marshaller,
@@ -6942,8 +6948,8 @@ static void red_send_qxl_draw_inverse(RedWorker *worker,
     RedChannel *channel = &display_channel->common.base;
     SpiceInvers inverse;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_INVERS, NULL);
     fill_base(display_channel, item);
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_INVERS;
     inverse = drawable->u.invers;
 
     spice_marshall_Invers(channel->send_data.marshaller,
@@ -6971,8 +6977,8 @@ static void red_send_qxl_draw_rop3(RedWorker *worker,
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *mask_bitmap_out;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_ROP3, &item->pipe_item);
     fill_base(display_channel, item);
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_ROP3;
     rop3 = drawable->u.rop3;
     spice_marshall_Rop3(channel->send_data.marshaller,
                         &rop3,
@@ -7052,9 +7058,8 @@ static void red_send_qxl_draw_stroke(RedWorker *worker,
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *style_out;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_STROKE, &item->pipe_item);
     fill_base(display_channel, item);
-
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_STROKE;
     stroke = drawable->u.stroke;
     spice_marshall_Stroke(channel->send_data.marshaller,
                           &stroke,
@@ -7131,9 +7136,8 @@ static void red_send_qxl_draw_text(RedWorker *worker,
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *back_brush_pat_out;
 
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_TEXT, &item->pipe_item);
     fill_base(display_channel, item);
-
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_TEXT;
     text = drawable->u.text;
     spice_marshall_Text(channel->send_data.marshaller,
                         &text,
@@ -7262,7 +7266,7 @@ static void red_lossy_send_qxl_drawable(RedWorker *worker, DisplayChannel *displ
 
     // a message is pending
     if (display_channel->common.base.send_data.header->type != 0) {
-        display_begin_send_message(display_channel, &item->pipe_item);
+        display_begin_send_message(display_channel);
     }
 }
 
@@ -7314,7 +7318,7 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
     default:
         red_error("invalid type");
     }
-    display_begin_send_message(display_channel, &item->pipe_item);
+    display_begin_send_message(display_channel);
 }
 
 #define MAX_SEND_VEC 100
@@ -7328,7 +7332,7 @@ static void inline channel_release_res(RedChannel *channel)
     channel->send_data.item = NULL;
 }
 
-static void red_send_data(RedChannel *channel, void *item)
+static void red_send_data(RedChannel *channel)
 {
     for (;;) {
         uint32_t n = channel->send_data.size - channel->send_data.pos;
@@ -7350,10 +7354,6 @@ static void red_send_data(RedChannel *channel, void *item)
             switch (errno) {
             case EAGAIN:
                 channel->send_data.blocked = TRUE;
-                if (item) {
-                    channel->hold_item(item);
-                    channel->send_data.item = item;
-                }
                 return;
             case EINTR:
                 break;
@@ -7396,17 +7396,17 @@ static void display_channel_push_release(DisplayChannel *channel, uint8_t type,
     free_list->res->resources[free_list->res->count++].id = id;
 }
 
-static inline void red_begin_send_message(RedChannel *channel, void *item)
+static inline void red_begin_send_message(RedChannel *channel)
 {
     spice_marshaller_flush(channel->send_data.marshaller);
     channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
     channel->send_data.header->size =  channel->send_data.size - sizeof(SpiceDataHeader);
     channel->ack_data.messages_window++;
     channel->send_data.header = NULL; /* avoid writing to this until we have a new message */
-    red_send_data(channel, item);
+    red_send_data(channel);
 }
 
-static inline void display_begin_send_message(DisplayChannel *channel, void *item)
+static inline void display_begin_send_message(DisplayChannel *channel)
 {
     FreeList *free_list = &channel->send_data.free_list;
 
@@ -7453,7 +7453,7 @@ static inline void display_begin_send_message(DisplayChannel *channel, void *ite
         spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m));
         channel->common.base.send_data.header->sub_list = spice_marshaller_get_offset(sub_list_m);
     }
-    red_begin_send_message((RedChannel *)channel, item);
+    red_begin_send_message((RedChannel *)channel);
 }
 
 static inline RedChannel *red_ref_channel(RedChannel *channel)
@@ -7729,7 +7729,7 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
         red_display_share_stream_buf(display_channel);
     }
 
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_DATA;
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_STREAM_DATA, NULL);
 
     SpiceMsgDisplayStreamData stream_data;
 
@@ -7740,7 +7740,7 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
     spice_marshaller_add_ref(channel->send_data.marshaller,
                              display_channel->send_data.stream_outbuf, n);
 
-    display_begin_send_message(display_channel, NULL);
+    display_begin_send_message(display_channel);
     agent->lats_send_time = time_now;
     return TRUE;
 }
@@ -7762,35 +7762,35 @@ static void red_send_set_ack(RedChannel *channel)
     SpiceMsgSetAck ack;
 
     ASSERT(channel);
-    channel->send_data.header->type = SPICE_MSG_SET_ACK;
+    red_channel_init_send_data(channel, SPICE_MSG_SET_ACK, NULL);
     ack.generation = ++channel->ack_data.generation;
     ack.window = channel->ack_data.client_window;
     channel->ack_data.messages_window = 0;
 
     spice_marshall_msg_set_ack(channel->send_data.marshaller, &ack);
 
-    red_begin_send_message(channel, NULL);
+    red_begin_send_message(channel);
 }
 
 static inline void red_send_verb(RedChannel *channel, uint16_t verb)
 {
     ASSERT(channel);
-    channel->send_data.header->type = verb;
-    red_begin_send_message(channel, NULL);
+    red_channel_init_send_data(channel, verb, NULL);
+    red_begin_send_message(channel);
 }
 
 static inline void display_send_verb(DisplayChannel *channel, uint16_t verb)
 {
     ASSERT(channel);
-    channel->common.base.send_data.header->type = verb;
-    display_begin_send_message(channel, NULL);
+    red_channel_init_send_data(&channel->common.base, verb, NULL);
+    display_begin_send_message(channel);
 }
 
 static inline void __red_send_inval(RedChannel *channel, CacheItem *cach_item)
 {
     SpiceMsgDisplayInvalOne inval_one;
 
-    channel->send_data.header->type = cach_item->inval_type;
+    red_channel_init_send_data(channel, cach_item->inval_type, NULL);
     inval_one.id = *(uint64_t *)&cach_item->id;
 
     spice_marshall_msg_cursor_inval_one(channel->send_data.marshaller, &inval_one);
@@ -7799,31 +7799,31 @@ static inline void __red_send_inval(RedChannel *channel, CacheItem *cach_item)
 static void red_send_inval(RedChannel *channel, CacheItem *cach_item)
 {
     __red_send_inval(channel, cach_item);
-    red_begin_send_message(channel, NULL);
+    red_begin_send_message(channel);
 }
 
 static void red_display_send_inval(DisplayChannel *display_channel, CacheItem *cach_item)
 {
     __red_send_inval((RedChannel *)display_channel, cach_item);
-    display_begin_send_message(display_channel, NULL);
+    display_begin_send_message(display_channel);
 }
 
 static void display_channel_send_migrate(DisplayChannel *display_channel)
 {
     SpiceMsgMigrate migrate;
 
-    display_channel->common.base.send_data.header->type = SPICE_MSG_MIGRATE;
+    red_channel_init_send_data(&display_channel->common.base, SPICE_MSG_MIGRATE, NULL);
     migrate.flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
     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);
+    display_begin_send_message(display_channel);
 }
 
 static void display_channel_send_migrate_data(DisplayChannel *display_channel)
 {
     DisplayChannelMigrateData display_data;
 
-    display_channel->common.base.send_data.header->type = SPICE_MSG_MIGRATE_DATA;
+    red_channel_init_send_data(&display_channel->common.base, SPICE_MSG_MIGRATE_DATA, NULL);
 
     ASSERT(display_channel->pixmap_cache);
     display_data.magic = DISPLAY_MIGRATE_DATA_MAGIC;
@@ -7847,7 +7847,7 @@ static void display_channel_send_migrate_data(DisplayChannel *display_channel)
 
     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);
+    display_begin_send_message(display_channel);
 }
 
 static void display_channel_pixmap_sync(DisplayChannel *display_channel)
@@ -7856,7 +7856,7 @@ static void display_channel_pixmap_sync(DisplayChannel *display_channel)
     PixmapCache *pixmap_cache;
 
 
-    display_channel->common.base.send_data.header->type = SPICE_MSG_WAIT_FOR_CHANNELS;
+    red_channel_init_send_data(&display_channel->common.base, SPICE_MSG_WAIT_FOR_CHANNELS, NULL);
     pixmap_cache = display_channel->pixmap_cache;
 
 
@@ -7873,19 +7873,19 @@ static void display_channel_pixmap_sync(DisplayChannel *display_channel)
 
     spice_marshall_msg_wait_for_channels(display_channel->common.base.send_data.marshaller, &wait);
 
-    display_begin_send_message(display_channel, NULL);
+    display_begin_send_message(display_channel);
 }
 
 static void display_channel_reset_cache(DisplayChannel *display_channel)
 {
     SpiceMsgWaitForChannels wait;
 
-    display_channel->common.base.send_data.header->type = SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS;
+    red_channel_init_send_data(&display_channel->common.base, SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS, NULL);
     pixmap_cache_reset(display_channel->pixmap_cache, display_channel, &wait);
 
     spice_marshall_msg_display_inval_all_pixmaps(display_channel->common.base.send_data.marshaller,
                                                  &wait);
-    display_begin_send_message(display_channel, NULL);
+    display_begin_send_message(display_channel);
 }
 
 static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
@@ -7928,7 +7928,7 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     chunks = spice_chunks_new_linear(item->data, bitmap.stride * bitmap.y);
     bitmap.data = chunks;
 
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_COPY;
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_COPY, &item->link);
 
     copy.base.surface_id = item->surface_id;
     copy.base.box.left = item->pos.x;
@@ -8021,7 +8021,7 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
                                  bitmap.y * bitmap.stride);
         region_remove(surface_lossy_region, &copy.base.box);
     }
-    display_begin_send_message(display_channel, &item->link);
+    display_begin_send_message(display_channel);
 
     spice_chunks_destroy(chunks);
 }
@@ -8036,7 +8036,7 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
     ASSERT(display_channel && item && item->drawable);
     channel = &display_channel->common.base;
 
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_DRAW_COPY;
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_DRAW_COPY, &item->base);
 
     red_drawable = item->drawable->red_drawable;
     ASSERT(red_drawable->type == QXL_DRAW_COPY);
@@ -8056,7 +8056,7 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
 
     fill_bits(display_channel, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE);
 
-    display_begin_send_message(display_channel, &item->base);
+    display_begin_send_message(display_channel);
 }
 
 static void red_display_send_stream_start(DisplayChannel *display_channel, StreamAgent *agent)
@@ -8066,7 +8066,8 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea
 
     agent->lats_send_time = 0;
     ASSERT(stream);
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_CREATE;
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_STREAM_CREATE,
+        stream->current ? &stream->current->pipe_item : NULL);
     SpiceMsgDisplayStreamCreate stream_create;
     SpiceClipRects clip_rects;
 
@@ -8093,11 +8094,7 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea
     spice_marshall_msg_display_stream_create(channel->send_data.marshaller, &stream_create);
 
 
-    if (stream->current) {
-        display_begin_send_message(display_channel, &stream->current->pipe_item);
-    } else {
-        display_begin_send_message(display_channel, NULL);
-    }
+    display_begin_send_message(display_channel);
 }
 
 static void red_display_send_stream_clip(DisplayChannel *display_channel,
@@ -8110,7 +8107,7 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
 
     ASSERT(stream);
 
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_CLIP;
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_STREAM_CLIP, &item->base);
     SpiceMsgDisplayStreamClip stream_clip;
 
     stream_clip.id = agent - display_channel->stream_agents;
@@ -8119,7 +8116,7 @@ static void red_display_send_stream_clip(DisplayChannel *display_channel,
 
     spice_marshall_msg_display_stream_clip(channel->send_data.marshaller, &stream_clip);
 
-    display_begin_send_message(display_channel, item);
+    display_begin_send_message(display_channel);
 }
 
 static void red_display_send_stream_end(DisplayChannel *display_channel, StreamAgent* agent)
@@ -8127,12 +8124,12 @@ static void red_display_send_stream_end(DisplayChannel *display_channel, StreamA
     RedChannel *channel = &display_channel->common.base;
     SpiceMsgDisplayStreamDestroy destroy;
 
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_STREAM_DESTROY;
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL);
     destroy.id = agent - display_channel->stream_agents;
 
     spice_marshall_msg_display_stream_destroy(channel->send_data.marshaller, &destroy);
 
-    display_begin_send_message(display_channel, NULL);
+    display_begin_send_message(display_channel);
 }
 
 static void red_cursor_send_inval(CursorChannel *channel, CacheItem *cach_item)
@@ -8151,7 +8148,7 @@ static void red_send_cursor_init(CursorChannel *channel)
 
     worker = channel->common.worker;
 
-    channel->common.base.send_data.header->type = SPICE_MSG_CURSOR_INIT;
+    red_channel_init_send_data(&channel->common.base, SPICE_MSG_CURSOR_INIT, &worker->cursor->pipe_data);
     msg.visible = worker->cursor_visible;
     msg.position = worker->cursor_position;
     msg.trail_length = worker->cursor_trail_length;
@@ -8161,7 +8158,7 @@ static void red_send_cursor_init(CursorChannel *channel)
     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->common.base, worker->cursor);
+    red_begin_send_message(&channel->common.base);
 }
 
 static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cursor)
@@ -8174,7 +8171,7 @@ static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cu
     ASSERT(cursor_channel);
     worker = cursor_channel->common.worker;
     channel = &cursor_channel->common.base;
-    channel->send_data.header->type = SPICE_MSG_CURSOR_SET;
+    red_channel_init_send_data(channel, SPICE_MSG_CURSOR_SET, &cursor->base.pipe_data);
     cursor_set.position = cursor->position;
     cursor_set.visible = worker->cursor_visible;
 
@@ -8182,7 +8179,7 @@ static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cu
     spice_marshall_msg_cursor_set(channel->send_data.marshaller, &cursor_set);
     add_buf_from_info(channel, channel->send_data.marshaller, &info);
 
-    red_begin_send_message(channel, cursor);
+    red_begin_send_message(channel);
 
     red_release_cursor(worker, (CursorItem *)cursor);
 }
@@ -8191,11 +8188,11 @@ static void cursor_channel_send_migrate(CursorChannel *cursor_channel)
 {
     SpiceMsgMigrate migrate;
 
-    cursor_channel->common.base.send_data.header->type = SPICE_MSG_MIGRATE;
+    red_channel_init_send_data(&cursor_channel->common.base, SPICE_MSG_MIGRATE, NULL);
     migrate.flags = 0;
 
     spice_marshall_msg_migrate(cursor_channel->common.base.send_data.marshaller, &migrate);
-    red_begin_send_message((RedChannel*)cursor_channel, NULL);
+    red_begin_send_message((RedChannel*)cursor_channel);
 }
 
 static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
@@ -8216,7 +8213,7 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
     case QXL_CURSOR_MOVE:
         {
             SpiceMsgCursorMove cursor_move;
-            channel->send_data.header->type = SPICE_MSG_CURSOR_MOVE;
+            red_channel_init_send_data(channel, SPICE_MSG_CURSOR_MOVE, &cursor->pipe_data);
             cursor_move.position = cmd->u.position;
             spice_marshall_msg_cursor_move(m, &cursor_move);
             break;
@@ -8226,7 +8223,7 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
             SpiceMsgCursorSet cursor_set;
             AddBufInfo info;
 
-            channel->send_data.header->type = SPICE_MSG_CURSOR_SET;
+            red_channel_init_send_data(channel, SPICE_MSG_CURSOR_SET, &cursor->pipe_data);
             cursor_set.position = cmd->u.set.position;
             cursor_set.visible = worker->cursor_visible;
 
@@ -8236,13 +8233,13 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
             break;
         }
     case QXL_CURSOR_HIDE:
-        channel->send_data.header->type = SPICE_MSG_CURSOR_HIDE;
+        red_channel_init_send_data(channel, SPICE_MSG_CURSOR_HIDE, &cursor->pipe_data);
         break;
     case QXL_CURSOR_TRAIL:
         {
             SpiceMsgCursorTrail cursor_trail;
 
-            channel->send_data.header->type = SPICE_MSG_CURSOR_TRAIL;
+            red_channel_init_send_data(channel, SPICE_MSG_CURSOR_TRAIL, &cursor->pipe_data);
             cursor_trail.length = cmd->u.trail.length;
             cursor_trail.frequency = cmd->u.trail.frequency;
             spice_marshall_msg_cursor_trail(m, &cursor_trail);
@@ -8252,7 +8249,7 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
         red_error("bad cursor command %d", cmd->type);
     }
 
-    red_begin_send_message(channel, cursor);
+    red_begin_send_message(channel);
 
     red_release_cursor(cursor_channel->common.worker, cursor);
 }
@@ -8265,11 +8262,11 @@ static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCrea
     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;
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_SURFACE_CREATE, NULL);
 
     spice_marshall_msg_display_surface_create(channel->send_data.marshaller, surface_create);
 
-    red_begin_send_message(channel, NULL);
+    red_begin_send_message(channel);
 }
 
 static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_id)
@@ -8281,13 +8278,13 @@ static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_i
     channel = &display->common.base;
 
     region_destroy(&display->surface_client_lossy_region[surface_id]);
-    channel->send_data.header->type = SPICE_MSG_DISPLAY_SURFACE_DESTROY;
+    red_channel_init_send_data(channel, SPICE_MSG_DISPLAY_SURFACE_DESTROY, NULL);
 
     surface_destroy.surface_id = surface_id;
 
     spice_marshall_msg_display_surface_destroy(channel->send_data.marshaller, &surface_destroy);
 
-    red_begin_send_message(channel, NULL);
+    red_begin_send_message(channel);
 }
 
 static inline PipeItem *red_pipe_get(RedChannel *channel)
@@ -8810,7 +8807,7 @@ static inline void flush_display_commands(RedWorker *worker)
             RedChannel *channel = (RedChannel *)worker->display_channel;
             red_ref_channel(channel);
             red_receive(channel);
-            red_send_data(channel, NULL);
+            red_send_data(channel);
             if (red_now() >= end_time) {
                 red_printf("update timeout");
                 red_disconnect_display(channel);
@@ -8852,7 +8849,7 @@ static inline void flush_cursor_commands(RedWorker *worker)
             RedChannel *channel = (RedChannel *)worker->cursor_channel;
             red_ref_channel(channel);
             red_receive(channel);
-            red_send_data(channel, NULL);
+            red_send_data(channel);
             if (red_now() >= end_time) {
                 red_printf("flush cursor timeout");
                 red_disconnect_cursor(channel);
@@ -9429,7 +9426,7 @@ static void handle_channel_events(EventListener *in_listener, uint32_t events)
     }
 
     if (channel->send_data.blocked) {
-        red_send_data(channel, NULL);
+        red_send_data(channel);
     }
 }
 
@@ -9702,7 +9699,7 @@ static void red_wait_outgoing_item(RedChannel *channel)
     do {
         usleep(DETACH_SLEEP_DURATION);
         red_receive(channel);
-        red_send_data(channel, NULL);
+        red_send_data(channel);
     } while ((blocked = channel->send_data.blocked) && red_now() < end_time);
 
     if (blocked) {
@@ -9731,7 +9728,7 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
 
     if (channel->send_data.blocked) {
         red_receive(channel);
-        red_send_data(channel, NULL);
+        red_send_data(channel);
     }
     // todo: different push for each channel
     red_push(common->worker);
@@ -9739,7 +9736,7 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
     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_send_data(channel);
         red_push(common->worker);
     }
 
commit 859aa15806b23bbf31c8f342c65b7e4c70a6119b
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 16:24:15 2010 +0200

    server/red_worker: split display_channel_send_item
    
    Split it out of display_channel_push.

diff --git a/server/red_worker.c b/server/red_worker.c
index 0d75bb8..6765d0f 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8308,99 +8308,105 @@ static inline PipeItem *red_pipe_get(RedChannel *channel)
     return item;
 }
 
+static void display_channel_send_item(RedChannel *base, PipeItem *pipe_item)
+{
+    DisplayChannel *display_channel = (DisplayChannel *)red_ref_channel(base);
+    RedWorker *worker = display_channel->common.worker;
+
+    red_display_reset_send_data(display_channel);
+    switch (pipe_item->type) {
+    case PIPE_ITEM_TYPE_DRAW: {
+        Drawable *drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
+        send_qxl_drawable(display_channel, drawable);
+        release_drawable(worker, drawable);
+        break;
+    }
+    case PIPE_ITEM_TYPE_INVAL_ONE:
+        red_display_send_inval(display_channel, (CacheItem *)pipe_item);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_STREAM_CREATE: {
+        StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, create_item);
+        red_display_send_stream_start(display_channel, agent);
+        red_display_release_stream(display_channel, agent);
+        break;
+    }
+    case PIPE_ITEM_TYPE_STREAM_CLIP: {
+        StreamClipItem* clip_item = (StreamClipItem *)pipe_item;
+        red_display_send_stream_clip(display_channel, clip_item);
+        red_display_release_stream_clip(display_channel, clip_item);
+        break;
+    }
+    case PIPE_ITEM_TYPE_STREAM_DESTROY: {
+        StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, destroy_item);
+        red_display_send_stream_end(display_channel, agent);
+        red_display_release_stream(display_channel, agent);
+        break;
+    }
+    case PIPE_ITEM_TYPE_UPGRADE:
+        red_display_send_upgrade(display_channel, (UpgradeItem *)pipe_item);
+        release_upgrade_item(worker, (UpgradeItem *)pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_VERB:
+        display_send_verb(display_channel, ((VerbItem*)pipe_item)->verb);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_MIGRATE:
+        red_printf("PIPE_ITEM_TYPE_MIGRATE");
+        display_channel_send_migrate(display_channel);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_MIGRATE_DATA:
+        display_channel_send_migrate_data(display_channel);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_SET_ACK:
+        red_send_set_ack((RedChannel *)display_channel);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_IMAGE:
+        red_send_image(display_channel, (ImageItem *)pipe_item);
+        release_image_item((ImageItem *)pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_PIXMAP_SYNC:
+        display_channel_pixmap_sync(display_channel);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_PIXMAP_RESET:
+        display_channel_reset_cache(display_channel);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
+        red_reset_palette_cache(display_channel);
+        red_send_verb((RedChannel *)display_channel, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
+        free(pipe_item);
+        break;
+    case PIPE_ITEM_TYPE_CREATE_SURFACE: {
+        SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(pipe_item, SurfaceCreateItem,
+                                                              pipe_item);
+        red_send_surface_create(display_channel, &surface_create->surface_create);
+        free(surface_create);
+        break;
+    }
+    case PIPE_ITEM_TYPE_DESTROY_SURFACE: {
+        SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(pipe_item, SurfaceDestroyItem,
+                                                                pipe_item);
+        red_send_surface_destroy(display_channel, surface_destroy->surface_destroy.surface_id);
+        free(surface_destroy);
+        break;
+    }
+    default:
+        red_error("invalid pipe item type");
+    }
+    red_unref_channel((RedChannel *)display_channel);
+}
+
 static void display_channel_push(RedWorker *worker)
 {
     PipeItem *pipe_item;
 
     while ((pipe_item = red_pipe_get((RedChannel *)worker->display_channel))) {
-        DisplayChannel *display_channel;
-        display_channel = (DisplayChannel *)red_ref_channel((RedChannel *)worker->display_channel);
-        red_display_reset_send_data(display_channel);
-        switch (pipe_item->type) {
-        case PIPE_ITEM_TYPE_DRAW: {
-            Drawable *drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
-            send_qxl_drawable(display_channel, drawable);
-            release_drawable(worker, drawable);
-            break;
-        }
-        case PIPE_ITEM_TYPE_INVAL_ONE:
-            red_display_send_inval(display_channel, (CacheItem *)pipe_item);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_STREAM_CREATE: {
-            StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, create_item);
-            red_display_send_stream_start(display_channel, agent);
-            red_display_release_stream(display_channel, agent);
-            break;
-        }
-        case PIPE_ITEM_TYPE_STREAM_CLIP: {
-            StreamClipItem* clip_item = (StreamClipItem *)pipe_item;
-            red_display_send_stream_clip(display_channel, clip_item);
-            red_display_release_stream_clip(display_channel, clip_item);
-            break;
-        }
-        case PIPE_ITEM_TYPE_STREAM_DESTROY: {
-            StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, destroy_item);
-            red_display_send_stream_end(display_channel, agent);
-            red_display_release_stream(display_channel, agent);
-            break;
-        }
-        case PIPE_ITEM_TYPE_UPGRADE:
-            red_display_send_upgrade(display_channel, (UpgradeItem *)pipe_item);
-            release_upgrade_item(worker, (UpgradeItem *)pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_VERB:
-            display_send_verb(display_channel, ((VerbItem*)pipe_item)->verb);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_MIGRATE:
-            red_printf("PIPE_ITEM_TYPE_MIGRATE");
-            display_channel_send_migrate(display_channel);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_MIGRATE_DATA:
-            display_channel_send_migrate_data(display_channel);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_SET_ACK:
-            red_send_set_ack((RedChannel *)display_channel);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_IMAGE:
-            red_send_image(display_channel, (ImageItem *)pipe_item);
-            release_image_item((ImageItem *)pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_PIXMAP_SYNC:
-            display_channel_pixmap_sync(display_channel);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_PIXMAP_RESET:
-            display_channel_reset_cache(display_channel);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
-            red_reset_palette_cache(display_channel);
-            red_send_verb((RedChannel *)display_channel, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
-            free(pipe_item);
-            break;
-        case PIPE_ITEM_TYPE_CREATE_SURFACE: {
-            SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(pipe_item, SurfaceCreateItem,
-                                                                  pipe_item);
-            red_send_surface_create(display_channel, &surface_create->surface_create);
-            free(surface_create);
-            break;
-        }
-        case PIPE_ITEM_TYPE_DESTROY_SURFACE: {
-            SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(pipe_item, SurfaceDestroyItem,
-                                                                    pipe_item);
-            red_send_surface_destroy(display_channel, surface_destroy->surface_destroy.surface_id);
-            free(surface_destroy);
-            break;
-        }
-        default:
-            red_error("invalid pipe item type");
-        }
-        red_unref_channel((RedChannel *)display_channel);
+        display_channel_send_item((RedChannel *)worker->display_channel, pipe_item);
     }
 }
 
commit f8262c80ad9b8d01aba0ebe254335aec05516927
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 15:44:37 2010 +0200

    server/red_worker: extract common_release_pipe_item from red_pipe_clear

diff --git a/server/red_worker.c b/server/red_worker.c
index 8550a92..0d75bb8 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1354,63 +1354,69 @@ static void release_upgrade_item(RedWorker* worker, UpgradeItem *item)
     }
 }
 
+static void common_release_pipe_item(RedChannel *channel, PipeItem *item)
+{
+    CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
+
+    switch (item->type) {
+    case PIPE_ITEM_TYPE_DRAW:
+        release_drawable(common->worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
+        break;
+    case PIPE_ITEM_TYPE_CURSOR:
+        red_release_cursor(common->worker, (CursorItem *)item);
+        break;
+    case PIPE_ITEM_TYPE_UPGRADE:
+        release_upgrade_item(common->worker, (UpgradeItem *)item);
+        break;
+    case PIPE_ITEM_TYPE_PIXMAP_RESET:
+    case PIPE_ITEM_TYPE_PIXMAP_SYNC:
+    case PIPE_ITEM_TYPE_INVAL_ONE:
+    case PIPE_ITEM_TYPE_MIGRATE:
+    case PIPE_ITEM_TYPE_SET_ACK:
+    case PIPE_ITEM_TYPE_CURSOR_INIT:
+    case PIPE_ITEM_TYPE_VERB:
+    case PIPE_ITEM_TYPE_MIGRATE_DATA:
+    case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
+    case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
+        free(item);
+        break;
+    case PIPE_ITEM_TYPE_IMAGE:
+        release_image_item((ImageItem *)item);
+        break;
+    case PIPE_ITEM_TYPE_STREAM_CREATE:
+        red_display_release_stream((DisplayChannel *)channel,
+                                   SPICE_CONTAINEROF(item, StreamAgent, create_item));
+        break;
+    case PIPE_ITEM_TYPE_STREAM_CLIP:
+        red_display_release_stream_clip((DisplayChannel *)channel, (StreamClipItem*)item);
+        break;
+    case PIPE_ITEM_TYPE_STREAM_DESTROY:
+        red_display_release_stream((DisplayChannel *)channel,
+                                   SPICE_CONTAINEROF(item, StreamAgent, destroy_item));
+        break;
+    case PIPE_ITEM_TYPE_CREATE_SURFACE: {
+        SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(item, SurfaceCreateItem,
+                                                              pipe_item);
+        free(surface_create);
+        break;
+    }
+    case PIPE_ITEM_TYPE_DESTROY_SURFACE: {
+        SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(item, SurfaceDestroyItem,
+                                                                pipe_item);
+        free(surface_destroy);
+        break;
+    }
+    }
+}
+
 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(common->worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
-            break;
-        case PIPE_ITEM_TYPE_CURSOR:
-            red_release_cursor(common->worker, (CursorItem *)item);
-            break;
-        case PIPE_ITEM_TYPE_UPGRADE:
-            release_upgrade_item(common->worker, (UpgradeItem *)item);
-            break;
-        case PIPE_ITEM_TYPE_PIXMAP_RESET:
-        case PIPE_ITEM_TYPE_PIXMAP_SYNC:
-        case PIPE_ITEM_TYPE_INVAL_ONE:
-        case PIPE_ITEM_TYPE_MIGRATE:
-        case PIPE_ITEM_TYPE_SET_ACK:
-        case PIPE_ITEM_TYPE_CURSOR_INIT:
-        case PIPE_ITEM_TYPE_VERB:
-        case PIPE_ITEM_TYPE_MIGRATE_DATA:
-        case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
-        case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
-            free(item);
-            break;
-        case PIPE_ITEM_TYPE_IMAGE:
-            release_image_item((ImageItem *)item);
-            break;
-        case PIPE_ITEM_TYPE_STREAM_CREATE:
-            red_display_release_stream((DisplayChannel *)channel,
-                                       SPICE_CONTAINEROF(item, StreamAgent, create_item));
-            break;
-        case PIPE_ITEM_TYPE_STREAM_CLIP:
-            red_display_release_stream_clip((DisplayChannel *)channel, (StreamClipItem*)item);
-            break;
-        case PIPE_ITEM_TYPE_STREAM_DESTROY:
-            red_display_release_stream((DisplayChannel *)channel,
-                                       SPICE_CONTAINEROF(item, StreamAgent, destroy_item));
-            break;
-        case PIPE_ITEM_TYPE_CREATE_SURFACE: {
-            SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(item, SurfaceCreateItem,
-                                                                  pipe_item);
-            free(surface_create);
-            break;
-        }
-        case PIPE_ITEM_TYPE_DESTROY_SURFACE: {
-            SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(item, SurfaceDestroyItem,
-                                                                    pipe_item);
-            free(surface_destroy);
-            break;
-        }
-        }
+        common_release_pipe_item(channel, item);
     }
     channel->pipe_size = 0;
 }
commit e588176dababaab0b6b0a2809e31c3054fc8101e
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 15:33:05 2010 +0200

    server/red_worker: use red_channel pipe add versions
    
    s/red_pipe_add/red_channel_pipe_add/
    s/red_pipe_add_after/red_channel_pipe_add_after/

diff --git a/server/red_worker.c b/server/red_worker.c
index c6973d6..8550a92 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1182,14 +1182,14 @@ static inline void red_pipe_item_init(PipeItem *item, int type)
     item->type = type;
 }
 
-static inline void red_pipe_add(RedChannel *channel, PipeItem *item)
+static inline void red_channel_pipe_add(RedChannel *channel, PipeItem *item)
 {
     ASSERT(channel);
     channel->pipe_size++;
     ring_add(&channel->pipe, &item->link);
 }
 
-static inline void red_pipe_add_after(RedChannel *channel, PipeItem *item, PipeItem *pos)
+static inline void red_channel_pipe_add_after(RedChannel *channel, PipeItem *item, PipeItem *pos)
 {
     ASSERT(channel && pos);
     channel->pipe_size++;
@@ -1218,14 +1218,14 @@ static void red_pipe_add_verb(RedChannel* channel, uint16_t verb)
     VerbItem *item = spice_new(VerbItem, 1);
     red_pipe_item_init(&item->base, PIPE_ITEM_TYPE_VERB);
     item->verb = verb;
-    red_pipe_add(channel, &item->base);
+    red_channel_pipe_add(channel, &item->base);
 }
 
 static void red_pipe_add_type(RedChannel* channel, int pipe_item_type)
 {
     PipeItem *item = spice_new(PipeItem, 1);
     red_pipe_item_init(item, pipe_item_type);
-    red_pipe_add(channel, item);
+    red_channel_pipe_add(channel, item);
 }
 
 static inline void red_create_surface_item(RedWorker *worker, int surface_id);
@@ -1267,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->common.base, &drawable->pipe_item);
+    red_channel_pipe_add(&worker->display_channel->common.base, &drawable->pipe_item);
 }
 
 static inline void red_pipe_add_drawable_to_tail(RedWorker *worker, Drawable *drawable)
@@ -1291,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->common.base, &drawable->pipe_item, &pos_after->pipe_item);
+    red_channel_pipe_add_after(&worker->display_channel->common.base, &drawable->pipe_item, &pos_after->pipe_item);
 }
 
 static inline PipeItem *red_pipe_get_tail(RedWorker *worker)
@@ -1320,7 +1320,7 @@ static inline void red_pipe_add_image_item(RedWorker *worker, ImageItem *item)
         return;
     }
     item->refs++;
-    red_pipe_add(&worker->display_channel->common.base, &item->link);
+    red_channel_pipe_add(&worker->display_channel->common.base, &item->link);
 }
 
 static inline void red_pipe_add_image_item_after(RedWorker *worker, ImageItem *item,
@@ -1330,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->common.base, &item->link, pos);
+    red_channel_pipe_add_after(&worker->display_channel->common.base, &item->link, pos);
 }
 
 static inline uint64_t channel_message_serial(RedChannel *channel)
@@ -1493,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->common.base, &destroy->pipe_item);
+    red_channel_pipe_add(&worker->display_channel->common.base, &destroy->pipe_item);
 }
 
 static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id)
@@ -2286,7 +2286,7 @@ static void push_stream_clip_by_drawable(DisplayChannel* channel, StreamAgent *a
         item->rects->num_rects = n_rects;
         region_ret_rects(&drawable->tree_item.base.rgn, item->rects->rects, n_rects);
     }
-    red_pipe_add((RedChannel*)channel, (PipeItem *)item);
+    red_channel_pipe_add((RedChannel*)channel, (PipeItem *)item);
 }
 
 static void push_stream_clip(DisplayChannel* channel, StreamAgent *agent)
@@ -2304,7 +2304,7 @@ static void push_stream_clip(DisplayChannel* channel, StreamAgent *agent)
     item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
     item->rects->num_rects = n_rects;
     region_ret_rects(&agent->vis_region, item->rects->rects, n_rects);
-    red_pipe_add((RedChannel*)channel, (PipeItem *)item);
+    red_channel_pipe_add((RedChannel*)channel, (PipeItem *)item);
 }
 
 static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipItem *item)
@@ -2349,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->common.base, &stream_agent->destroy_item);
+        red_channel_pipe_add(&channel->common.base, &stream_agent->destroy_item);
     }
     ring_remove(&stream->link);
     red_release_stream(worker, stream);
@@ -2373,7 +2373,7 @@ static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *strea
         upgrade_item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
         upgrade_item->rects->num_rects = n_rects;
         region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn, upgrade_item->rects->rects, n_rects);
-        red_pipe_add((RedChannel *)channel, &upgrade_item->base);
+        red_channel_pipe_add((RedChannel *)channel, &upgrade_item->base);
     }
     red_detach_stream(worker, stream);
 }
@@ -2527,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->common.base, &agent->create_item);
+    red_channel_pipe_add(&display->common.base, &agent->create_item);
 }
 
 static void red_create_stream(RedWorker *worker, Drawable *drawable)
@@ -4287,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->common.base, &item->pipe_data);
+        red_channel_pipe_add(&worker->cursor_channel->common.base, &item->pipe_data);
     } else {
         red_release_cursor(worker, item);
     }
@@ -8702,7 +8702,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->common.base, &create->pipe_item);
+    red_channel_pipe_add(&worker->display_channel->common.base, &create->pipe_item);
 }
 
 static inline void red_create_surface_item(RedWorker *worker, int surface_id)
commit a0a958c77b14fbfde08bef7ce4a22dfde88fd44f
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 15:26:46 2010 +0200

    server/red_worker: shorten some lines using alias variables

diff --git a/server/red_worker.c b/server/red_worker.c
index 0ed46e9..c6973d6 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8163,13 +8163,14 @@ static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cu
     RedChannel *channel;
     SpiceMsgCursorSet cursor_set;
     AddBufInfo info;
+    RedWorker *worker;
 
     ASSERT(cursor_channel);
-
+    worker = cursor_channel->common.worker;
     channel = &cursor_channel->common.base;
     channel->send_data.header->type = SPICE_MSG_CURSOR_SET;
     cursor_set.position = cursor->position;
-    cursor_set.visible = cursor_channel->common.worker->cursor_visible;
+    cursor_set.visible = worker->cursor_visible;
 
     fill_cursor(cursor_channel, &cursor_set.cursor, &cursor->base, &info);
     spice_marshall_msg_cursor_set(channel->send_data.marshaller, &cursor_set);
@@ -8177,7 +8178,7 @@ static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cu
 
     red_begin_send_message(channel, cursor);
 
-    red_release_cursor(cursor_channel->common.worker, (CursorItem *)cursor);
+    red_release_cursor(worker, (CursorItem *)cursor);
 }
 
 static void cursor_channel_send_migrate(CursorChannel *cursor_channel)
@@ -8196,10 +8197,12 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
     RedChannel *channel;
     RedCursorCmd *cmd;
     SpiceMarshaller *m;
+    RedWorker *worker;
 
     ASSERT(cursor_channel);
 
     channel = &cursor_channel->common.base;
+    worker = cursor_channel->common.worker;
     m = channel->send_data.marshaller;
 
     cmd = cursor->red_cursor;
@@ -8219,7 +8222,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 = cursor_channel->common.worker->cursor_visible;
+            cursor_set.visible = worker->cursor_visible;
 
             fill_cursor(cursor_channel, &cursor_set.cursor, cursor, &info);
             spice_marshall_msg_cursor_set(m, &cursor_set);
@@ -8540,17 +8543,19 @@ static void red_disconnect_channel(RedChannel *channel)
 static void red_disconnect_display(RedChannel *channel)
 {
     DisplayChannel *display_channel;
+    CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
+    RedWorker *worker;
 
     if (!channel || !channel->peer) {
         return;
     }
-
+    worker = common->worker;
     display_channel = (DisplayChannel *)channel;
-    ASSERT(display_channel == display_channel->common.worker->display_channel);
+    ASSERT(display_channel == worker->display_channel);
 #ifdef COMPRESS_STAT
     print_compress_stats(display_channel);
 #endif
-    display_channel->common.worker->display_channel = NULL;
+    worker->display_channel = NULL;
     red_display_unshare_stream_buf(display_channel);
     red_release_pixmap_cache(display_channel);
     red_release_glz(display_channel);
@@ -9962,6 +9967,8 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
 {
     RedWorker *worker = SPICE_CONTAINEROF(listener, RedWorker, dev_listener);
     RedWorkerMessage message;
+    RedChannel *cursor_red_channel = &worker->cursor_channel->common.base;
+    RedChannel *display_red_channel = &worker->display_channel->common.base;
     int ring_is_empty;
 
     read_message(worker->channel, &message);
@@ -9980,8 +9987,9 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
             display_channel_push(worker);
         }
         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->common.base.pipe_size : 0);
+            red_printf("oom current %u pipe %u", worker->current_size,
+                       worker->display_channel ?
+                       display_red_channel->pipe_size : 0);
             red_free_some(worker);
             worker->qxl->st->qif->flush_resources(worker->qxl);
         }
@@ -9995,11 +10003,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->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);
+            red_pipe_add_type(cursor_red_channel, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+            if (!cursor_red_channel->migrate) {
+                red_pipe_add_verb(cursor_red_channel, SPICE_MSG_CURSOR_RESET);
             }
-            ASSERT(!worker->cursor_channel->common.base.send_data.item);
+            ASSERT(!cursor_red_channel->send_data.item);
 
             worker->cursor_visible = TRUE;
             worker->cursor_position.x = worker->cursor_position.y = 0;
@@ -10063,10 +10071,10 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         red_printf("start");
         ASSERT(!worker->running);
         if (worker->cursor_channel) {
-            worker->cursor_channel->common.base.migrate = FALSE;
+            cursor_red_channel->migrate = FALSE;
         }
         if (worker->display_channel) {
-            worker->display_channel->common.base.migrate = FALSE;
+            display_red_channel->migrate = FALSE;
         }
         worker->running = TRUE;
         break;
commit e8698ea0f89f797fcfb34c192486f636e677f3b2
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 14:05:19 2010 +0200

    server/red_worker: introduce CommonChannel
    
    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.

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) {
commit 9330dbac13ccec52f32e06169c746f99086e464a
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 13:23:59 2010 +0200

    server/red_worker: use ack_data struct
    
    start of move to red_channel based channels

diff --git a/server/red_worker.c b/server/red_worker.c
index df51841..97f5e70 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -362,10 +362,12 @@ struct RedChannel {
     Ring pipe;
     uint32_t pipe_size;
 
-    uint32_t client_ack_window;
-    uint32_t ack_generation;
-    uint32_t client_ack_generation;
-    uint32_t messages_window;
+    struct {
+        uint32_t client_window;
+        uint32_t generation;
+        uint32_t client_generation;
+        uint32_t messages_window;
+    } ack_data;
 
     struct {
         int blocked;
@@ -7386,7 +7388,7 @@ static inline void red_begin_send_message(RedChannel *channel, void *item)
     spice_marshaller_flush(channel->send_data.marshaller);
     channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
     channel->send_data.header->size =  channel->send_data.size - sizeof(SpiceDataHeader);
-    channel->messages_window++;
+    channel->ack_data.messages_window++;
     channel->send_data.header = NULL; /* avoid writing to this until we have a new message */
     red_send_data(channel, item);
 }
@@ -7742,9 +7744,9 @@ static void red_send_set_ack(RedChannel *channel)
 
     ASSERT(channel);
     channel->send_data.header->type = SPICE_MSG_SET_ACK;
-    ack.generation = ++channel->ack_generation;
-    ack.window = channel->client_ack_window;
-    channel->messages_window = 0;
+    ack.generation = ++channel->ack_data.generation;
+    ack.window = channel->ack_data.client_window;
+    channel->ack_data.messages_window = 0;
 
     spice_marshall_msg_set_ack(channel->send_data.marshaller, &ack);
 
@@ -8274,7 +8276,7 @@ static inline PipeItem *red_pipe_get(RedChannel *channel)
         return NULL;
     }
 
-    if (channel->messages_window > channel->client_ack_window * 2) {
+    if (channel->ack_data.messages_window > channel->ack_data.client_window * 2) {
         channel->send_data.blocked = TRUE;
         return NULL;
     }
@@ -8896,7 +8898,7 @@ static void on_new_display_channel(RedWorker *worker)
     if (!display_channel_wait_for_init(display_channel)) {
         return;
     }
-    display_channel->base.messages_window = 0;
+    display_channel->base.ack_data.messages_window = 0;
     if (worker->surfaces[0].context.canvas) {
         red_current_flush(worker, 0);
         push_new_primary_surface(worker);
@@ -8912,11 +8914,11 @@ static int channel_handle_message(RedChannel *channel, size_t size, uint32_t typ
 {
     switch (type) {
     case SPICE_MSGC_ACK_SYNC:
-        channel->client_ack_generation = *(uint32_t *)message;
+        channel->ack_data.client_generation = *(uint32_t *)message;
         break;
     case SPICE_MSGC_ACK:
-        if (channel->client_ack_generation == channel->ack_generation) {
-            channel->messages_window -= channel->client_ack_window;
+        if (channel->ack_data.client_generation == channel->ack_data.generation) {
+            channel->ack_data.messages_window -= channel->ack_data.client_window;
         }
         break;
     case SPICE_MSGC_DISCONNECTING:
@@ -9211,7 +9213,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.messages_window = 0;
+    channel->base.ack_data.messages_window = 0;
     return TRUE;
 }
 
@@ -9346,11 +9348,11 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     channel->handle_message = handle_message;
     channel->peer = peer;
     channel->worker = worker;
-    channel->messages_window = ~0;  // blocks send message (maybe use send_data.blocked +
+    channel->ack_data.messages_window = ~0;  // blocks send message (maybe use send_data.blocked +
                                     // block flags)
-    channel->client_ack_window = IS_LOW_BANDWIDTH() ? WIDE_CLIENT_ACK_WINDOW :
+    channel->ack_data.client_window = IS_LOW_BANDWIDTH() ? WIDE_CLIENT_ACK_WINDOW :
                                                       NARROW_CLIENT_ACK_WINDOW;
-    channel->client_ack_generation = ~0;
+    channel->ack_data.client_generation = ~0;
     channel->recive_data.message = (SpiceDataHeader *)channel->recive_data.buf;
     channel->recive_data.now = channel->recive_data.buf;
     channel->recive_data.end = channel->recive_data.buf + sizeof(channel->recive_data.buf);
@@ -9537,7 +9539,7 @@ static void on_new_cursor_channel(RedWorker *worker)
 
     ASSERT(channel);
 
-    channel->base.messages_window = 0;
+    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);
commit a185c1daf054dea34d6152cbe6e4f86518f3701d
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Nov 7 18:47:50 2010 +0200

    server/red_worker: change hold_item sig, drop the void*
    
    changed to PipeItem *

diff --git a/server/red_worker.c b/server/red_worker.c
index 2acef40..df51841 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -347,7 +347,7 @@ typedef struct LocalCursor {
 
 typedef struct RedChannel RedChannel;
 typedef void (*disconnect_channel_proc)(RedChannel *channel);
-typedef void (*hold_pipe_item_proc)(void *item);
+typedef void (*hold_pipe_item_proc)(PipeItem *item);
 typedef void (*release_item_proc)(RedChannel *channel, void *item);
 typedef int (*handle_message_proc)(RedChannel *channel, size_t size, uint32_t type, void *message);
 
@@ -9389,10 +9389,10 @@ static void handle_channel_events(EventListener *in_listener, uint32_t events)
     }
 }
 
-static void display_channel_hold_pipe_item(void *item)
+static void display_channel_hold_pipe_item(PipeItem *item)
 {
     ASSERT(item);
-    switch (((PipeItem *)item)->type) {
+    switch (item->type) {
     case PIPE_ITEM_TYPE_DRAW:
     case PIPE_ITEM_TYPE_STREAM_CREATE:
         SPICE_CONTAINEROF(item, Drawable, pipe_item)->refs++;
@@ -9544,7 +9544,7 @@ static void on_new_cursor_channel(RedWorker *worker)
     }
 }
 
-static void cursor_channel_hold_pipe_item(void *item)
+static void cursor_channel_hold_pipe_item(PipeItem *item)
 {
     ASSERT(item);
     ((CursorItem *)item)->refs++;


More information about the Spice-commits mailing list