summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2013-09-03 00:21:55 +0200
committerFrediano Ziglio <fziglio@redhat.com>2015-10-23 16:32:47 +0100
commitf99fac0f42d25d8f34104dd0ff11dcf93cd7bf7e (patch)
tree659a658f78aa65f44366a2a2dfca3bae0d46e315
parentb9defad7d9a774d50c8f8497f41e82f0d563597b (diff)
downloadspice-f99fac0f42d25d8f34104dd0ff11dcf93cd7bf7e.tar.gz
spice-f99fac0f42d25d8f34104dd0ff11dcf93cd7bf7e.tar.xz
spice-f99fac0f42d25d8f34104dd0ff11dcf93cd7bf7e.zip
server: start separate display/cursor channel headers
Just move some declarations around Acked-by: Frediano Ziglio <fziglio@redhat.com>
-rw-r--r--server/Makefile.am2
-rw-r--r--server/cursor-channel.h79
-rw-r--r--server/display-channel.h211
-rw-r--r--server/red_worker.c264
-rw-r--r--server/red_worker.h20
5 files changed, 314 insertions, 262 deletions
diff --git a/server/Makefile.am b/server/Makefile.am
index 826659e9..ad7476ce 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -106,6 +106,8 @@ libspice_server_la_SOURCES = \
red_time.h \
red_worker.c \
red_worker.h \
+ display-channel.h \
+ cursor-channel.h \
reds.c \
reds.h \
reds-private.h \
diff --git a/server/cursor-channel.h b/server/cursor-channel.h
new file mode 100644
index 00000000..48b2c71c
--- /dev/null
+++ b/server/cursor-channel.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef CURSOR_CHANNEL_H_
+# define CURSOR_CHANNEL_H_
+
+#include "red_worker.h"
+#include "stat.h"
+
+#define CLIENT_CURSOR_CACHE_SIZE 256
+
+#define CURSOR_CACHE_HASH_SHIFT 8
+#define CURSOR_CACHE_HASH_SIZE (1 << CURSOR_CACHE_HASH_SHIFT)
+#define CURSOR_CACHE_HASH_MASK (CURSOR_CACHE_HASH_SIZE - 1)
+#define CURSOR_CACHE_HASH_KEY(id) ((id) & CURSOR_CACHE_HASH_MASK)
+
+typedef struct CursorItem {
+ uint32_t group_id;
+ int refs;
+ RedCursorCmd *red_cursor;
+} CursorItem;
+
+typedef struct CursorPipeItem {
+ PipeItem base;
+ CursorItem *cursor_item;
+ int refs;
+} CursorPipeItem;
+
+typedef struct LocalCursor {
+ CursorItem base;
+ SpicePoint16 position;
+ uint32_t data_size;
+ SpiceCursor red_cursor;
+} LocalCursor;
+
+typedef struct CursorChannelClient {
+ CommonChannelClient common;
+
+ CacheItem *cursor_cache[CURSOR_CACHE_HASH_SIZE];
+ Ring cursor_cache_lru;
+ long cursor_cache_available;
+ uint32_t cursor_cache_items;
+} CursorChannelClient;
+
+typedef struct CursorChannel {
+ CommonChannel common; // Must be the first thing
+
+#ifdef RED_STATISTICS
+ StatNodeRef stat;
+#endif
+} CursorChannel;
+
+typedef struct _CursorItem _CursorItem;
+
+struct _CursorItem {
+ union {
+ CursorItem cursor_item;
+ _CursorItem *next;
+ } u;
+};
+
+G_STATIC_ASSERT(sizeof(CursorItem) <= QXL_CURSUR_DEVICE_DATA_SIZE);
+
+
+#endif /* CURSOR_CHANNEL_H_ */
diff --git a/server/display-channel.h b/server/display-channel.h
new file mode 100644
index 00000000..ecf764d1
--- /dev/null
+++ b/server/display-channel.h
@@ -0,0 +1,211 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2009-2015 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef RED_WORKER_CLIENT_H_
+# define RED_WORKER_CLIENT_H_
+
+#include "red_worker.h"
+#include "pixmap-cache.h"
+
+typedef int64_t red_time_t;
+
+typedef struct Drawable Drawable;
+
+#define PALETTE_CACHE_HASH_SHIFT 8
+#define PALETTE_CACHE_HASH_SIZE (1 << PALETTE_CACHE_HASH_SHIFT)
+#define PALETTE_CACHE_HASH_MASK (PALETTE_CACHE_HASH_SIZE - 1)
+#define PALETTE_CACHE_HASH_KEY(id) ((id) & PALETTE_CACHE_HASH_MASK)
+
+/* Each drawable can refer to at most 3 images: src, brush and mask */
+#define MAX_DRAWABLE_PIXMAP_CACHE_ITEMS 3
+
+#define NUM_STREAMS 50
+#define NUM_SURFACES 10000
+
+typedef struct CacheItem CacheItem;
+
+struct CacheItem {
+ union {
+ PipeItem pipe_data;
+ struct {
+ RingItem lru_link;
+ CacheItem *next;
+ } cache_data;
+ } u;
+ uint64_t id;
+ size_t size;
+ uint32_t inval_type;
+};
+
+#define RED_COMPRESS_BUF_SIZE (1024 * 64)
+typedef struct RedCompressBuf RedCompressBuf;
+struct RedCompressBuf {
+ uint32_t buf[RED_COMPRESS_BUF_SIZE / 4];
+ RedCompressBuf *next;
+ RedCompressBuf *send_next;
+};
+
+typedef struct WaitForChannels {
+ SpiceMsgWaitForChannels header;
+ SpiceWaitForChannel buf[MAX_CACHE_CLIENTS];
+} WaitForChannels;
+
+typedef struct FreeList {
+ int res_size;
+ SpiceResourceList *res;
+ uint64_t sync[MAX_CACHE_CLIENTS];
+ WaitForChannels wait;
+} FreeList;
+
+typedef struct GlzSharedDictionary {
+ RingItem base;
+ GlzEncDictContext *dict;
+ uint32_t refs;
+ uint8_t id;
+ pthread_rwlock_t encode_lock;
+ int migrate_freeze;
+ RedClient *client; // channel clients of the same client share the dict
+} GlzSharedDictionary;
+
+typedef struct {
+ DisplayChannelClient *dcc;
+ RedCompressBuf *bufs_head;
+ RedCompressBuf *bufs_tail;
+ jmp_buf jmp_env;
+ union {
+ struct {
+ SpiceChunks *chunks;
+ int next;
+ int stride;
+ int reverse;
+ } lines_data;
+ struct {
+ RedCompressBuf* next;
+ int size_left;
+ } compressed_data; // for encoding data that was already compressed by another method
+ } u;
+ char message_buf[512];
+} EncoderData;
+
+typedef struct {
+ GlzEncoderUsrContext usr;
+ EncoderData data;
+} GlzData;
+
+typedef struct Stream Stream;
+struct Stream {
+ uint8_t refs;
+ Drawable *current;
+ red_time_t last_time;
+ int width;
+ int height;
+ SpiceRect dest_area;
+ int top_down;
+ Stream *next;
+ RingItem link;
+
+ uint32_t num_input_frames;
+ uint64_t input_fps_start_time;
+ uint32_t input_fps;
+};
+
+#define STREAM_STATS
+#ifdef STREAM_STATS
+typedef struct StreamStats {
+ uint64_t num_drops_pipe;
+ uint64_t num_drops_fps;
+ uint64_t num_frames_sent;
+ uint64_t num_input_frames;
+ uint64_t size_sent;
+
+ uint64_t start;
+ uint64_t end;
+} StreamStats;
+#endif
+
+typedef struct StreamAgent {
+ QRegion vis_region; /* the part of the surface area that is currently occupied by video
+ fragments */
+ QRegion clip; /* the current video clipping. It can be different from vis_region:
+ for example, let c1 be the clip area at time t1, and c2
+ be the clip area at time t2, where t1 < t2. If c1 contains c2, and
+ at least part of c1/c2, hasn't been covered by a non-video images,
+ vis_region will contain c2 and also the part of c1/c2 that still
+ displays fragments of the video */
+
+ PipeItem create_item;
+ PipeItem destroy_item;
+ Stream *stream;
+ uint64_t last_send_time;
+ MJpegEncoder *mjpeg_encoder;
+ DisplayChannelClient *dcc;
+
+ int frames;
+ int drops;
+ int fps;
+
+ uint32_t report_id;
+ uint32_t client_required_latency;
+#ifdef STREAM_STATS
+ StreamStats stats;
+#endif
+} StreamAgent;
+
+struct DisplayChannelClient {
+ CommonChannelClient common;
+
+ int expect_init;
+
+ PixmapCache *pixmap_cache;
+ uint32_t pixmap_cache_generation;
+ int pending_pixmaps_sync;
+
+ CacheItem *palette_cache[PALETTE_CACHE_HASH_SIZE];
+ Ring palette_cache_lru;
+ long palette_cache_available;
+ uint32_t palette_cache_items;
+
+ struct {
+ uint32_t stream_outbuf_size;
+ uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!!
+
+ RedCompressBuf *used_compress_bufs;
+
+ FreeList free_list;
+ uint64_t pixmap_cache_items[MAX_DRAWABLE_PIXMAP_CACHE_ITEMS];
+ int num_pixmap_cache_items;
+ } send_data;
+
+ /* global lz encoding entities */
+ GlzSharedDictionary *glz_dict;
+ GlzEncoderContext *glz;
+ GlzData glz_data;
+
+ Ring glz_drawables; // all the living lz drawable, ordered by encoding time
+ Ring glz_drawables_inst_to_free; // list of instances to be freed
+ pthread_mutex_t glz_drawables_inst_to_free_lock;
+
+ uint8_t surface_client_created[NUM_SURFACES];
+ QRegion surface_client_lossy_region[NUM_SURFACES];
+
+ StreamAgent stream_agents[NUM_STREAMS];
+ int use_mjpeg_encoder_rate_control;
+ uint32_t streams_max_latency;
+ uint64_t streams_max_bit_rate;
+};
+
+#endif /* RED_WORKER_CLIENT_H_ */
diff --git a/server/red_worker.c b/server/red_worker.c
index 2a4de003..3d326d1e 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -93,6 +93,8 @@
#include "spice_bitmap_utils.h"
#include "spice_image_cache.h"
#include "pixmap-cache.h"
+#include "display-channel.h"
+#include "cursor-channel.h"
//#define COMPRESS_STAT
//#define DUMP_BITMAP
@@ -127,13 +129,9 @@
#define FPS_TEST_INTERVAL 1
#define MAX_FPS 30
-#define RED_COMPRESS_BUF_SIZE (1024 * 64)
-
#define ZLIB_DEFAULT_COMPRESSION_LEVEL 3
#define MIN_GLZ_SIZE_FOR_ZLIB 100
-typedef int64_t red_time_t;
-
#define VALIDATE_SURFACE_RET(worker, surface_id) \
if (!validate_surface(worker, surface_id)) { \
rendering_incorrect(__func__); \
@@ -300,21 +298,6 @@ typedef struct VerbItem {
#define MAX_LZ_ENCODERS MAX_CACHE_CLIENTS
-typedef struct CacheItem CacheItem;
-
-struct CacheItem {
- union {
- PipeItem pipe_data;
- struct {
- RingItem lru_link;
- CacheItem *next;
- } cache_data;
- } u;
- uint64_t id;
- size_t size;
- uint32_t inval_type;
-};
-
typedef struct SurfaceCreateItem {
SpiceMsgSurfaceCreate surface_create;
PipeItem pipe_item;
@@ -343,45 +326,13 @@ typedef struct StreamActivateReportItem {
uint32_t stream_id;
} StreamActivateReportItem;
-typedef struct CursorItem {
- uint32_t group_id;
- int refs;
- RedCursorCmd *red_cursor;
-} CursorItem;
-
-typedef struct CursorPipeItem {
- PipeItem base;
- CursorItem *cursor_item;
- int refs;
-} CursorPipeItem;
-
-typedef struct LocalCursor {
- CursorItem base;
- SpicePoint16 position;
- uint32_t data_size;
- SpiceCursor red_cursor;
-} LocalCursor;
-
#define MAX_PIPE_SIZE 50
-#define CHANNEL_RECEIVE_BUF_SIZE 1024
#define WIDE_CLIENT_ACK_WINDOW 40
#define NARROW_CLIENT_ACK_WINDOW 20
-#define CLIENT_CURSOR_CACHE_SIZE 256
-
-#define CURSOR_CACHE_HASH_SHIFT 8
-#define CURSOR_CACHE_HASH_SIZE (1 << CURSOR_CACHE_HASH_SHIFT)
-#define CURSOR_CACHE_HASH_MASK (CURSOR_CACHE_HASH_SIZE - 1)
-#define CURSOR_CACHE_HASH_KEY(id) ((id) & CURSOR_CACHE_HASH_MASK)
-
#define CLIENT_PALETTE_CACHE_SIZE 128
-#define PALETTE_CACHE_HASH_SHIFT 8
-#define PALETTE_CACHE_HASH_SIZE (1 << PALETTE_CACHE_HASH_SHIFT)
-#define PALETTE_CACHE_HASH_MASK (PALETTE_CACHE_HASH_SIZE - 1)
-#define PALETTE_CACHE_HASH_KEY(id) ((id) & PALETTE_CACHE_HASH_MASK)
-
typedef struct ImageItem {
PipeItem link;
int refs;
@@ -397,8 +348,6 @@ typedef struct ImageItem {
uint8_t data[0];
} ImageItem;
-typedef struct Drawable Drawable;
-
typedef struct DisplayChannel DisplayChannel;
enum {
@@ -407,65 +356,6 @@ enum {
STREAM_FRAME_CONTAINER,
};
-typedef struct Stream Stream;
-struct Stream {
- uint8_t refs;
- Drawable *current;
- red_time_t last_time;
- int width;
- int height;
- SpiceRect dest_area;
- int top_down;
- Stream *next;
- RingItem link;
-
- uint32_t num_input_frames;
- uint64_t input_fps_start_time;
- uint32_t input_fps;
-};
-
-#define STREAM_STATS
-#ifdef STREAM_STATS
-typedef struct StreamStats {
- uint64_t num_drops_pipe;
- uint64_t num_drops_fps;
- uint64_t num_frames_sent;
- uint64_t num_input_frames;
- uint64_t size_sent;
-
- uint64_t start;
- uint64_t end;
-} StreamStats;
-#endif
-
-typedef struct StreamAgent {
- QRegion vis_region; /* the part of the surface area that is currently occupied by video
- fragments */
- QRegion clip; /* the current video clipping. It can be different from vis_region:
- for example, let c1 be the clip area at time t1, and c2
- be the clip area at time t2, where t1 < t2. If c1 contains c2, and
- at least part of c1/c2, hasn't been covered by a non-video images,
- vis_region will contain c2 and also the part of c1/c2 that still
- displays fragments of the video */
-
- PipeItem create_item;
- PipeItem destroy_item;
- Stream *stream;
- uint64_t last_send_time;
- MJpegEncoder *mjpeg_encoder;
- DisplayChannelClient *dcc;
-
- int frames;
- int drops;
- int fps;
-
- uint32_t report_id;
- uint32_t client_required_latency;
-#ifdef STREAM_STATS
- StreamStats stats;
-#endif
-} StreamAgent;
-
typedef struct StreamClipItem {
PipeItem base;
int refs;
@@ -474,13 +364,6 @@ typedef struct StreamClipItem {
SpiceClipRects *rects;
} StreamClipItem;
-typedef struct RedCompressBuf RedCompressBuf;
-struct RedCompressBuf {
- uint32_t buf[RED_COMPRESS_BUF_SIZE / 4];
- RedCompressBuf *next;
- RedCompressBuf *send_next;
-};
-
static const int BITMAP_FMT_IS_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
static const int BITMAP_FMP_BYTES_PER_PIXEL[] = {0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 1};
@@ -488,40 +371,6 @@ static const int BITMAP_FMP_BYTES_PER_PIXEL[] = {0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 1
(bitmap_fmt_is_rgb(f) && \
((f) != SPICE_BITMAP_FMT_8BIT_A))
-#define NUM_STREAMS 50
-
-typedef struct WaitForChannels {
- SpiceMsgWaitForChannels header;
- SpiceWaitForChannel buf[MAX_CACHE_CLIENTS];
-} WaitForChannels;
-
-typedef struct FreeList {
- int res_size;
- SpiceResourceList *res;
- uint64_t sync[MAX_CACHE_CLIENTS];
- WaitForChannels wait;
-} FreeList;
-
-typedef struct {
- DisplayChannelClient *dcc;
- RedCompressBuf *bufs_head;
- RedCompressBuf *bufs_tail;
- jmp_buf jmp_env;
- union {
- struct {
- SpiceChunks *chunks;
- int next;
- int stride;
- int reverse;
- } lines_data;
- struct {
- RedCompressBuf* next;
- int size_left;
- } compressed_data; // for encoding data that was already compressed by another method
- } u;
- char message_buf[512];
-} EncoderData;
-
typedef struct {
QuicUsrContext usr;
EncoderData data;
@@ -533,11 +382,6 @@ typedef struct {
} LzData;
typedef struct {
- GlzEncoderUsrContext usr;
- EncoderData data;
-} GlzData;
-
-typedef struct {
JpegEncoderUsrContext usr;
EncoderData data;
} JpegData;
@@ -590,83 +434,6 @@ struct RedGlzDrawable {
pthread_mutex_t glz_dictionary_list_lock = PTHREAD_MUTEX_INITIALIZER;
Ring glz_dictionary_list = {&glz_dictionary_list, &glz_dictionary_list};
-typedef struct GlzSharedDictionary {
- RingItem base;
- GlzEncDictContext *dict;
- uint32_t refs;
- uint8_t id;
- pthread_rwlock_t encode_lock;
- int migrate_freeze;
- RedClient *client; // channel clients of the same client share the dict
-} GlzSharedDictionary;
-
-#define NUM_SURFACES 10000
-
-typedef struct CommonChannel {
- RedChannel base; // Must be the first thing
- struct RedWorker *worker;
- uint8_t recv_buf[CHANNEL_RECEIVE_BUF_SIZE];
- uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme.
- int during_target_migrate; /* TRUE when the client that is associated with the channel
- is during migration. Turned off when the vm is started.
- The flag is used to avoid sending messages that are artifacts
- of the transition from stopped vm to loaded vm (e.g., recreation
- of the primary surface) */
-} CommonChannel;
-
-typedef struct CommonChannelClient {
- RedChannelClient base;
- uint32_t id;
- struct RedWorker *worker;
- int is_low_bandwidth;
-} CommonChannelClient;
-
-/* Each drawable can refer to at most 3 images: src, brush and mask */
-#define MAX_DRAWABLE_PIXMAP_CACHE_ITEMS 3
-
-struct DisplayChannelClient {
- CommonChannelClient common;
-
- int expect_init;
-
- PixmapCache *pixmap_cache;
- uint32_t pixmap_cache_generation;
- int pending_pixmaps_sync;
-
- CacheItem *palette_cache[PALETTE_CACHE_HASH_SIZE];
- Ring palette_cache_lru;
- long palette_cache_available;
- uint32_t palette_cache_items;
-
- struct {
- uint32_t stream_outbuf_size;
- uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!!
-
- RedCompressBuf *used_compress_bufs;
-
- FreeList free_list;
- uint64_t pixmap_cache_items[MAX_DRAWABLE_PIXMAP_CACHE_ITEMS];
- int num_pixmap_cache_items;
- } send_data;
-
- /* global lz encoding entities */
- GlzSharedDictionary *glz_dict;
- GlzEncoderContext *glz;
- GlzData glz_data;
-
- Ring glz_drawables; // all the living lz drawable, ordered by encoding time
- Ring glz_drawables_inst_to_free; // list of instances to be freed
- pthread_mutex_t glz_drawables_inst_to_free_lock;
-
- uint8_t surface_client_created[NUM_SURFACES];
- QRegion surface_client_lossy_region[NUM_SURFACES];
-
- StreamAgent stream_agents[NUM_STREAMS];
- int use_mjpeg_encoder_rate_control;
- uint32_t streams_max_latency;
- uint64_t streams_max_bit_rate;
-};
-
struct DisplayChannel {
CommonChannel common; // Must be the first thing
@@ -694,23 +461,6 @@ struct DisplayChannel {
#endif
};
-typedef struct CursorChannelClient {
- CommonChannelClient common;
-
- CacheItem *cursor_cache[CURSOR_CACHE_HASH_SIZE];
- Ring cursor_cache_lru;
- long cursor_cache_available;
- uint32_t cursor_cache_items;
-} CursorChannelClient;
-
-typedef struct CursorChannel {
- CommonChannel common; // Must be the first thing
-
-#ifdef RED_STATISTICS
- StatNodeRef stat;
-#endif
-} CursorChannel;
-
enum {
TREE_ITEM_TYPE_DRAWABLE,
TREE_ITEM_TYPE_CONTAINER,
@@ -802,14 +552,6 @@ struct _Drawable {
} u;
};
-typedef struct _CursorItem _CursorItem;
-struct _CursorItem {
- union {
- CursorItem cursor_item;
- _CursorItem *next;
- } u;
-};
-
typedef struct UpgradeItem {
PipeItem base;
int refs;
@@ -11853,8 +11595,6 @@ RedWorker* red_worker_new(WorkerInitData *init_data)
int i;
const char *record_filename;
- spice_assert(sizeof(CursorItem) <= QXL_CURSUR_DEVICE_DATA_SIZE);
-
record_filename = getenv("SPICE_WORKER_RECORD_FILENAME");
if (record_filename) {
static const char header[] = "SPICE_REPLAY 1\n";
diff --git a/server/red_worker.h b/server/red_worker.h
index c935e0a7..7732e390 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -58,6 +58,26 @@ typedef struct WorkerInitData {
RedDispatcher *red_dispatcher;
} WorkerInitData;
+typedef struct CommonChannelClient {
+ RedChannelClient base;
+ uint32_t id;
+ struct RedWorker *worker;
+ int is_low_bandwidth;
+} CommonChannelClient;
+
+#define CHANNEL_RECEIVE_BUF_SIZE 1024
+typedef struct CommonChannel {
+ RedChannel base; // Must be the first thing
+ struct RedWorker *worker;
+ uint8_t recv_buf[CHANNEL_RECEIVE_BUF_SIZE];
+ uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme.
+ int during_target_migrate; /* TRUE when the client that is associated with the channel
+ is during migration. Turned off when the vm is started.
+ The flag is used to avoid sending messages that are artifacts
+ of the transition from stopped vm to loaded vm (e.g., recreation
+ of the primary surface) */
+} CommonChannel;
+
RedWorker* red_worker_new(WorkerInitData *init_data);
bool red_worker_run(RedWorker *worker);