1*2624bab8SDaniel P. Berrange /* 2*2624bab8SDaniel P. Berrange * QEMU VNC display driver 3*2624bab8SDaniel P. Berrange * 4*2624bab8SDaniel P. Berrange * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws> 5*2624bab8SDaniel P. Berrange * Copyright (C) 2006 Fabrice Bellard 6*2624bab8SDaniel P. Berrange * Copyright (C) 2009 Red Hat, Inc 7*2624bab8SDaniel P. Berrange * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> 8*2624bab8SDaniel P. Berrange * 9*2624bab8SDaniel P. Berrange * Permission is hereby granted, free of charge, to any person obtaining a copy 10*2624bab8SDaniel P. Berrange * of this software and associated documentation files (the "Software"), to deal 11*2624bab8SDaniel P. Berrange * in the Software without restriction, including without limitation the rights 12*2624bab8SDaniel P. Berrange * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13*2624bab8SDaniel P. Berrange * copies of the Software, and to permit persons to whom the Software is 14*2624bab8SDaniel P. Berrange * furnished to do so, subject to the following conditions: 15*2624bab8SDaniel P. Berrange * 16*2624bab8SDaniel P. Berrange * The above copyright notice and this permission notice shall be included in 17*2624bab8SDaniel P. Berrange * all copies or substantial portions of the Software. 18*2624bab8SDaniel P. Berrange * 19*2624bab8SDaniel P. Berrange * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20*2624bab8SDaniel P. Berrange * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21*2624bab8SDaniel P. Berrange * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22*2624bab8SDaniel P. Berrange * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23*2624bab8SDaniel P. Berrange * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24*2624bab8SDaniel P. Berrange * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25*2624bab8SDaniel P. Berrange * THE SOFTWARE. 26*2624bab8SDaniel P. Berrange */ 27*2624bab8SDaniel P. Berrange 28*2624bab8SDaniel P. Berrange 29*2624bab8SDaniel P. Berrange #include "vnc.h" 30*2624bab8SDaniel P. Berrange #include "vnc-jobs.h" 31*2624bab8SDaniel P. Berrange #include "qemu_socket.h" 32*2624bab8SDaniel P. Berrange 33*2624bab8SDaniel P. Berrange /* 34*2624bab8SDaniel P. Berrange * Locking: 35*2624bab8SDaniel P. Berrange * 36*2624bab8SDaniel P. Berrange * There is three levels of locking: 37*2624bab8SDaniel P. Berrange * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?) 38*2624bab8SDaniel P. Berrange * - VncDisplay global lock: mainly used for framebuffer updates to avoid 39*2624bab8SDaniel P. Berrange * screen corruption if the framebuffer is updated 40*2624bab8SDaniel P. Berrange * while the worker is doing something. 41*2624bab8SDaniel P. Berrange * - VncState::output lock: used to make sure the output buffer is not corrupted 42*2624bab8SDaniel P. Berrange * if two threads try to write on it at the same time 43*2624bab8SDaniel P. Berrange * 44*2624bab8SDaniel P. Berrange * While the VNC worker thread is working, the VncDisplay global lock is hold 45*2624bab8SDaniel P. Berrange * to avoid screen corruptions (this does not block vnc_refresh() because it 46*2624bab8SDaniel P. Berrange * uses trylock()) but the output lock is not hold because the thread work on 47*2624bab8SDaniel P. Berrange * its own output buffer. 48*2624bab8SDaniel P. Berrange * When the encoding job is done, the worker thread will hold the output lock 49*2624bab8SDaniel P. Berrange * and copy its output buffer in vs->output. 50*2624bab8SDaniel P. Berrange */ 51*2624bab8SDaniel P. Berrange 52*2624bab8SDaniel P. Berrange struct VncJobQueue { 53*2624bab8SDaniel P. Berrange QemuCond cond; 54*2624bab8SDaniel P. Berrange QemuMutex mutex; 55*2624bab8SDaniel P. Berrange QemuThread thread; 56*2624bab8SDaniel P. Berrange Buffer buffer; 57*2624bab8SDaniel P. Berrange bool exit; 58*2624bab8SDaniel P. Berrange QTAILQ_HEAD(, VncJob) jobs; 59*2624bab8SDaniel P. Berrange }; 60*2624bab8SDaniel P. Berrange 61*2624bab8SDaniel P. Berrange typedef struct VncJobQueue VncJobQueue; 62*2624bab8SDaniel P. Berrange 63*2624bab8SDaniel P. Berrange /* 64*2624bab8SDaniel P. Berrange * We use a single global queue, but most of the functions are 65*2624bab8SDaniel P. Berrange * already reetrant, so we can easilly add more than one encoding thread 66*2624bab8SDaniel P. Berrange */ 67*2624bab8SDaniel P. Berrange static VncJobQueue *queue; 68*2624bab8SDaniel P. Berrange 69*2624bab8SDaniel P. Berrange static void vnc_lock_queue(VncJobQueue *queue) 70*2624bab8SDaniel P. Berrange { 71*2624bab8SDaniel P. Berrange qemu_mutex_lock(&queue->mutex); 72*2624bab8SDaniel P. Berrange } 73*2624bab8SDaniel P. Berrange 74*2624bab8SDaniel P. Berrange static void vnc_unlock_queue(VncJobQueue *queue) 75*2624bab8SDaniel P. Berrange { 76*2624bab8SDaniel P. Berrange qemu_mutex_unlock(&queue->mutex); 77*2624bab8SDaniel P. Berrange } 78*2624bab8SDaniel P. Berrange 79*2624bab8SDaniel P. Berrange VncJob *vnc_job_new(VncState *vs) 80*2624bab8SDaniel P. Berrange { 81*2624bab8SDaniel P. Berrange VncJob *job = g_malloc0(sizeof(VncJob)); 82*2624bab8SDaniel P. Berrange 83*2624bab8SDaniel P. Berrange job->vs = vs; 84*2624bab8SDaniel P. Berrange vnc_lock_queue(queue); 85*2624bab8SDaniel P. Berrange QLIST_INIT(&job->rectangles); 86*2624bab8SDaniel P. Berrange vnc_unlock_queue(queue); 87*2624bab8SDaniel P. Berrange return job; 88*2624bab8SDaniel P. Berrange } 89*2624bab8SDaniel P. Berrange 90*2624bab8SDaniel P. Berrange int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h) 91*2624bab8SDaniel P. Berrange { 92*2624bab8SDaniel P. Berrange VncRectEntry *entry = g_malloc0(sizeof(VncRectEntry)); 93*2624bab8SDaniel P. Berrange 94*2624bab8SDaniel P. Berrange entry->rect.x = x; 95*2624bab8SDaniel P. Berrange entry->rect.y = y; 96*2624bab8SDaniel P. Berrange entry->rect.w = w; 97*2624bab8SDaniel P. Berrange entry->rect.h = h; 98*2624bab8SDaniel P. Berrange 99*2624bab8SDaniel P. Berrange vnc_lock_queue(queue); 100*2624bab8SDaniel P. Berrange QLIST_INSERT_HEAD(&job->rectangles, entry, next); 101*2624bab8SDaniel P. Berrange vnc_unlock_queue(queue); 102*2624bab8SDaniel P. Berrange return 1; 103*2624bab8SDaniel P. Berrange } 104*2624bab8SDaniel P. Berrange 105*2624bab8SDaniel P. Berrange void vnc_job_push(VncJob *job) 106*2624bab8SDaniel P. Berrange { 107*2624bab8SDaniel P. Berrange vnc_lock_queue(queue); 108*2624bab8SDaniel P. Berrange if (queue->exit || QLIST_EMPTY(&job->rectangles)) { 109*2624bab8SDaniel P. Berrange g_free(job); 110*2624bab8SDaniel P. Berrange } else { 111*2624bab8SDaniel P. Berrange QTAILQ_INSERT_TAIL(&queue->jobs, job, next); 112*2624bab8SDaniel P. Berrange qemu_cond_broadcast(&queue->cond); 113*2624bab8SDaniel P. Berrange } 114*2624bab8SDaniel P. Berrange vnc_unlock_queue(queue); 115*2624bab8SDaniel P. Berrange } 116*2624bab8SDaniel P. Berrange 117*2624bab8SDaniel P. Berrange static bool vnc_has_job_locked(VncState *vs) 118*2624bab8SDaniel P. Berrange { 119*2624bab8SDaniel P. Berrange VncJob *job; 120*2624bab8SDaniel P. Berrange 121*2624bab8SDaniel P. Berrange QTAILQ_FOREACH(job, &queue->jobs, next) { 122*2624bab8SDaniel P. Berrange if (job->vs == vs || !vs) { 123*2624bab8SDaniel P. Berrange return true; 124*2624bab8SDaniel P. Berrange } 125*2624bab8SDaniel P. Berrange } 126*2624bab8SDaniel P. Berrange return false; 127*2624bab8SDaniel P. Berrange } 128*2624bab8SDaniel P. Berrange 129*2624bab8SDaniel P. Berrange bool vnc_has_job(VncState *vs) 130*2624bab8SDaniel P. Berrange { 131*2624bab8SDaniel P. Berrange bool ret; 132*2624bab8SDaniel P. Berrange 133*2624bab8SDaniel P. Berrange vnc_lock_queue(queue); 134*2624bab8SDaniel P. Berrange ret = vnc_has_job_locked(vs); 135*2624bab8SDaniel P. Berrange vnc_unlock_queue(queue); 136*2624bab8SDaniel P. Berrange return ret; 137*2624bab8SDaniel P. Berrange } 138*2624bab8SDaniel P. Berrange 139*2624bab8SDaniel P. Berrange void vnc_jobs_clear(VncState *vs) 140*2624bab8SDaniel P. Berrange { 141*2624bab8SDaniel P. Berrange VncJob *job, *tmp; 142*2624bab8SDaniel P. Berrange 143*2624bab8SDaniel P. Berrange vnc_lock_queue(queue); 144*2624bab8SDaniel P. Berrange QTAILQ_FOREACH_SAFE(job, &queue->jobs, next, tmp) { 145*2624bab8SDaniel P. Berrange if (job->vs == vs || !vs) { 146*2624bab8SDaniel P. Berrange QTAILQ_REMOVE(&queue->jobs, job, next); 147*2624bab8SDaniel P. Berrange } 148*2624bab8SDaniel P. Berrange } 149*2624bab8SDaniel P. Berrange vnc_unlock_queue(queue); 150*2624bab8SDaniel P. Berrange } 151*2624bab8SDaniel P. Berrange 152*2624bab8SDaniel P. Berrange void vnc_jobs_join(VncState *vs) 153*2624bab8SDaniel P. Berrange { 154*2624bab8SDaniel P. Berrange vnc_lock_queue(queue); 155*2624bab8SDaniel P. Berrange while (vnc_has_job_locked(vs)) { 156*2624bab8SDaniel P. Berrange qemu_cond_wait(&queue->cond, &queue->mutex); 157*2624bab8SDaniel P. Berrange } 158*2624bab8SDaniel P. Berrange vnc_unlock_queue(queue); 159*2624bab8SDaniel P. Berrange vnc_jobs_consume_buffer(vs); 160*2624bab8SDaniel P. Berrange } 161*2624bab8SDaniel P. Berrange 162*2624bab8SDaniel P. Berrange void vnc_jobs_consume_buffer(VncState *vs) 163*2624bab8SDaniel P. Berrange { 164*2624bab8SDaniel P. Berrange bool flush; 165*2624bab8SDaniel P. Berrange 166*2624bab8SDaniel P. Berrange vnc_lock_output(vs); 167*2624bab8SDaniel P. Berrange if (vs->jobs_buffer.offset) { 168*2624bab8SDaniel P. Berrange vnc_write(vs, vs->jobs_buffer.buffer, vs->jobs_buffer.offset); 169*2624bab8SDaniel P. Berrange buffer_reset(&vs->jobs_buffer); 170*2624bab8SDaniel P. Berrange } 171*2624bab8SDaniel P. Berrange flush = vs->csock != -1 && vs->abort != true; 172*2624bab8SDaniel P. Berrange vnc_unlock_output(vs); 173*2624bab8SDaniel P. Berrange 174*2624bab8SDaniel P. Berrange if (flush) { 175*2624bab8SDaniel P. Berrange vnc_flush(vs); 176*2624bab8SDaniel P. Berrange } 177*2624bab8SDaniel P. Berrange } 178*2624bab8SDaniel P. Berrange 179*2624bab8SDaniel P. Berrange /* 180*2624bab8SDaniel P. Berrange * Copy data for local use 181*2624bab8SDaniel P. Berrange */ 182*2624bab8SDaniel P. Berrange static void vnc_async_encoding_start(VncState *orig, VncState *local) 183*2624bab8SDaniel P. Berrange { 184*2624bab8SDaniel P. Berrange local->vnc_encoding = orig->vnc_encoding; 185*2624bab8SDaniel P. Berrange local->features = orig->features; 186*2624bab8SDaniel P. Berrange local->ds = orig->ds; 187*2624bab8SDaniel P. Berrange local->vd = orig->vd; 188*2624bab8SDaniel P. Berrange local->lossy_rect = orig->lossy_rect; 189*2624bab8SDaniel P. Berrange local->write_pixels = orig->write_pixels; 190*2624bab8SDaniel P. Berrange local->clientds = orig->clientds; 191*2624bab8SDaniel P. Berrange local->tight = orig->tight; 192*2624bab8SDaniel P. Berrange local->zlib = orig->zlib; 193*2624bab8SDaniel P. Berrange local->hextile = orig->hextile; 194*2624bab8SDaniel P. Berrange local->zrle = orig->zrle; 195*2624bab8SDaniel P. Berrange local->output = queue->buffer; 196*2624bab8SDaniel P. Berrange local->csock = -1; /* Don't do any network work on this thread */ 197*2624bab8SDaniel P. Berrange 198*2624bab8SDaniel P. Berrange buffer_reset(&local->output); 199*2624bab8SDaniel P. Berrange } 200*2624bab8SDaniel P. Berrange 201*2624bab8SDaniel P. Berrange static void vnc_async_encoding_end(VncState *orig, VncState *local) 202*2624bab8SDaniel P. Berrange { 203*2624bab8SDaniel P. Berrange orig->tight = local->tight; 204*2624bab8SDaniel P. Berrange orig->zlib = local->zlib; 205*2624bab8SDaniel P. Berrange orig->hextile = local->hextile; 206*2624bab8SDaniel P. Berrange orig->zrle = local->zrle; 207*2624bab8SDaniel P. Berrange orig->lossy_rect = local->lossy_rect; 208*2624bab8SDaniel P. Berrange 209*2624bab8SDaniel P. Berrange queue->buffer = local->output; 210*2624bab8SDaniel P. Berrange } 211*2624bab8SDaniel P. Berrange 212*2624bab8SDaniel P. Berrange static int vnc_worker_thread_loop(VncJobQueue *queue) 213*2624bab8SDaniel P. Berrange { 214*2624bab8SDaniel P. Berrange VncJob *job; 215*2624bab8SDaniel P. Berrange VncRectEntry *entry, *tmp; 216*2624bab8SDaniel P. Berrange VncState vs; 217*2624bab8SDaniel P. Berrange int n_rectangles; 218*2624bab8SDaniel P. Berrange int saved_offset; 219*2624bab8SDaniel P. Berrange 220*2624bab8SDaniel P. Berrange vnc_lock_queue(queue); 221*2624bab8SDaniel P. Berrange while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) { 222*2624bab8SDaniel P. Berrange qemu_cond_wait(&queue->cond, &queue->mutex); 223*2624bab8SDaniel P. Berrange } 224*2624bab8SDaniel P. Berrange /* Here job can only be NULL if queue->exit is true */ 225*2624bab8SDaniel P. Berrange job = QTAILQ_FIRST(&queue->jobs); 226*2624bab8SDaniel P. Berrange vnc_unlock_queue(queue); 227*2624bab8SDaniel P. Berrange 228*2624bab8SDaniel P. Berrange if (queue->exit) { 229*2624bab8SDaniel P. Berrange return -1; 230*2624bab8SDaniel P. Berrange } 231*2624bab8SDaniel P. Berrange 232*2624bab8SDaniel P. Berrange vnc_lock_output(job->vs); 233*2624bab8SDaniel P. Berrange if (job->vs->csock == -1 || job->vs->abort == true) { 234*2624bab8SDaniel P. Berrange vnc_unlock_output(job->vs); 235*2624bab8SDaniel P. Berrange goto disconnected; 236*2624bab8SDaniel P. Berrange } 237*2624bab8SDaniel P. Berrange vnc_unlock_output(job->vs); 238*2624bab8SDaniel P. Berrange 239*2624bab8SDaniel P. Berrange /* Make a local copy of vs and switch output buffers */ 240*2624bab8SDaniel P. Berrange vnc_async_encoding_start(job->vs, &vs); 241*2624bab8SDaniel P. Berrange 242*2624bab8SDaniel P. Berrange /* Start sending rectangles */ 243*2624bab8SDaniel P. Berrange n_rectangles = 0; 244*2624bab8SDaniel P. Berrange vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); 245*2624bab8SDaniel P. Berrange vnc_write_u8(&vs, 0); 246*2624bab8SDaniel P. Berrange saved_offset = vs.output.offset; 247*2624bab8SDaniel P. Berrange vnc_write_u16(&vs, 0); 248*2624bab8SDaniel P. Berrange 249*2624bab8SDaniel P. Berrange vnc_lock_display(job->vs->vd); 250*2624bab8SDaniel P. Berrange QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) { 251*2624bab8SDaniel P. Berrange int n; 252*2624bab8SDaniel P. Berrange 253*2624bab8SDaniel P. Berrange if (job->vs->csock == -1) { 254*2624bab8SDaniel P. Berrange vnc_unlock_display(job->vs->vd); 255*2624bab8SDaniel P. Berrange goto disconnected; 256*2624bab8SDaniel P. Berrange } 257*2624bab8SDaniel P. Berrange 258*2624bab8SDaniel P. Berrange n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y, 259*2624bab8SDaniel P. Berrange entry->rect.w, entry->rect.h); 260*2624bab8SDaniel P. Berrange 261*2624bab8SDaniel P. Berrange if (n >= 0) { 262*2624bab8SDaniel P. Berrange n_rectangles += n; 263*2624bab8SDaniel P. Berrange } 264*2624bab8SDaniel P. Berrange g_free(entry); 265*2624bab8SDaniel P. Berrange } 266*2624bab8SDaniel P. Berrange vnc_unlock_display(job->vs->vd); 267*2624bab8SDaniel P. Berrange 268*2624bab8SDaniel P. Berrange /* Put n_rectangles at the beginning of the message */ 269*2624bab8SDaniel P. Berrange vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; 270*2624bab8SDaniel P. Berrange vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF; 271*2624bab8SDaniel P. Berrange 272*2624bab8SDaniel P. Berrange vnc_lock_output(job->vs); 273*2624bab8SDaniel P. Berrange if (job->vs->csock != -1) { 274*2624bab8SDaniel P. Berrange buffer_reserve(&job->vs->jobs_buffer, vs.output.offset); 275*2624bab8SDaniel P. Berrange buffer_append(&job->vs->jobs_buffer, vs.output.buffer, 276*2624bab8SDaniel P. Berrange vs.output.offset); 277*2624bab8SDaniel P. Berrange /* Copy persistent encoding data */ 278*2624bab8SDaniel P. Berrange vnc_async_encoding_end(job->vs, &vs); 279*2624bab8SDaniel P. Berrange 280*2624bab8SDaniel P. Berrange qemu_bh_schedule(job->vs->bh); 281*2624bab8SDaniel P. Berrange } 282*2624bab8SDaniel P. Berrange vnc_unlock_output(job->vs); 283*2624bab8SDaniel P. Berrange 284*2624bab8SDaniel P. Berrange disconnected: 285*2624bab8SDaniel P. Berrange vnc_lock_queue(queue); 286*2624bab8SDaniel P. Berrange QTAILQ_REMOVE(&queue->jobs, job, next); 287*2624bab8SDaniel P. Berrange vnc_unlock_queue(queue); 288*2624bab8SDaniel P. Berrange qemu_cond_broadcast(&queue->cond); 289*2624bab8SDaniel P. Berrange g_free(job); 290*2624bab8SDaniel P. Berrange return 0; 291*2624bab8SDaniel P. Berrange } 292*2624bab8SDaniel P. Berrange 293*2624bab8SDaniel P. Berrange static VncJobQueue *vnc_queue_init(void) 294*2624bab8SDaniel P. Berrange { 295*2624bab8SDaniel P. Berrange VncJobQueue *queue = g_malloc0(sizeof(VncJobQueue)); 296*2624bab8SDaniel P. Berrange 297*2624bab8SDaniel P. Berrange qemu_cond_init(&queue->cond); 298*2624bab8SDaniel P. Berrange qemu_mutex_init(&queue->mutex); 299*2624bab8SDaniel P. Berrange QTAILQ_INIT(&queue->jobs); 300*2624bab8SDaniel P. Berrange return queue; 301*2624bab8SDaniel P. Berrange } 302*2624bab8SDaniel P. Berrange 303*2624bab8SDaniel P. Berrange static void vnc_queue_clear(VncJobQueue *q) 304*2624bab8SDaniel P. Berrange { 305*2624bab8SDaniel P. Berrange qemu_cond_destroy(&queue->cond); 306*2624bab8SDaniel P. Berrange qemu_mutex_destroy(&queue->mutex); 307*2624bab8SDaniel P. Berrange buffer_free(&queue->buffer); 308*2624bab8SDaniel P. Berrange g_free(q); 309*2624bab8SDaniel P. Berrange queue = NULL; /* Unset global queue */ 310*2624bab8SDaniel P. Berrange } 311*2624bab8SDaniel P. Berrange 312*2624bab8SDaniel P. Berrange static void *vnc_worker_thread(void *arg) 313*2624bab8SDaniel P. Berrange { 314*2624bab8SDaniel P. Berrange VncJobQueue *queue = arg; 315*2624bab8SDaniel P. Berrange 316*2624bab8SDaniel P. Berrange qemu_thread_get_self(&queue->thread); 317*2624bab8SDaniel P. Berrange 318*2624bab8SDaniel P. Berrange while (!vnc_worker_thread_loop(queue)) ; 319*2624bab8SDaniel P. Berrange vnc_queue_clear(queue); 320*2624bab8SDaniel P. Berrange return NULL; 321*2624bab8SDaniel P. Berrange } 322*2624bab8SDaniel P. Berrange 323*2624bab8SDaniel P. Berrange void vnc_start_worker_thread(void) 324*2624bab8SDaniel P. Berrange { 325*2624bab8SDaniel P. Berrange VncJobQueue *q; 326*2624bab8SDaniel P. Berrange 327*2624bab8SDaniel P. Berrange if (vnc_worker_thread_running()) 328*2624bab8SDaniel P. Berrange return ; 329*2624bab8SDaniel P. Berrange 330*2624bab8SDaniel P. Berrange q = vnc_queue_init(); 331*2624bab8SDaniel P. Berrange qemu_thread_create(&q->thread, vnc_worker_thread, q, QEMU_THREAD_DETACHED); 332*2624bab8SDaniel P. Berrange queue = q; /* Set global queue */ 333*2624bab8SDaniel P. Berrange } 334*2624bab8SDaniel P. Berrange 335*2624bab8SDaniel P. Berrange bool vnc_worker_thread_running(void) 336*2624bab8SDaniel P. Berrange { 337*2624bab8SDaniel P. Berrange return queue; /* Check global queue */ 338*2624bab8SDaniel P. Berrange } 339*2624bab8SDaniel P. Berrange 340*2624bab8SDaniel P. Berrange void vnc_stop_worker_thread(void) 341*2624bab8SDaniel P. Berrange { 342*2624bab8SDaniel P. Berrange if (!vnc_worker_thread_running()) 343*2624bab8SDaniel P. Berrange return ; 344*2624bab8SDaniel P. Berrange 345*2624bab8SDaniel P. Berrange /* Remove all jobs and wake up the thread */ 346*2624bab8SDaniel P. Berrange vnc_lock_queue(queue); 347*2624bab8SDaniel P. Berrange queue->exit = true; 348*2624bab8SDaniel P. Berrange vnc_unlock_queue(queue); 349*2624bab8SDaniel P. Berrange vnc_jobs_clear(NULL); 350*2624bab8SDaniel P. Berrange qemu_cond_broadcast(&queue->cond); 351*2624bab8SDaniel P. Berrange } 352