xref: /openbmc/qemu/ui/vnc-jobs.c (revision e16f4c8770b73f530dad842a31298963b6c7e41d)
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 
29*e16f4c87SPeter 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"
352624bab8SDaniel P. Berrange 
362624bab8SDaniel P. Berrange /*
372624bab8SDaniel P. Berrange  * Locking:
382624bab8SDaniel P. Berrange  *
3911f66978SPeter Maydell  * There are three levels of locking:
402624bab8SDaniel P. Berrange  * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?)
412624bab8SDaniel P. Berrange  * - VncDisplay global lock: mainly used for framebuffer updates to avoid
422624bab8SDaniel P. Berrange  *                      screen corruption if the framebuffer is updated
432624bab8SDaniel P. Berrange  *                      while the worker is doing something.
442624bab8SDaniel P. Berrange  * - VncState::output lock: used to make sure the output buffer is not corrupted
452624bab8SDaniel P. Berrange  *                          if two threads try to write on it at the same time
462624bab8SDaniel P. Berrange  *
4711f66978SPeter Maydell  * While the VNC worker thread is working, the VncDisplay global lock is held
4811f66978SPeter Maydell  * to avoid screen corruption (this does not block vnc_refresh() because it
4911f66978SPeter Maydell  * uses trylock()) but the output lock is not held because the thread works on
502624bab8SDaniel P. Berrange  * its own output buffer.
512624bab8SDaniel P. Berrange  * When the encoding job is done, the worker thread will hold the output lock
522624bab8SDaniel P. Berrange  * and copy its output buffer in vs->output.
532624bab8SDaniel P. Berrange  */
542624bab8SDaniel P. Berrange 
552624bab8SDaniel P. Berrange struct VncJobQueue {
562624bab8SDaniel P. Berrange     QemuCond cond;
572624bab8SDaniel P. Berrange     QemuMutex mutex;
582624bab8SDaniel P. Berrange     QemuThread thread;
592624bab8SDaniel P. Berrange     bool exit;
602624bab8SDaniel P. Berrange     QTAILQ_HEAD(, VncJob) jobs;
612624bab8SDaniel P. Berrange };
622624bab8SDaniel P. Berrange 
632624bab8SDaniel P. Berrange typedef struct VncJobQueue VncJobQueue;
642624bab8SDaniel P. Berrange 
652624bab8SDaniel P. Berrange /*
662624bab8SDaniel P. Berrange  * We use a single global queue, but most of the functions are
6711f66978SPeter Maydell  * already reentrant, so we can easily add more than one encoding thread
682624bab8SDaniel P. Berrange  */
692624bab8SDaniel P. Berrange static VncJobQueue *queue;
702624bab8SDaniel P. Berrange 
712624bab8SDaniel P. Berrange static void vnc_lock_queue(VncJobQueue *queue)
722624bab8SDaniel P. Berrange {
732624bab8SDaniel P. Berrange     qemu_mutex_lock(&queue->mutex);
742624bab8SDaniel P. Berrange }
752624bab8SDaniel P. Berrange 
762624bab8SDaniel P. Berrange static void vnc_unlock_queue(VncJobQueue *queue)
772624bab8SDaniel P. Berrange {
782624bab8SDaniel P. Berrange     qemu_mutex_unlock(&queue->mutex);
792624bab8SDaniel P. Berrange }
802624bab8SDaniel P. Berrange 
812624bab8SDaniel P. Berrange VncJob *vnc_job_new(VncState *vs)
822624bab8SDaniel P. Berrange {
83fedf0d35SMarkus Armbruster     VncJob *job = g_new0(VncJob, 1);
842624bab8SDaniel P. Berrange 
852624bab8SDaniel P. Berrange     job->vs = vs;
862624bab8SDaniel P. Berrange     vnc_lock_queue(queue);
872624bab8SDaniel P. Berrange     QLIST_INIT(&job->rectangles);
882624bab8SDaniel P. Berrange     vnc_unlock_queue(queue);
892624bab8SDaniel P. Berrange     return job;
902624bab8SDaniel P. Berrange }
912624bab8SDaniel P. Berrange 
922624bab8SDaniel P. Berrange int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
932624bab8SDaniel P. Berrange {
94fedf0d35SMarkus Armbruster     VncRectEntry *entry = g_new0(VncRectEntry, 1);
952624bab8SDaniel P. Berrange 
962624bab8SDaniel P. Berrange     entry->rect.x = x;
972624bab8SDaniel P. Berrange     entry->rect.y = y;
982624bab8SDaniel P. Berrange     entry->rect.w = w;
992624bab8SDaniel P. Berrange     entry->rect.h = h;
1002624bab8SDaniel P. Berrange 
1012624bab8SDaniel P. Berrange     vnc_lock_queue(queue);
1022624bab8SDaniel P. Berrange     QLIST_INSERT_HEAD(&job->rectangles, entry, next);
1032624bab8SDaniel P. Berrange     vnc_unlock_queue(queue);
1042624bab8SDaniel P. Berrange     return 1;
1052624bab8SDaniel P. Berrange }
1062624bab8SDaniel P. Berrange 
1072624bab8SDaniel P. Berrange void vnc_job_push(VncJob *job)
1082624bab8SDaniel P. Berrange {
1092624bab8SDaniel P. Berrange     vnc_lock_queue(queue);
1102624bab8SDaniel P. Berrange     if (queue->exit || QLIST_EMPTY(&job->rectangles)) {
1112624bab8SDaniel P. Berrange         g_free(job);
1122624bab8SDaniel P. Berrange     } else {
1132624bab8SDaniel P. Berrange         QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
1142624bab8SDaniel P. Berrange         qemu_cond_broadcast(&queue->cond);
1152624bab8SDaniel P. Berrange     }
1162624bab8SDaniel P. Berrange     vnc_unlock_queue(queue);
1172624bab8SDaniel P. Berrange }
1182624bab8SDaniel P. Berrange 
1192624bab8SDaniel P. Berrange static bool vnc_has_job_locked(VncState *vs)
1202624bab8SDaniel P. Berrange {
1212624bab8SDaniel P. Berrange     VncJob *job;
1222624bab8SDaniel P. Berrange 
1232624bab8SDaniel P. Berrange     QTAILQ_FOREACH(job, &queue->jobs, next) {
1242624bab8SDaniel P. Berrange         if (job->vs == vs || !vs) {
1252624bab8SDaniel P. Berrange             return true;
1262624bab8SDaniel P. Berrange         }
1272624bab8SDaniel P. Berrange     }
1282624bab8SDaniel P. Berrange     return false;
1292624bab8SDaniel P. Berrange }
1302624bab8SDaniel P. Berrange 
1312624bab8SDaniel P. Berrange bool vnc_has_job(VncState *vs)
1322624bab8SDaniel P. Berrange {
1332624bab8SDaniel P. Berrange     bool ret;
1342624bab8SDaniel P. Berrange 
1352624bab8SDaniel P. Berrange     vnc_lock_queue(queue);
1362624bab8SDaniel P. Berrange     ret = vnc_has_job_locked(vs);
1372624bab8SDaniel P. Berrange     vnc_unlock_queue(queue);
1382624bab8SDaniel P. Berrange     return ret;
1392624bab8SDaniel P. Berrange }
1402624bab8SDaniel P. Berrange 
1412624bab8SDaniel P. Berrange void vnc_jobs_clear(VncState *vs)
1422624bab8SDaniel P. Berrange {
1432624bab8SDaniel P. Berrange     VncJob *job, *tmp;
1442624bab8SDaniel P. Berrange 
1452624bab8SDaniel P. Berrange     vnc_lock_queue(queue);
1462624bab8SDaniel P. Berrange     QTAILQ_FOREACH_SAFE(job, &queue->jobs, next, tmp) {
1472624bab8SDaniel P. Berrange         if (job->vs == vs || !vs) {
1482624bab8SDaniel P. Berrange             QTAILQ_REMOVE(&queue->jobs, job, next);
1492624bab8SDaniel P. Berrange         }
1502624bab8SDaniel P. Berrange     }
1512624bab8SDaniel P. Berrange     vnc_unlock_queue(queue);
1522624bab8SDaniel P. Berrange }
1532624bab8SDaniel P. Berrange 
1542624bab8SDaniel P. Berrange void vnc_jobs_join(VncState *vs)
1552624bab8SDaniel P. Berrange {
1562624bab8SDaniel P. Berrange     vnc_lock_queue(queue);
1572624bab8SDaniel P. Berrange     while (vnc_has_job_locked(vs)) {
1582624bab8SDaniel P. Berrange         qemu_cond_wait(&queue->cond, &queue->mutex);
1592624bab8SDaniel P. Berrange     }
1602624bab8SDaniel P. Berrange     vnc_unlock_queue(queue);
1612624bab8SDaniel P. Berrange     vnc_jobs_consume_buffer(vs);
1622624bab8SDaniel P. Berrange }
1632624bab8SDaniel P. Berrange 
1642624bab8SDaniel P. Berrange void vnc_jobs_consume_buffer(VncState *vs)
1652624bab8SDaniel P. Berrange {
1662624bab8SDaniel P. Berrange     bool flush;
1672624bab8SDaniel P. Berrange 
1682624bab8SDaniel P. Berrange     vnc_lock_output(vs);
1692624bab8SDaniel P. Berrange     if (vs->jobs_buffer.offset) {
17004d2529dSDaniel P. Berrange         if (vs->ioc != NULL && buffer_empty(&vs->output)) {
17104d2529dSDaniel P. Berrange             if (vs->ioc_tag) {
17204d2529dSDaniel P. Berrange                 g_source_remove(vs->ioc_tag);
17304d2529dSDaniel P. Berrange             }
17404d2529dSDaniel P. Berrange             vs->ioc_tag = qio_channel_add_watch(
17504d2529dSDaniel P. Berrange                 vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL);
176d9034011SGerd Hoffmann         }
177d9034011SGerd Hoffmann         buffer_move(&vs->output, &vs->jobs_buffer);
1782624bab8SDaniel P. Berrange     }
17904d2529dSDaniel P. Berrange     flush = vs->ioc != NULL && vs->abort != true;
1802624bab8SDaniel P. Berrange     vnc_unlock_output(vs);
1812624bab8SDaniel P. Berrange 
1822624bab8SDaniel P. Berrange     if (flush) {
1832624bab8SDaniel P. Berrange       vnc_flush(vs);
1842624bab8SDaniel P. Berrange     }
1852624bab8SDaniel P. Berrange }
1862624bab8SDaniel P. Berrange 
1872624bab8SDaniel P. Berrange /*
1882624bab8SDaniel P. Berrange  * Copy data for local use
1892624bab8SDaniel P. Berrange  */
1902624bab8SDaniel P. Berrange static void vnc_async_encoding_start(VncState *orig, VncState *local)
1912624bab8SDaniel P. Berrange {
1922e0c90afSGerd Hoffmann     buffer_init(&local->output, "vnc-worker-output");
19304d2529dSDaniel P. Berrange     local->sioc = NULL; /* Don't do any network work on this thread */
19404d2529dSDaniel P. Berrange     local->ioc = NULL; /* Don't do any network work on this thread */
1952e0c90afSGerd Hoffmann 
1962624bab8SDaniel P. Berrange     local->vnc_encoding = orig->vnc_encoding;
1972624bab8SDaniel P. Berrange     local->features = orig->features;
1982624bab8SDaniel P. Berrange     local->vd = orig->vd;
1992624bab8SDaniel P. Berrange     local->lossy_rect = orig->lossy_rect;
2002624bab8SDaniel P. Berrange     local->write_pixels = orig->write_pixels;
2019f64916dSGerd Hoffmann     local->client_pf = orig->client_pf;
2029f64916dSGerd Hoffmann     local->client_be = orig->client_be;
2032624bab8SDaniel P. Berrange     local->tight = orig->tight;
2042624bab8SDaniel P. Berrange     local->zlib = orig->zlib;
2052624bab8SDaniel P. Berrange     local->hextile = orig->hextile;
2062624bab8SDaniel P. Berrange     local->zrle = orig->zrle;
2072624bab8SDaniel P. Berrange }
2082624bab8SDaniel P. Berrange 
2092624bab8SDaniel P. Berrange static void vnc_async_encoding_end(VncState *orig, VncState *local)
2102624bab8SDaniel P. Berrange {
2112624bab8SDaniel P. Berrange     orig->tight = local->tight;
2122624bab8SDaniel P. Berrange     orig->zlib = local->zlib;
2132624bab8SDaniel P. Berrange     orig->hextile = local->hextile;
2142624bab8SDaniel P. Berrange     orig->zrle = local->zrle;
2152624bab8SDaniel P. Berrange     orig->lossy_rect = local->lossy_rect;
2162624bab8SDaniel P. Berrange }
2172624bab8SDaniel P. Berrange 
2182624bab8SDaniel P. Berrange static int vnc_worker_thread_loop(VncJobQueue *queue)
2192624bab8SDaniel P. Berrange {
2202624bab8SDaniel P. Berrange     VncJob *job;
2212624bab8SDaniel P. Berrange     VncRectEntry *entry, *tmp;
2222e0c90afSGerd Hoffmann     VncState vs = {};
2232624bab8SDaniel P. Berrange     int n_rectangles;
2242624bab8SDaniel P. Berrange     int saved_offset;
2252624bab8SDaniel P. Berrange 
2262624bab8SDaniel P. Berrange     vnc_lock_queue(queue);
2272624bab8SDaniel P. Berrange     while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) {
2282624bab8SDaniel P. Berrange         qemu_cond_wait(&queue->cond, &queue->mutex);
2292624bab8SDaniel P. Berrange     }
2302624bab8SDaniel P. Berrange     /* Here job can only be NULL if queue->exit is true */
2312624bab8SDaniel P. Berrange     job = QTAILQ_FIRST(&queue->jobs);
2322624bab8SDaniel P. Berrange     vnc_unlock_queue(queue);
2332624bab8SDaniel P. Berrange 
2342624bab8SDaniel P. Berrange     if (queue->exit) {
2352624bab8SDaniel P. Berrange         return -1;
2362624bab8SDaniel P. Berrange     }
2372624bab8SDaniel P. Berrange 
2382624bab8SDaniel P. Berrange     vnc_lock_output(job->vs);
23904d2529dSDaniel P. Berrange     if (job->vs->ioc == NULL || job->vs->abort == true) {
2402624bab8SDaniel P. Berrange         vnc_unlock_output(job->vs);
2412624bab8SDaniel P. Berrange         goto disconnected;
2422624bab8SDaniel P. Berrange     }
243c3d6899cSPeter Lieven     if (buffer_empty(&job->vs->output)) {
244c3d6899cSPeter Lieven         /*
245c3d6899cSPeter Lieven          * Looks like a NOP as it obviously moves no data.  But it
246c3d6899cSPeter Lieven          * moves the empty buffer, so we don't have to malloc a new
247c3d6899cSPeter Lieven          * one for vs.output
248c3d6899cSPeter Lieven          */
249c3d6899cSPeter Lieven         buffer_move_empty(&vs.output, &job->vs->output);
250c3d6899cSPeter Lieven     }
2512624bab8SDaniel P. Berrange     vnc_unlock_output(job->vs);
2522624bab8SDaniel P. Berrange 
2532624bab8SDaniel P. Berrange     /* Make a local copy of vs and switch output buffers */
2542624bab8SDaniel P. Berrange     vnc_async_encoding_start(job->vs, &vs);
2552624bab8SDaniel P. Berrange 
2562624bab8SDaniel P. Berrange     /* Start sending rectangles */
2572624bab8SDaniel P. Berrange     n_rectangles = 0;
2582624bab8SDaniel P. Berrange     vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
2592624bab8SDaniel P. Berrange     vnc_write_u8(&vs, 0);
2602624bab8SDaniel P. Berrange     saved_offset = vs.output.offset;
2612624bab8SDaniel P. Berrange     vnc_write_u16(&vs, 0);
2622624bab8SDaniel P. Berrange 
2632624bab8SDaniel P. Berrange     vnc_lock_display(job->vs->vd);
2642624bab8SDaniel P. Berrange     QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
2652624bab8SDaniel P. Berrange         int n;
2662624bab8SDaniel P. Berrange 
26704d2529dSDaniel P. Berrange         if (job->vs->ioc == NULL) {
2682624bab8SDaniel P. Berrange             vnc_unlock_display(job->vs->vd);
269e3c1adf1SGonglei (Arei)             /* Copy persistent encoding data */
270e3c1adf1SGonglei (Arei)             vnc_async_encoding_end(job->vs, &vs);
2712624bab8SDaniel P. Berrange             goto disconnected;
2722624bab8SDaniel P. Berrange         }
2732624bab8SDaniel P. Berrange 
2742624bab8SDaniel P. Berrange         n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
2752624bab8SDaniel P. Berrange                                         entry->rect.w, entry->rect.h);
2762624bab8SDaniel P. Berrange 
2772624bab8SDaniel P. Berrange         if (n >= 0) {
2782624bab8SDaniel P. Berrange             n_rectangles += n;
2792624bab8SDaniel P. Berrange         }
2802624bab8SDaniel P. Berrange         g_free(entry);
2812624bab8SDaniel P. Berrange     }
2822624bab8SDaniel P. Berrange     vnc_unlock_display(job->vs->vd);
2832624bab8SDaniel P. Berrange 
2842624bab8SDaniel P. Berrange     /* Put n_rectangles at the beginning of the message */
2852624bab8SDaniel P. Berrange     vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
2862624bab8SDaniel P. Berrange     vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
2872624bab8SDaniel P. Berrange 
2882624bab8SDaniel P. Berrange     vnc_lock_output(job->vs);
28904d2529dSDaniel P. Berrange     if (job->vs->ioc != NULL) {
290d9034011SGerd Hoffmann         buffer_move(&job->vs->jobs_buffer, &vs.output);
2912624bab8SDaniel P. Berrange         /* Copy persistent encoding data */
2922624bab8SDaniel P. Berrange         vnc_async_encoding_end(job->vs, &vs);
2932624bab8SDaniel P. Berrange 
2942624bab8SDaniel P. Berrange 	qemu_bh_schedule(job->vs->bh);
295e3c1adf1SGonglei (Arei)     }  else {
296d9034011SGerd Hoffmann         buffer_reset(&vs.output);
297e3c1adf1SGonglei (Arei)         /* Copy persistent encoding data */
298e3c1adf1SGonglei (Arei)         vnc_async_encoding_end(job->vs, &vs);
2992624bab8SDaniel P. Berrange     }
3002624bab8SDaniel P. Berrange     vnc_unlock_output(job->vs);
3012624bab8SDaniel P. Berrange 
3022624bab8SDaniel P. Berrange disconnected:
3032624bab8SDaniel P. Berrange     vnc_lock_queue(queue);
3042624bab8SDaniel P. Berrange     QTAILQ_REMOVE(&queue->jobs, job, next);
3052624bab8SDaniel P. Berrange     vnc_unlock_queue(queue);
3062624bab8SDaniel P. Berrange     qemu_cond_broadcast(&queue->cond);
3072624bab8SDaniel P. Berrange     g_free(job);
3082624bab8SDaniel P. Berrange     return 0;
3092624bab8SDaniel P. Berrange }
3102624bab8SDaniel P. Berrange 
3112624bab8SDaniel P. Berrange static VncJobQueue *vnc_queue_init(void)
3122624bab8SDaniel P. Berrange {
313fedf0d35SMarkus Armbruster     VncJobQueue *queue = g_new0(VncJobQueue, 1);
3142624bab8SDaniel P. Berrange 
3152624bab8SDaniel P. Berrange     qemu_cond_init(&queue->cond);
3162624bab8SDaniel P. Berrange     qemu_mutex_init(&queue->mutex);
3172624bab8SDaniel P. Berrange     QTAILQ_INIT(&queue->jobs);
3182624bab8SDaniel P. Berrange     return queue;
3192624bab8SDaniel P. Berrange }
3202624bab8SDaniel P. Berrange 
3212624bab8SDaniel P. Berrange static void vnc_queue_clear(VncJobQueue *q)
3222624bab8SDaniel P. Berrange {
3232624bab8SDaniel P. Berrange     qemu_cond_destroy(&queue->cond);
3242624bab8SDaniel P. Berrange     qemu_mutex_destroy(&queue->mutex);
3252624bab8SDaniel P. Berrange     g_free(q);
3262624bab8SDaniel P. Berrange     queue = NULL; /* Unset global queue */
3272624bab8SDaniel P. Berrange }
3282624bab8SDaniel P. Berrange 
3292624bab8SDaniel P. Berrange static void *vnc_worker_thread(void *arg)
3302624bab8SDaniel P. Berrange {
3312624bab8SDaniel P. Berrange     VncJobQueue *queue = arg;
3322624bab8SDaniel P. Berrange 
3332624bab8SDaniel P. Berrange     qemu_thread_get_self(&queue->thread);
3342624bab8SDaniel P. Berrange 
3352624bab8SDaniel P. Berrange     while (!vnc_worker_thread_loop(queue)) ;
3362624bab8SDaniel P. Berrange     vnc_queue_clear(queue);
3372624bab8SDaniel P. Berrange     return NULL;
3382624bab8SDaniel P. Berrange }
3392624bab8SDaniel P. Berrange 
34071a8cdecSBlue Swirl static bool vnc_worker_thread_running(void)
34171a8cdecSBlue Swirl {
34271a8cdecSBlue Swirl     return queue; /* Check global queue */
34371a8cdecSBlue Swirl }
34471a8cdecSBlue Swirl 
3452624bab8SDaniel P. Berrange void vnc_start_worker_thread(void)
3462624bab8SDaniel P. Berrange {
3472624bab8SDaniel P. Berrange     VncJobQueue *q;
3482624bab8SDaniel P. Berrange 
3492624bab8SDaniel P. Berrange     if (vnc_worker_thread_running())
3502624bab8SDaniel P. Berrange         return ;
3512624bab8SDaniel P. Berrange 
3522624bab8SDaniel P. Berrange     q = vnc_queue_init();
3534900116eSDr. David Alan Gilbert     qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q,
3544900116eSDr. David Alan Gilbert                        QEMU_THREAD_DETACHED);
3552624bab8SDaniel P. Berrange     queue = q; /* Set global queue */
3562624bab8SDaniel P. Berrange }
357