12624bab8SDaniel P. Berrange /*
22624bab8SDaniel P. Berrange * QEMU VNC display driver
32624bab8SDaniel P. Berrange *
42624bab8SDaniel P. Berrange * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
52624bab8SDaniel P. Berrange * Copyright (C) 2006 Fabrice Bellard
62624bab8SDaniel P. Berrange * Copyright (C) 2009 Red Hat, Inc
72624bab8SDaniel P. Berrange * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
82624bab8SDaniel P. Berrange *
92624bab8SDaniel P. Berrange * Permission is hereby granted, free of charge, to any person obtaining a copy
102624bab8SDaniel P. Berrange * of this software and associated documentation files (the "Software"), to deal
112624bab8SDaniel P. Berrange * in the Software without restriction, including without limitation the rights
122624bab8SDaniel P. Berrange * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
132624bab8SDaniel P. Berrange * copies of the Software, and to permit persons to whom the Software is
142624bab8SDaniel P. Berrange * furnished to do so, subject to the following conditions:
152624bab8SDaniel P. Berrange *
162624bab8SDaniel P. Berrange * The above copyright notice and this permission notice shall be included in
172624bab8SDaniel P. Berrange * all copies or substantial portions of the Software.
182624bab8SDaniel P. Berrange *
192624bab8SDaniel P. Berrange * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
202624bab8SDaniel P. Berrange * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
212624bab8SDaniel P. Berrange * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
222624bab8SDaniel P. Berrange * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
232624bab8SDaniel P. Berrange * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
242624bab8SDaniel P. Berrange * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
252624bab8SDaniel P. Berrange * THE SOFTWARE.
262624bab8SDaniel P. Berrange */
272624bab8SDaniel P. Berrange
282624bab8SDaniel P. Berrange
29e16f4c87SPeter Maydell #include "qemu/osdep.h"
302624bab8SDaniel P. Berrange #include "vnc.h"
312624bab8SDaniel P. Berrange #include "vnc-jobs.h"
321de7afc9SPaolo Bonzini #include "qemu/sockets.h"
33d9034011SGerd Hoffmann #include "qemu/main-loop.h"
34a0b1a66eSMarkus Armbruster #include "block/aio.h"
3555b40049SDaniel P. Berrangé #include "trace.h"
362624bab8SDaniel P. Berrange
372624bab8SDaniel P. Berrange /*
382624bab8SDaniel P. Berrange * Locking:
392624bab8SDaniel P. Berrange *
4011f66978SPeter Maydell * There are three levels of locking:
412624bab8SDaniel P. Berrange * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?)
422624bab8SDaniel P. Berrange * - VncDisplay global lock: mainly used for framebuffer updates to avoid
432624bab8SDaniel P. Berrange * screen corruption if the framebuffer is updated
442624bab8SDaniel P. Berrange * while the worker is doing something.
452624bab8SDaniel P. Berrange * - VncState::output lock: used to make sure the output buffer is not corrupted
462624bab8SDaniel P. Berrange * if two threads try to write on it at the same time
472624bab8SDaniel P. Berrange *
4811f66978SPeter Maydell * While the VNC worker thread is working, the VncDisplay global lock is held
4911f66978SPeter Maydell * to avoid screen corruption (this does not block vnc_refresh() because it
5011f66978SPeter Maydell * uses trylock()) but the output lock is not held because the thread works on
512624bab8SDaniel P. Berrange * its own output buffer.
522624bab8SDaniel P. Berrange * When the encoding job is done, the worker thread will hold the output lock
532624bab8SDaniel P. Berrange * and copy its output buffer in vs->output.
542624bab8SDaniel P. Berrange */
552624bab8SDaniel P. Berrange
562624bab8SDaniel P. Berrange struct VncJobQueue {
572624bab8SDaniel P. Berrange QemuCond cond;
582624bab8SDaniel P. Berrange QemuMutex mutex;
592624bab8SDaniel P. Berrange QemuThread thread;
602624bab8SDaniel P. Berrange bool exit;
612624bab8SDaniel P. Berrange QTAILQ_HEAD(, VncJob) jobs;
622624bab8SDaniel P. Berrange };
632624bab8SDaniel P. Berrange
642624bab8SDaniel P. Berrange typedef struct VncJobQueue VncJobQueue;
652624bab8SDaniel P. Berrange
662624bab8SDaniel P. Berrange /*
672624bab8SDaniel P. Berrange * We use a single global queue, but most of the functions are
6811f66978SPeter Maydell * already reentrant, so we can easily add more than one encoding thread
692624bab8SDaniel P. Berrange */
702624bab8SDaniel P. Berrange static VncJobQueue *queue;
712624bab8SDaniel P. Berrange
vnc_lock_queue(VncJobQueue * queue)722624bab8SDaniel P. Berrange static void vnc_lock_queue(VncJobQueue *queue)
732624bab8SDaniel P. Berrange {
742624bab8SDaniel P. Berrange qemu_mutex_lock(&queue->mutex);
752624bab8SDaniel P. Berrange }
762624bab8SDaniel P. Berrange
vnc_unlock_queue(VncJobQueue * queue)772624bab8SDaniel P. Berrange static void vnc_unlock_queue(VncJobQueue *queue)
782624bab8SDaniel P. Berrange {
792624bab8SDaniel P. Berrange qemu_mutex_unlock(&queue->mutex);
802624bab8SDaniel P. Berrange }
812624bab8SDaniel P. Berrange
vnc_job_new(VncState * vs)822624bab8SDaniel P. Berrange VncJob *vnc_job_new(VncState *vs)
832624bab8SDaniel P. Berrange {
84fedf0d35SMarkus Armbruster VncJob *job = g_new0(VncJob, 1);
852624bab8SDaniel P. Berrange
86f31f9c10SGerd Hoffmann assert(vs->magic == VNC_MAGIC);
872624bab8SDaniel P. Berrange job->vs = vs;
882624bab8SDaniel P. Berrange vnc_lock_queue(queue);
892624bab8SDaniel P. Berrange QLIST_INIT(&job->rectangles);
902624bab8SDaniel P. Berrange vnc_unlock_queue(queue);
912624bab8SDaniel P. Berrange return job;
922624bab8SDaniel P. Berrange }
932624bab8SDaniel P. Berrange
vnc_job_add_rect(VncJob * job,int x,int y,int w,int h)942624bab8SDaniel P. Berrange int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
952624bab8SDaniel P. Berrange {
96fedf0d35SMarkus Armbruster VncRectEntry *entry = g_new0(VncRectEntry, 1);
972624bab8SDaniel P. Berrange
9855b40049SDaniel P. Berrangé trace_vnc_job_add_rect(job->vs, job, x, y, w, h);
9955b40049SDaniel P. Berrangé
1002624bab8SDaniel P. Berrange entry->rect.x = x;
1012624bab8SDaniel P. Berrange entry->rect.y = y;
1022624bab8SDaniel P. Berrange entry->rect.w = w;
1032624bab8SDaniel P. Berrange entry->rect.h = h;
1042624bab8SDaniel P. Berrange
1052624bab8SDaniel P. Berrange vnc_lock_queue(queue);
1062624bab8SDaniel P. Berrange QLIST_INSERT_HEAD(&job->rectangles, entry, next);
1072624bab8SDaniel P. Berrange vnc_unlock_queue(queue);
1082624bab8SDaniel P. Berrange return 1;
1092624bab8SDaniel P. Berrange }
1102624bab8SDaniel P. Berrange
vnc_job_push(VncJob * job)1112624bab8SDaniel P. Berrange void vnc_job_push(VncJob *job)
1122624bab8SDaniel P. Berrange {
1132624bab8SDaniel P. Berrange vnc_lock_queue(queue);
1142624bab8SDaniel P. Berrange if (queue->exit || QLIST_EMPTY(&job->rectangles)) {
1152624bab8SDaniel P. Berrange g_free(job);
1162624bab8SDaniel P. Berrange } else {
1172624bab8SDaniel P. Berrange QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
1182624bab8SDaniel P. Berrange qemu_cond_broadcast(&queue->cond);
1192624bab8SDaniel P. Berrange }
1202624bab8SDaniel P. Berrange vnc_unlock_queue(queue);
1212624bab8SDaniel P. Berrange }
1222624bab8SDaniel P. Berrange
vnc_has_job_locked(VncState * vs)1232624bab8SDaniel P. Berrange static bool vnc_has_job_locked(VncState *vs)
1242624bab8SDaniel P. Berrange {
1252624bab8SDaniel P. Berrange VncJob *job;
1262624bab8SDaniel P. Berrange
1272624bab8SDaniel P. Berrange QTAILQ_FOREACH(job, &queue->jobs, next) {
1282624bab8SDaniel P. Berrange if (job->vs == vs || !vs) {
1292624bab8SDaniel P. Berrange return true;
1302624bab8SDaniel P. Berrange }
1312624bab8SDaniel P. Berrange }
1322624bab8SDaniel P. Berrange return false;
1332624bab8SDaniel P. Berrange }
1342624bab8SDaniel P. Berrange
vnc_jobs_join(VncState * vs)1352624bab8SDaniel P. Berrange void vnc_jobs_join(VncState *vs)
1362624bab8SDaniel P. Berrange {
1372624bab8SDaniel P. Berrange vnc_lock_queue(queue);
1382624bab8SDaniel P. Berrange while (vnc_has_job_locked(vs)) {
1392624bab8SDaniel P. Berrange qemu_cond_wait(&queue->cond, &queue->mutex);
1402624bab8SDaniel P. Berrange }
1412624bab8SDaniel P. Berrange vnc_unlock_queue(queue);
1422624bab8SDaniel P. Berrange vnc_jobs_consume_buffer(vs);
1432624bab8SDaniel P. Berrange }
1442624bab8SDaniel P. Berrange
vnc_jobs_consume_buffer(VncState * vs)1452624bab8SDaniel P. Berrange void vnc_jobs_consume_buffer(VncState *vs)
1462624bab8SDaniel P. Berrange {
1472624bab8SDaniel P. Berrange bool flush;
1482624bab8SDaniel P. Berrange
1492624bab8SDaniel P. Berrange vnc_lock_output(vs);
1502624bab8SDaniel P. Berrange if (vs->jobs_buffer.offset) {
15104d2529dSDaniel P. Berrange if (vs->ioc != NULL && buffer_empty(&vs->output)) {
15204d2529dSDaniel P. Berrange if (vs->ioc_tag) {
15304d2529dSDaniel P. Berrange g_source_remove(vs->ioc_tag);
15404d2529dSDaniel P. Berrange }
155d49b87f0SKlim Kireev if (vs->disconnecting == FALSE) {
15604d2529dSDaniel P. Berrange vs->ioc_tag = qio_channel_add_watch(
1572ddafce7SDing Hui vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_OUT,
1582ddafce7SDing Hui vnc_client_io, vs, NULL);
159d9034011SGerd Hoffmann }
160d49b87f0SKlim Kireev }
161d9034011SGerd Hoffmann buffer_move(&vs->output, &vs->jobs_buffer);
162ada8d2e4SDaniel P. Berrange
163ada8d2e4SDaniel P. Berrange if (vs->job_update == VNC_STATE_UPDATE_FORCE) {
164ada8d2e4SDaniel P. Berrange vs->force_update_offset = vs->output.offset;
165ada8d2e4SDaniel P. Berrange }
166ada8d2e4SDaniel P. Berrange vs->job_update = VNC_STATE_UPDATE_NONE;
1672624bab8SDaniel P. Berrange }
16804d2529dSDaniel P. Berrange flush = vs->ioc != NULL && vs->abort != true;
1692624bab8SDaniel P. Berrange vnc_unlock_output(vs);
1702624bab8SDaniel P. Berrange
1712624bab8SDaniel P. Berrange if (flush) {
1722624bab8SDaniel P. Berrange vnc_flush(vs);
1732624bab8SDaniel P. Berrange }
1742624bab8SDaniel P. Berrange }
1752624bab8SDaniel P. Berrange
1762624bab8SDaniel P. Berrange /*
1772624bab8SDaniel P. Berrange * Copy data for local use
1782624bab8SDaniel P. Berrange */
vnc_async_encoding_start(VncState * orig,VncState * local)1792624bab8SDaniel P. Berrange static void vnc_async_encoding_start(VncState *orig, VncState *local)
1802624bab8SDaniel P. Berrange {
1812e0c90afSGerd Hoffmann buffer_init(&local->output, "vnc-worker-output");
18204d2529dSDaniel P. Berrange local->sioc = NULL; /* Don't do any network work on this thread */
18304d2529dSDaniel P. Berrange local->ioc = NULL; /* Don't do any network work on this thread */
1842e0c90afSGerd Hoffmann
1852624bab8SDaniel P. Berrange local->vnc_encoding = orig->vnc_encoding;
1862624bab8SDaniel P. Berrange local->features = orig->features;
1872624bab8SDaniel P. Berrange local->vd = orig->vd;
1882624bab8SDaniel P. Berrange local->lossy_rect = orig->lossy_rect;
1892624bab8SDaniel P. Berrange local->write_pixels = orig->write_pixels;
1909f64916dSGerd Hoffmann local->client_pf = orig->client_pf;
1919f64916dSGerd Hoffmann local->client_be = orig->client_be;
1922624bab8SDaniel P. Berrange local->tight = orig->tight;
1932624bab8SDaniel P. Berrange local->zlib = orig->zlib;
1942624bab8SDaniel P. Berrange local->hextile = orig->hextile;
1952624bab8SDaniel P. Berrange local->zrle = orig->zrle;
19655b40049SDaniel P. Berrangé local->client_width = orig->client_width;
19755b40049SDaniel P. Berrangé local->client_height = orig->client_height;
1982624bab8SDaniel P. Berrange }
1992624bab8SDaniel P. Berrange
vnc_async_encoding_end(VncState * orig,VncState * local)2002624bab8SDaniel P. Berrange static void vnc_async_encoding_end(VncState *orig, VncState *local)
2012624bab8SDaniel P. Berrange {
2020ae0b069SPeter Wu buffer_free(&local->output);
2032624bab8SDaniel P. Berrange orig->tight = local->tight;
2042624bab8SDaniel P. Berrange orig->zlib = local->zlib;
2052624bab8SDaniel P. Berrange orig->hextile = local->hextile;
2062624bab8SDaniel P. Berrange orig->zrle = local->zrle;
2072624bab8SDaniel P. Berrange orig->lossy_rect = local->lossy_rect;
2082624bab8SDaniel P. Berrange }
2092624bab8SDaniel P. Berrange
vnc_worker_clamp_rect(VncState * vs,VncJob * job,VncRect * rect)21055b40049SDaniel P. Berrangé static bool vnc_worker_clamp_rect(VncState *vs, VncJob *job, VncRect *rect)
21155b40049SDaniel P. Berrangé {
21255b40049SDaniel P. Berrangé trace_vnc_job_clamp_rect(vs, job, rect->x, rect->y, rect->w, rect->h);
21355b40049SDaniel P. Berrangé
21455b40049SDaniel P. Berrangé if (rect->x >= vs->client_width) {
21555b40049SDaniel P. Berrangé goto discard;
21655b40049SDaniel P. Berrangé }
21755b40049SDaniel P. Berrangé rect->w = MIN(vs->client_width - rect->x, rect->w);
21855b40049SDaniel P. Berrangé if (rect->w == 0) {
21955b40049SDaniel P. Berrangé goto discard;
22055b40049SDaniel P. Berrangé }
22155b40049SDaniel P. Berrangé
22255b40049SDaniel P. Berrangé if (rect->y >= vs->client_height) {
22355b40049SDaniel P. Berrangé goto discard;
22455b40049SDaniel P. Berrangé }
22555b40049SDaniel P. Berrangé rect->h = MIN(vs->client_height - rect->y, rect->h);
22655b40049SDaniel P. Berrangé if (rect->h == 0) {
22755b40049SDaniel P. Berrangé goto discard;
22855b40049SDaniel P. Berrangé }
22955b40049SDaniel P. Berrangé
23055b40049SDaniel P. Berrangé trace_vnc_job_clamped_rect(vs, job, rect->x, rect->y, rect->w, rect->h);
23155b40049SDaniel P. Berrangé return true;
23255b40049SDaniel P. Berrangé
23355b40049SDaniel P. Berrangé discard:
23455b40049SDaniel P. Berrangé trace_vnc_job_discard_rect(vs, job, rect->x, rect->y, rect->w, rect->h);
23555b40049SDaniel P. Berrangé return false;
23655b40049SDaniel P. Berrangé }
23755b40049SDaniel P. Berrangé
vnc_worker_thread_loop(VncJobQueue * queue)2382624bab8SDaniel P. Berrange static int vnc_worker_thread_loop(VncJobQueue *queue)
2392624bab8SDaniel P. Berrange {
2402624bab8SDaniel P. Berrange VncJob *job;
2412624bab8SDaniel P. Berrange VncRectEntry *entry, *tmp;
2422e0c90afSGerd Hoffmann VncState vs = {};
2432624bab8SDaniel P. Berrange int n_rectangles;
2442624bab8SDaniel P. Berrange int saved_offset;
2452624bab8SDaniel P. Berrange
2462624bab8SDaniel P. Berrange vnc_lock_queue(queue);
2472624bab8SDaniel P. Berrange while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) {
2482624bab8SDaniel P. Berrange qemu_cond_wait(&queue->cond, &queue->mutex);
2492624bab8SDaniel P. Berrange }
2502624bab8SDaniel P. Berrange /* Here job can only be NULL if queue->exit is true */
2512624bab8SDaniel P. Berrange job = QTAILQ_FIRST(&queue->jobs);
2522624bab8SDaniel P. Berrange vnc_unlock_queue(queue);
2532624bab8SDaniel P. Berrange
2542624bab8SDaniel P. Berrange if (queue->exit) {
2552624bab8SDaniel P. Berrange return -1;
2562624bab8SDaniel P. Berrange }
2572624bab8SDaniel P. Berrange
258*bdfca8a2SAnastasia Belova assert(job->vs->magic == VNC_MAGIC);
259*bdfca8a2SAnastasia Belova
2602624bab8SDaniel P. Berrange vnc_lock_output(job->vs);
26104d2529dSDaniel P. Berrange if (job->vs->ioc == NULL || job->vs->abort == true) {
2622624bab8SDaniel P. Berrange vnc_unlock_output(job->vs);
2632624bab8SDaniel P. Berrange goto disconnected;
2642624bab8SDaniel P. Berrange }
265c3d6899cSPeter Lieven if (buffer_empty(&job->vs->output)) {
266c3d6899cSPeter Lieven /*
267c3d6899cSPeter Lieven * Looks like a NOP as it obviously moves no data. But it
268c3d6899cSPeter Lieven * moves the empty buffer, so we don't have to malloc a new
269c3d6899cSPeter Lieven * one for vs.output
270c3d6899cSPeter Lieven */
271c3d6899cSPeter Lieven buffer_move_empty(&vs.output, &job->vs->output);
272c3d6899cSPeter Lieven }
2732624bab8SDaniel P. Berrange vnc_unlock_output(job->vs);
2742624bab8SDaniel P. Berrange
2752624bab8SDaniel P. Berrange /* Make a local copy of vs and switch output buffers */
2762624bab8SDaniel P. Berrange vnc_async_encoding_start(job->vs, &vs);
277f31f9c10SGerd Hoffmann vs.magic = VNC_MAGIC;
2782624bab8SDaniel P. Berrange
2792624bab8SDaniel P. Berrange /* Start sending rectangles */
2802624bab8SDaniel P. Berrange n_rectangles = 0;
2812624bab8SDaniel P. Berrange vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
2822624bab8SDaniel P. Berrange vnc_write_u8(&vs, 0);
2832624bab8SDaniel P. Berrange saved_offset = vs.output.offset;
2842624bab8SDaniel P. Berrange vnc_write_u16(&vs, 0);
2852624bab8SDaniel P. Berrange
2862624bab8SDaniel P. Berrange vnc_lock_display(job->vs->vd);
2872624bab8SDaniel P. Berrange QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
2882624bab8SDaniel P. Berrange int n;
2892624bab8SDaniel P. Berrange
29004d2529dSDaniel P. Berrange if (job->vs->ioc == NULL) {
2912624bab8SDaniel P. Berrange vnc_unlock_display(job->vs->vd);
292e3c1adf1SGonglei (Arei) /* Copy persistent encoding data */
293e3c1adf1SGonglei (Arei) vnc_async_encoding_end(job->vs, &vs);
2942624bab8SDaniel P. Berrange goto disconnected;
2952624bab8SDaniel P. Berrange }
2962624bab8SDaniel P. Berrange
29755b40049SDaniel P. Berrangé if (vnc_worker_clamp_rect(&vs, job, &entry->rect)) {
2982624bab8SDaniel P. Berrange n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
2992624bab8SDaniel P. Berrange entry->rect.w, entry->rect.h);
3002624bab8SDaniel P. Berrange
3012624bab8SDaniel P. Berrange if (n >= 0) {
3022624bab8SDaniel P. Berrange n_rectangles += n;
3032624bab8SDaniel P. Berrange }
30455b40049SDaniel P. Berrangé }
3052624bab8SDaniel P. Berrange g_free(entry);
3062624bab8SDaniel P. Berrange }
30755b40049SDaniel P. Berrangé trace_vnc_job_nrects(&vs, job, n_rectangles);
3082624bab8SDaniel P. Berrange vnc_unlock_display(job->vs->vd);
3092624bab8SDaniel P. Berrange
3102624bab8SDaniel P. Berrange /* Put n_rectangles at the beginning of the message */
3112624bab8SDaniel P. Berrange vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
3122624bab8SDaniel P. Berrange vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
3132624bab8SDaniel P. Berrange
3142624bab8SDaniel P. Berrange vnc_lock_output(job->vs);
31504d2529dSDaniel P. Berrange if (job->vs->ioc != NULL) {
316d9034011SGerd Hoffmann buffer_move(&job->vs->jobs_buffer, &vs.output);
3172624bab8SDaniel P. Berrange /* Copy persistent encoding data */
3182624bab8SDaniel P. Berrange vnc_async_encoding_end(job->vs, &vs);
3192624bab8SDaniel P. Berrange
3202624bab8SDaniel P. Berrange qemu_bh_schedule(job->vs->bh);
321e3c1adf1SGonglei (Arei) } else {
322d9034011SGerd Hoffmann buffer_reset(&vs.output);
323e3c1adf1SGonglei (Arei) /* Copy persistent encoding data */
324e3c1adf1SGonglei (Arei) vnc_async_encoding_end(job->vs, &vs);
3252624bab8SDaniel P. Berrange }
3262624bab8SDaniel P. Berrange vnc_unlock_output(job->vs);
3272624bab8SDaniel P. Berrange
3282624bab8SDaniel P. Berrange disconnected:
3292624bab8SDaniel P. Berrange vnc_lock_queue(queue);
3302624bab8SDaniel P. Berrange QTAILQ_REMOVE(&queue->jobs, job, next);
3312624bab8SDaniel P. Berrange vnc_unlock_queue(queue);
3322624bab8SDaniel P. Berrange qemu_cond_broadcast(&queue->cond);
3332624bab8SDaniel P. Berrange g_free(job);
334f31f9c10SGerd Hoffmann vs.magic = 0;
3352624bab8SDaniel P. Berrange return 0;
3362624bab8SDaniel P. Berrange }
3372624bab8SDaniel P. Berrange
vnc_queue_init(void)3382624bab8SDaniel P. Berrange static VncJobQueue *vnc_queue_init(void)
3392624bab8SDaniel P. Berrange {
340fedf0d35SMarkus Armbruster VncJobQueue *queue = g_new0(VncJobQueue, 1);
3412624bab8SDaniel P. Berrange
3422624bab8SDaniel P. Berrange qemu_cond_init(&queue->cond);
3432624bab8SDaniel P. Berrange qemu_mutex_init(&queue->mutex);
3442624bab8SDaniel P. Berrange QTAILQ_INIT(&queue->jobs);
3452624bab8SDaniel P. Berrange return queue;
3462624bab8SDaniel P. Berrange }
3472624bab8SDaniel P. Berrange
vnc_queue_clear(VncJobQueue * q)3482624bab8SDaniel P. Berrange static void vnc_queue_clear(VncJobQueue *q)
3492624bab8SDaniel P. Berrange {
3502624bab8SDaniel P. Berrange qemu_cond_destroy(&queue->cond);
3512624bab8SDaniel P. Berrange qemu_mutex_destroy(&queue->mutex);
3522624bab8SDaniel P. Berrange g_free(q);
3532624bab8SDaniel P. Berrange queue = NULL; /* Unset global queue */
3542624bab8SDaniel P. Berrange }
3552624bab8SDaniel P. Berrange
vnc_worker_thread(void * arg)3562624bab8SDaniel P. Berrange static void *vnc_worker_thread(void *arg)
3572624bab8SDaniel P. Berrange {
3582624bab8SDaniel P. Berrange VncJobQueue *queue = arg;
3592624bab8SDaniel P. Berrange
3602624bab8SDaniel P. Berrange qemu_thread_get_self(&queue->thread);
3612624bab8SDaniel P. Berrange
3622624bab8SDaniel P. Berrange while (!vnc_worker_thread_loop(queue)) ;
3632624bab8SDaniel P. Berrange vnc_queue_clear(queue);
3642624bab8SDaniel P. Berrange return NULL;
3652624bab8SDaniel P. Berrange }
3662624bab8SDaniel P. Berrange
vnc_worker_thread_running(void)36771a8cdecSBlue Swirl static bool vnc_worker_thread_running(void)
36871a8cdecSBlue Swirl {
36971a8cdecSBlue Swirl return queue; /* Check global queue */
37071a8cdecSBlue Swirl }
37171a8cdecSBlue Swirl
vnc_start_worker_thread(void)3722624bab8SDaniel P. Berrange void vnc_start_worker_thread(void)
3732624bab8SDaniel P. Berrange {
3742624bab8SDaniel P. Berrange VncJobQueue *q;
3752624bab8SDaniel P. Berrange
3762624bab8SDaniel P. Berrange if (vnc_worker_thread_running())
3772624bab8SDaniel P. Berrange return;
3782624bab8SDaniel P. Berrange
3792624bab8SDaniel P. Berrange q = vnc_queue_init();
3804900116eSDr. David Alan Gilbert qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q,
3814900116eSDr. David Alan Gilbert QEMU_THREAD_DETACHED);
3822624bab8SDaniel P. Berrange queue = q; /* Set global queue */
3832624bab8SDaniel P. Berrange }
384