Message ID | 1340198668-21307-1-git-send-email-berrange@redhat.com |
---|---|
State | New |
Headers | show |
20.06.2012 16:24, Daniel P. Berrange wrote: > delete mode 100644 ui/vnc-jobs-async.c > delete mode 100644 ui/vnc-jobs-sync.c > create mode 100644 ui/vnc-jobs.c Is there a reason to rename vnc-jobs-foo.c to vnc-jobs.c ? I'd leave it alone at this stage, omiting just the rename... /mjt
On Thu, Jun 21, 2012 at 12:57:44PM +0300, Michael Tokarev wrote: > 20.06.2012 16:24, Daniel P. Berrange wrote: > > delete mode 100644 ui/vnc-jobs-async.c > > delete mode 100644 ui/vnc-jobs-sync.c > > create mode 100644 ui/vnc-jobs.c > > Is there a reason to rename vnc-jobs-foo.c to vnc-jobs.c ? The corresponding header file is vnc-jobs.h, and since we only have one impl of it now, using the same name is normal practice. > I'd leave it alone at this stage, omiting just the rename... I disagree, GIT handles renames like this fine, so there's no reason not to do this. Daniel
On 06/21/12 11:59, Daniel P. Berrange wrote: > On Thu, Jun 21, 2012 at 12:57:44PM +0300, Michael Tokarev wrote: >> 20.06.2012 16:24, Daniel P. Berrange wrote: >>> delete mode 100644 ui/vnc-jobs-async.c >>> delete mode 100644 ui/vnc-jobs-sync.c >>> create mode 100644 ui/vnc-jobs.c >> >> Is there a reason to rename vnc-jobs-foo.c to vnc-jobs.c ? > > The corresponding header file is vnc-jobs.h, and since we only > have one impl of it now, using the same name is normal practice. > >> I'd leave it alone at this stage, omiting just the rename... > > I disagree, GIT handles renames like this fine, so there's no > reason not to do this. /me suggests "git format-patch -M" so the patch shows the rename. cheers, Gerd
On 06/20/2012 08:24 AM, Daniel P. Berrange wrote: > From: "Daniel P. Berrange"<berrange@redhat.com> > > QEMU now has a fundamental requirement for pthreads, so there > is no compelling reason to retain support for the non-threaded > VNC server. Remove the --{enable,disable}-vnc-thread configure > arguments, and all CONFIG_VNC_THREAD conditionals > > Signed-off-by: Daniel P. Berrange<berrange@redhat.com> Applied. Thanks. Regards, Anthony Liguori > --- > configure | 9 -- > ui/Makefile.objs | 6 +- > ui/vnc-jobs-async.c | 351 --------------------------------------------------- > ui/vnc-jobs-sync.c | 73 ----------- > ui/vnc-jobs.c | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++ > ui/vnc-jobs.h | 16 --- > ui/vnc.c | 21 --- > ui/vnc.h | 17 --- > 8 files changed, 352 insertions(+), 492 deletions(-) > delete mode 100644 ui/vnc-jobs-async.c > delete mode 100644 ui/vnc-jobs-sync.c > create mode 100644 ui/vnc-jobs.c > > diff --git a/configure b/configure > index b68c0ca..4767532 100755 > --- a/configure > +++ b/configure > @@ -134,7 +134,6 @@ vnc_tls="" > vnc_sasl="" > vnc_jpeg="" > vnc_png="" > -vnc_thread="no" > xen="" > xen_ctrl_version="" > linux_aio="" > @@ -666,10 +665,6 @@ for opt do > ;; > --enable-vnc-png) vnc_png="yes" > ;; > - --disable-vnc-thread) vnc_thread="no" > - ;; > - --enable-vnc-thread) vnc_thread="yes" > - ;; > --disable-slirp) slirp="no" > ;; > --disable-uuid) uuid="no" > @@ -2998,7 +2993,6 @@ if test "$vnc" = "yes" ; then > echo "VNC SASL support $vnc_sasl" > echo "VNC JPEG support $vnc_jpeg" > echo "VNC PNG support $vnc_png" > - echo "VNC thread $vnc_thread" > fi > if test -n "$sparc_cpu"; then > echo "Target Sparc Arch $sparc_cpu" > @@ -3174,9 +3168,6 @@ if test "$vnc_png" = "yes" ; then > echo "CONFIG_VNC_PNG=y">> $config_host_mak > echo "VNC_PNG_CFLAGS=$vnc_png_cflags">> $config_host_mak > fi > -if test "$vnc_thread" = "yes" ; then > - echo "CONFIG_VNC_THREAD=y">> $config_host_mak > -fi > if test "$fnmatch" = "yes" ; then > echo "CONFIG_FNMATCH=y">> $config_host_mak > fi > diff --git a/ui/Makefile.objs b/ui/Makefile.objs > index 3687c8a..adc07be 100644 > --- a/ui/Makefile.objs > +++ b/ui/Makefile.objs > @@ -4,11 +4,7 @@ vnc-obj-y += vnc-enc-tight.o vnc-palette.o > vnc-obj-y += vnc-enc-zrle.o > vnc-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o > vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o > -ifdef CONFIG_VNC_THREAD > -vnc-obj-y += vnc-jobs-async.o > -else > -vnc-obj-y += vnc-jobs-sync.o > -endif > +vnc-obj-y += vnc-jobs.o > > common-obj-y += keymaps.o > common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o > diff --git a/ui/vnc-jobs-async.c b/ui/vnc-jobs-async.c > deleted file mode 100644 > index 087b84d..0000000 > --- a/ui/vnc-jobs-async.c > +++ /dev/null > @@ -1,351 +0,0 @@ > -/* > - * QEMU VNC display driver > - * > - * Copyright (C) 2006 Anthony Liguori<anthony@codemonkey.ws> > - * Copyright (C) 2006 Fabrice Bellard > - * Copyright (C) 2009 Red Hat, Inc > - * Copyright (C) 2010 Corentin Chary<corentin.chary@gmail.com> > - * > - * Permission is hereby granted, free of charge, to any person obtaining a copy > - * of this software and associated documentation files (the "Software"), to deal > - * in the Software without restriction, including without limitation the rights > - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > - * copies of the Software, and to permit persons to whom the Software is > - * furnished to do so, subject to the following conditions: > - * > - * The above copyright notice and this permission notice shall be included in > - * all copies or substantial portions of the Software. > - * > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > - * THE SOFTWARE. > - */ > - > - > -#include "vnc.h" > -#include "vnc-jobs.h" > -#include "qemu_socket.h" > - > -/* > - * Locking: > - * > - * There is three levels of locking: > - * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?) > - * - VncDisplay global lock: mainly used for framebuffer updates to avoid > - * screen corruption if the framebuffer is updated > - * while the worker is doing something. > - * - VncState::output lock: used to make sure the output buffer is not corrupted > - * if two threads try to write on it at the same time > - * > - * While the VNC worker thread is working, the VncDisplay global lock is hold > - * to avoid screen corruptions (this does not block vnc_refresh() because it > - * uses trylock()) but the output lock is not hold because the thread work on > - * its own output buffer. > - * When the encoding job is done, the worker thread will hold the output lock > - * and copy its output buffer in vs->output. > -*/ > - > -struct VncJobQueue { > - QemuCond cond; > - QemuMutex mutex; > - QemuThread thread; > - Buffer buffer; > - bool exit; > - QTAILQ_HEAD(, VncJob) jobs; > -}; > - > -typedef struct VncJobQueue VncJobQueue; > - > -/* > - * We use a single global queue, but most of the functions are > - * already reetrant, so we can easilly add more than one encoding thread > - */ > -static VncJobQueue *queue; > - > -static void vnc_lock_queue(VncJobQueue *queue) > -{ > - qemu_mutex_lock(&queue->mutex); > -} > - > -static void vnc_unlock_queue(VncJobQueue *queue) > -{ > - qemu_mutex_unlock(&queue->mutex); > -} > - > -VncJob *vnc_job_new(VncState *vs) > -{ > - VncJob *job = g_malloc0(sizeof(VncJob)); > - > - job->vs = vs; > - vnc_lock_queue(queue); > - QLIST_INIT(&job->rectangles); > - vnc_unlock_queue(queue); > - return job; > -} > - > -int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h) > -{ > - VncRectEntry *entry = g_malloc0(sizeof(VncRectEntry)); > - > - entry->rect.x = x; > - entry->rect.y = y; > - entry->rect.w = w; > - entry->rect.h = h; > - > - vnc_lock_queue(queue); > - QLIST_INSERT_HEAD(&job->rectangles, entry, next); > - vnc_unlock_queue(queue); > - return 1; > -} > - > -void vnc_job_push(VncJob *job) > -{ > - vnc_lock_queue(queue); > - if (queue->exit || QLIST_EMPTY(&job->rectangles)) { > - g_free(job); > - } else { > - QTAILQ_INSERT_TAIL(&queue->jobs, job, next); > - qemu_cond_broadcast(&queue->cond); > - } > - vnc_unlock_queue(queue); > -} > - > -static bool vnc_has_job_locked(VncState *vs) > -{ > - VncJob *job; > - > - QTAILQ_FOREACH(job,&queue->jobs, next) { > - if (job->vs == vs || !vs) { > - return true; > - } > - } > - return false; > -} > - > -bool vnc_has_job(VncState *vs) > -{ > - bool ret; > - > - vnc_lock_queue(queue); > - ret = vnc_has_job_locked(vs); > - vnc_unlock_queue(queue); > - return ret; > -} > - > -void vnc_jobs_clear(VncState *vs) > -{ > - VncJob *job, *tmp; > - > - vnc_lock_queue(queue); > - QTAILQ_FOREACH_SAFE(job,&queue->jobs, next, tmp) { > - if (job->vs == vs || !vs) { > - QTAILQ_REMOVE(&queue->jobs, job, next); > - } > - } > - vnc_unlock_queue(queue); > -} > - > -void vnc_jobs_join(VncState *vs) > -{ > - vnc_lock_queue(queue); > - while (vnc_has_job_locked(vs)) { > - qemu_cond_wait(&queue->cond,&queue->mutex); > - } > - vnc_unlock_queue(queue); > - vnc_jobs_consume_buffer(vs); > -} > - > -void vnc_jobs_consume_buffer(VncState *vs) > -{ > - bool flush; > - > - vnc_lock_output(vs); > - if (vs->jobs_buffer.offset) { > - vnc_write(vs, vs->jobs_buffer.buffer, vs->jobs_buffer.offset); > - buffer_reset(&vs->jobs_buffer); > - } > - flush = vs->csock != -1&& vs->abort != true; > - vnc_unlock_output(vs); > - > - if (flush) { > - vnc_flush(vs); > - } > -} > - > -/* > - * Copy data for local use > - */ > -static void vnc_async_encoding_start(VncState *orig, VncState *local) > -{ > - local->vnc_encoding = orig->vnc_encoding; > - local->features = orig->features; > - local->ds = orig->ds; > - local->vd = orig->vd; > - local->lossy_rect = orig->lossy_rect; > - local->write_pixels = orig->write_pixels; > - local->clientds = orig->clientds; > - local->tight = orig->tight; > - local->zlib = orig->zlib; > - local->hextile = orig->hextile; > - local->zrle = orig->zrle; > - local->output = queue->buffer; > - local->csock = -1; /* Don't do any network work on this thread */ > - > - buffer_reset(&local->output); > -} > - > -static void vnc_async_encoding_end(VncState *orig, VncState *local) > -{ > - orig->tight = local->tight; > - orig->zlib = local->zlib; > - orig->hextile = local->hextile; > - orig->zrle = local->zrle; > - orig->lossy_rect = local->lossy_rect; > - > - queue->buffer = local->output; > -} > - > -static int vnc_worker_thread_loop(VncJobQueue *queue) > -{ > - VncJob *job; > - VncRectEntry *entry, *tmp; > - VncState vs; > - int n_rectangles; > - int saved_offset; > - > - vnc_lock_queue(queue); > - while (QTAILQ_EMPTY(&queue->jobs)&& !queue->exit) { > - qemu_cond_wait(&queue->cond,&queue->mutex); > - } > - /* Here job can only be NULL if queue->exit is true */ > - job = QTAILQ_FIRST(&queue->jobs); > - vnc_unlock_queue(queue); > - > - if (queue->exit) { > - return -1; > - } > - > - vnc_lock_output(job->vs); > - if (job->vs->csock == -1 || job->vs->abort == true) { > - vnc_unlock_output(job->vs); > - goto disconnected; > - } > - vnc_unlock_output(job->vs); > - > - /* Make a local copy of vs and switch output buffers */ > - vnc_async_encoding_start(job->vs,&vs); > - > - /* Start sending rectangles */ > - n_rectangles = 0; > - vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); > - vnc_write_u8(&vs, 0); > - saved_offset = vs.output.offset; > - vnc_write_u16(&vs, 0); > - > - vnc_lock_display(job->vs->vd); > - QLIST_FOREACH_SAFE(entry,&job->rectangles, next, tmp) { > - int n; > - > - if (job->vs->csock == -1) { > - vnc_unlock_display(job->vs->vd); > - goto disconnected; > - } > - > - n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y, > - entry->rect.w, entry->rect.h); > - > - if (n>= 0) { > - n_rectangles += n; > - } > - g_free(entry); > - } > - vnc_unlock_display(job->vs->vd); > - > - /* Put n_rectangles at the beginning of the message */ > - vs.output.buffer[saved_offset] = (n_rectangles>> 8)& 0xFF; > - vs.output.buffer[saved_offset + 1] = n_rectangles& 0xFF; > - > - vnc_lock_output(job->vs); > - if (job->vs->csock != -1) { > - buffer_reserve(&job->vs->jobs_buffer, vs.output.offset); > - buffer_append(&job->vs->jobs_buffer, vs.output.buffer, > - vs.output.offset); > - /* Copy persistent encoding data */ > - vnc_async_encoding_end(job->vs,&vs); > - > - qemu_bh_schedule(job->vs->bh); > - } > - vnc_unlock_output(job->vs); > - > -disconnected: > - vnc_lock_queue(queue); > - QTAILQ_REMOVE(&queue->jobs, job, next); > - vnc_unlock_queue(queue); > - qemu_cond_broadcast(&queue->cond); > - g_free(job); > - return 0; > -} > - > -static VncJobQueue *vnc_queue_init(void) > -{ > - VncJobQueue *queue = g_malloc0(sizeof(VncJobQueue)); > - > - qemu_cond_init(&queue->cond); > - qemu_mutex_init(&queue->mutex); > - QTAILQ_INIT(&queue->jobs); > - return queue; > -} > - > -static void vnc_queue_clear(VncJobQueue *q) > -{ > - qemu_cond_destroy(&queue->cond); > - qemu_mutex_destroy(&queue->mutex); > - buffer_free(&queue->buffer); > - g_free(q); > - queue = NULL; /* Unset global queue */ > -} > - > -static void *vnc_worker_thread(void *arg) > -{ > - VncJobQueue *queue = arg; > - > - qemu_thread_get_self(&queue->thread); > - > - while (!vnc_worker_thread_loop(queue)) ; > - vnc_queue_clear(queue); > - return NULL; > -} > - > -void vnc_start_worker_thread(void) > -{ > - VncJobQueue *q; > - > - if (vnc_worker_thread_running()) > - return ; > - > - q = vnc_queue_init(); > - qemu_thread_create(&q->thread, vnc_worker_thread, q, QEMU_THREAD_DETACHED); > - queue = q; /* Set global queue */ > -} > - > -bool vnc_worker_thread_running(void) > -{ > - return queue; /* Check global queue */ > -} > - > -void vnc_stop_worker_thread(void) > -{ > - if (!vnc_worker_thread_running()) > - return ; > - > - /* Remove all jobs and wake up the thread */ > - vnc_lock_queue(queue); > - queue->exit = true; > - vnc_unlock_queue(queue); > - vnc_jobs_clear(NULL); > - qemu_cond_broadcast(&queue->cond); > -} > diff --git a/ui/vnc-jobs-sync.c b/ui/vnc-jobs-sync.c > deleted file mode 100644 > index 49b77af..0000000 > --- a/ui/vnc-jobs-sync.c > +++ /dev/null > @@ -1,73 +0,0 @@ > -/* > - * QEMU VNC display driver > - * > - * Copyright (C) 2006 Anthony Liguori<anthony@codemonkey.ws> > - * Copyright (C) 2006 Fabrice Bellard > - * Copyright (C) 2009 Red Hat, Inc > - * Copyright (C) 2010 Corentin Chary<corentin.chary@gmail.com> > - * > - * Permission is hereby granted, free of charge, to any person obtaining a copy > - * of this software and associated documentation files (the "Software"), to deal > - * in the Software without restriction, including without limitation the rights > - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > - * copies of the Software, and to permit persons to whom the Software is > - * furnished to do so, subject to the following conditions: > - * > - * The above copyright notice and this permission notice shall be included in > - * all copies or substantial portions of the Software. > - * > - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > - * THE SOFTWARE. > - */ > - > -#include "vnc.h" > -#include "vnc-jobs.h" > - > -void vnc_jobs_clear(VncState *vs) > -{ > -} > - > -void vnc_jobs_join(VncState *vs) > -{ > -} > - > -VncJob *vnc_job_new(VncState *vs) > -{ > - vs->job.vs = vs; > - vs->job.rectangles = 0; > - > - vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); > - vnc_write_u8(vs, 0); > - vs->job.saved_offset = vs->output.offset; > - vnc_write_u16(vs, 0); > - return&vs->job; > -} > - > -void vnc_job_push(VncJob *job) > -{ > - VncState *vs = job->vs; > - > - vs->output.buffer[job->saved_offset] = (job->rectangles>> 8)& 0xFF; > - vs->output.buffer[job->saved_offset + 1] = job->rectangles& 0xFF; > - vnc_flush(job->vs); > -} > - > -int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h) > -{ > - int n; > - > - n = vnc_send_framebuffer_update(job->vs, x, y, w, h); > - if (n>= 0) > - job->rectangles += n; > - return n; > -} > - > -bool vnc_has_job(VncState *vs) > -{ > - return false; > -} > diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c > new file mode 100644 > index 0000000..087b84d > --- /dev/null > +++ b/ui/vnc-jobs.c > @@ -0,0 +1,351 @@ > +/* > + * QEMU VNC display driver > + * > + * Copyright (C) 2006 Anthony Liguori<anthony@codemonkey.ws> > + * Copyright (C) 2006 Fabrice Bellard > + * Copyright (C) 2009 Red Hat, Inc > + * Copyright (C) 2010 Corentin Chary<corentin.chary@gmail.com> > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > + > +#include "vnc.h" > +#include "vnc-jobs.h" > +#include "qemu_socket.h" > + > +/* > + * Locking: > + * > + * There is three levels of locking: > + * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?) > + * - VncDisplay global lock: mainly used for framebuffer updates to avoid > + * screen corruption if the framebuffer is updated > + * while the worker is doing something. > + * - VncState::output lock: used to make sure the output buffer is not corrupted > + * if two threads try to write on it at the same time > + * > + * While the VNC worker thread is working, the VncDisplay global lock is hold > + * to avoid screen corruptions (this does not block vnc_refresh() because it > + * uses trylock()) but the output lock is not hold because the thread work on > + * its own output buffer. > + * When the encoding job is done, the worker thread will hold the output lock > + * and copy its output buffer in vs->output. > +*/ > + > +struct VncJobQueue { > + QemuCond cond; > + QemuMutex mutex; > + QemuThread thread; > + Buffer buffer; > + bool exit; > + QTAILQ_HEAD(, VncJob) jobs; > +}; > + > +typedef struct VncJobQueue VncJobQueue; > + > +/* > + * We use a single global queue, but most of the functions are > + * already reetrant, so we can easilly add more than one encoding thread > + */ > +static VncJobQueue *queue; > + > +static void vnc_lock_queue(VncJobQueue *queue) > +{ > + qemu_mutex_lock(&queue->mutex); > +} > + > +static void vnc_unlock_queue(VncJobQueue *queue) > +{ > + qemu_mutex_unlock(&queue->mutex); > +} > + > +VncJob *vnc_job_new(VncState *vs) > +{ > + VncJob *job = g_malloc0(sizeof(VncJob)); > + > + job->vs = vs; > + vnc_lock_queue(queue); > + QLIST_INIT(&job->rectangles); > + vnc_unlock_queue(queue); > + return job; > +} > + > +int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h) > +{ > + VncRectEntry *entry = g_malloc0(sizeof(VncRectEntry)); > + > + entry->rect.x = x; > + entry->rect.y = y; > + entry->rect.w = w; > + entry->rect.h = h; > + > + vnc_lock_queue(queue); > + QLIST_INSERT_HEAD(&job->rectangles, entry, next); > + vnc_unlock_queue(queue); > + return 1; > +} > + > +void vnc_job_push(VncJob *job) > +{ > + vnc_lock_queue(queue); > + if (queue->exit || QLIST_EMPTY(&job->rectangles)) { > + g_free(job); > + } else { > + QTAILQ_INSERT_TAIL(&queue->jobs, job, next); > + qemu_cond_broadcast(&queue->cond); > + } > + vnc_unlock_queue(queue); > +} > + > +static bool vnc_has_job_locked(VncState *vs) > +{ > + VncJob *job; > + > + QTAILQ_FOREACH(job,&queue->jobs, next) { > + if (job->vs == vs || !vs) { > + return true; > + } > + } > + return false; > +} > + > +bool vnc_has_job(VncState *vs) > +{ > + bool ret; > + > + vnc_lock_queue(queue); > + ret = vnc_has_job_locked(vs); > + vnc_unlock_queue(queue); > + return ret; > +} > + > +void vnc_jobs_clear(VncState *vs) > +{ > + VncJob *job, *tmp; > + > + vnc_lock_queue(queue); > + QTAILQ_FOREACH_SAFE(job,&queue->jobs, next, tmp) { > + if (job->vs == vs || !vs) { > + QTAILQ_REMOVE(&queue->jobs, job, next); > + } > + } > + vnc_unlock_queue(queue); > +} > + > +void vnc_jobs_join(VncState *vs) > +{ > + vnc_lock_queue(queue); > + while (vnc_has_job_locked(vs)) { > + qemu_cond_wait(&queue->cond,&queue->mutex); > + } > + vnc_unlock_queue(queue); > + vnc_jobs_consume_buffer(vs); > +} > + > +void vnc_jobs_consume_buffer(VncState *vs) > +{ > + bool flush; > + > + vnc_lock_output(vs); > + if (vs->jobs_buffer.offset) { > + vnc_write(vs, vs->jobs_buffer.buffer, vs->jobs_buffer.offset); > + buffer_reset(&vs->jobs_buffer); > + } > + flush = vs->csock != -1&& vs->abort != true; > + vnc_unlock_output(vs); > + > + if (flush) { > + vnc_flush(vs); > + } > +} > + > +/* > + * Copy data for local use > + */ > +static void vnc_async_encoding_start(VncState *orig, VncState *local) > +{ > + local->vnc_encoding = orig->vnc_encoding; > + local->features = orig->features; > + local->ds = orig->ds; > + local->vd = orig->vd; > + local->lossy_rect = orig->lossy_rect; > + local->write_pixels = orig->write_pixels; > + local->clientds = orig->clientds; > + local->tight = orig->tight; > + local->zlib = orig->zlib; > + local->hextile = orig->hextile; > + local->zrle = orig->zrle; > + local->output = queue->buffer; > + local->csock = -1; /* Don't do any network work on this thread */ > + > + buffer_reset(&local->output); > +} > + > +static void vnc_async_encoding_end(VncState *orig, VncState *local) > +{ > + orig->tight = local->tight; > + orig->zlib = local->zlib; > + orig->hextile = local->hextile; > + orig->zrle = local->zrle; > + orig->lossy_rect = local->lossy_rect; > + > + queue->buffer = local->output; > +} > + > +static int vnc_worker_thread_loop(VncJobQueue *queue) > +{ > + VncJob *job; > + VncRectEntry *entry, *tmp; > + VncState vs; > + int n_rectangles; > + int saved_offset; > + > + vnc_lock_queue(queue); > + while (QTAILQ_EMPTY(&queue->jobs)&& !queue->exit) { > + qemu_cond_wait(&queue->cond,&queue->mutex); > + } > + /* Here job can only be NULL if queue->exit is true */ > + job = QTAILQ_FIRST(&queue->jobs); > + vnc_unlock_queue(queue); > + > + if (queue->exit) { > + return -1; > + } > + > + vnc_lock_output(job->vs); > + if (job->vs->csock == -1 || job->vs->abort == true) { > + vnc_unlock_output(job->vs); > + goto disconnected; > + } > + vnc_unlock_output(job->vs); > + > + /* Make a local copy of vs and switch output buffers */ > + vnc_async_encoding_start(job->vs,&vs); > + > + /* Start sending rectangles */ > + n_rectangles = 0; > + vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); > + vnc_write_u8(&vs, 0); > + saved_offset = vs.output.offset; > + vnc_write_u16(&vs, 0); > + > + vnc_lock_display(job->vs->vd); > + QLIST_FOREACH_SAFE(entry,&job->rectangles, next, tmp) { > + int n; > + > + if (job->vs->csock == -1) { > + vnc_unlock_display(job->vs->vd); > + goto disconnected; > + } > + > + n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y, > + entry->rect.w, entry->rect.h); > + > + if (n>= 0) { > + n_rectangles += n; > + } > + g_free(entry); > + } > + vnc_unlock_display(job->vs->vd); > + > + /* Put n_rectangles at the beginning of the message */ > + vs.output.buffer[saved_offset] = (n_rectangles>> 8)& 0xFF; > + vs.output.buffer[saved_offset + 1] = n_rectangles& 0xFF; > + > + vnc_lock_output(job->vs); > + if (job->vs->csock != -1) { > + buffer_reserve(&job->vs->jobs_buffer, vs.output.offset); > + buffer_append(&job->vs->jobs_buffer, vs.output.buffer, > + vs.output.offset); > + /* Copy persistent encoding data */ > + vnc_async_encoding_end(job->vs,&vs); > + > + qemu_bh_schedule(job->vs->bh); > + } > + vnc_unlock_output(job->vs); > + > +disconnected: > + vnc_lock_queue(queue); > + QTAILQ_REMOVE(&queue->jobs, job, next); > + vnc_unlock_queue(queue); > + qemu_cond_broadcast(&queue->cond); > + g_free(job); > + return 0; > +} > + > +static VncJobQueue *vnc_queue_init(void) > +{ > + VncJobQueue *queue = g_malloc0(sizeof(VncJobQueue)); > + > + qemu_cond_init(&queue->cond); > + qemu_mutex_init(&queue->mutex); > + QTAILQ_INIT(&queue->jobs); > + return queue; > +} > + > +static void vnc_queue_clear(VncJobQueue *q) > +{ > + qemu_cond_destroy(&queue->cond); > + qemu_mutex_destroy(&queue->mutex); > + buffer_free(&queue->buffer); > + g_free(q); > + queue = NULL; /* Unset global queue */ > +} > + > +static void *vnc_worker_thread(void *arg) > +{ > + VncJobQueue *queue = arg; > + > + qemu_thread_get_self(&queue->thread); > + > + while (!vnc_worker_thread_loop(queue)) ; > + vnc_queue_clear(queue); > + return NULL; > +} > + > +void vnc_start_worker_thread(void) > +{ > + VncJobQueue *q; > + > + if (vnc_worker_thread_running()) > + return ; > + > + q = vnc_queue_init(); > + qemu_thread_create(&q->thread, vnc_worker_thread, q, QEMU_THREAD_DETACHED); > + queue = q; /* Set global queue */ > +} > + > +bool vnc_worker_thread_running(void) > +{ > + return queue; /* Check global queue */ > +} > + > +void vnc_stop_worker_thread(void) > +{ > + if (!vnc_worker_thread_running()) > + return ; > + > + /* Remove all jobs and wake up the thread */ > + vnc_lock_queue(queue); > + queue->exit = true; > + vnc_unlock_queue(queue); > + vnc_jobs_clear(NULL); > + qemu_cond_broadcast(&queue->cond); > +} > diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h > index 4c661f9..86e6d88 100644 > --- a/ui/vnc-jobs.h > +++ b/ui/vnc-jobs.h > @@ -38,51 +38,35 @@ bool vnc_has_job(VncState *vs); > void vnc_jobs_clear(VncState *vs); > void vnc_jobs_join(VncState *vs); > > -#ifdef CONFIG_VNC_THREAD > - > void vnc_jobs_consume_buffer(VncState *vs); > void vnc_start_worker_thread(void); > bool vnc_worker_thread_running(void); > void vnc_stop_worker_thread(void); > > -#endif /* CONFIG_VNC_THREAD */ > - > /* Locks */ > static inline int vnc_trylock_display(VncDisplay *vd) > { > -#ifdef CONFIG_VNC_THREAD > return qemu_mutex_trylock(&vd->mutex); > -#else > - return 0; > -#endif > } > > static inline void vnc_lock_display(VncDisplay *vd) > { > -#ifdef CONFIG_VNC_THREAD > qemu_mutex_lock(&vd->mutex); > -#endif > } > > static inline void vnc_unlock_display(VncDisplay *vd) > { > -#ifdef CONFIG_VNC_THREAD > qemu_mutex_unlock(&vd->mutex); > -#endif > } > > static inline void vnc_lock_output(VncState *vs) > { > -#ifdef CONFIG_VNC_THREAD > qemu_mutex_lock(&vs->output_mutex); > -#endif > } > > static inline void vnc_unlock_output(VncState *vs) > { > -#ifdef CONFIG_VNC_THREAD > qemu_mutex_unlock(&vs->output_mutex); > -#endif > } > > #endif /* VNC_JOBS_H */ > diff --git a/ui/vnc.c b/ui/vnc.c > index 54bc5ad..cf1cae2 100644 > --- a/ui/vnc.c > +++ b/ui/vnc.c > @@ -526,7 +526,6 @@ static void vnc_desktop_resize(VncState *vs) > vnc_flush(vs); > } > > -#ifdef CONFIG_VNC_THREAD > static void vnc_abort_display_jobs(VncDisplay *vd) > { > VncState *vs; > @@ -545,11 +544,6 @@ static void vnc_abort_display_jobs(VncDisplay *vd) > vnc_unlock_output(vs); > } > } > -#else > -static void vnc_abort_display_jobs(VncDisplay *vd) > -{ > -} > -#endif > > static void vnc_dpy_resize(DisplayState *ds) > { > @@ -867,19 +861,12 @@ static int find_and_clear_dirty_height(struct VncState *vs, > return h; > } > > -#ifdef CONFIG_VNC_THREAD > static int vnc_update_client_sync(VncState *vs, int has_dirty) > { > int ret = vnc_update_client(vs, has_dirty); > vnc_jobs_join(vs); > return ret; > } > -#else > -static int vnc_update_client_sync(VncState *vs, int has_dirty) > -{ > - return vnc_update_client(vs, has_dirty); > -} > -#endif > > static int vnc_update_client(VncState *vs, int has_dirty) > { > @@ -1066,11 +1053,9 @@ static void vnc_disconnect_finish(VncState *vs) > qemu_remove_led_event_handler(vs->led); > vnc_unlock_output(vs); > > -#ifdef CONFIG_VNC_THREAD > qemu_mutex_destroy(&vs->output_mutex); > qemu_bh_delete(vs->bh); > buffer_free(&vs->jobs_buffer); > -#endif > > for (i = 0; i< VNC_STAT_ROWS; ++i) { > g_free(vs->lossy_rect[i]); > @@ -1286,14 +1271,12 @@ static long vnc_client_read_plain(VncState *vs) > return ret; > } > > -#ifdef CONFIG_VNC_THREAD > static void vnc_jobs_bh(void *opaque) > { > VncState *vs = opaque; > > vnc_jobs_consume_buffer(vs); > } > -#endif > > /* > * First function called whenever there is more data to be read from > @@ -2699,10 +2682,8 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth) > vs->as.fmt = AUD_FMT_S16; > vs->as.endianness = 0; > > -#ifdef CONFIG_VNC_THREAD > qemu_mutex_init(&vs->output_mutex); > vs->bh = qemu_bh_new(vnc_jobs_bh, vs); > -#endif > > QTAILQ_INSERT_HEAD(&vd->clients, vs, next); > > @@ -2762,10 +2743,8 @@ void vnc_display_init(DisplayState *ds) > if (!vs->kbd_layout) > exit(1); > > -#ifdef CONFIG_VNC_THREAD > qemu_mutex_init(&vs->mutex); > vnc_start_worker_thread(); > -#endif > > dcl->dpy_copy = vnc_dpy_copy; > dcl->dpy_update = vnc_dpy_update; > diff --git a/ui/vnc.h b/ui/vnc.h > index a851ebd..068c2fc 100644 > --- a/ui/vnc.h > +++ b/ui/vnc.h > @@ -29,9 +29,7 @@ > > #include "qemu-common.h" > #include "qemu-queue.h" > -#ifdef CONFIG_VNC_THREAD > #include "qemu-thread.h" > -#endif > #include "console.h" > #include "monitor.h" > #include "audio/audio.h" > @@ -146,9 +144,7 @@ struct VncDisplay > DisplayState *ds; > kbd_layout_t *kbd_layout; > int lock_key_sync; > -#ifdef CONFIG_VNC_THREAD > QemuMutex mutex; > -#endif > > QEMUCursor *cursor; > int cursor_msize; > @@ -216,7 +212,6 @@ typedef struct VncZywrle { > int buf[VNC_ZRLE_TILE_WIDTH * VNC_ZRLE_TILE_HEIGHT]; > } VncZywrle; > > -#ifdef CONFIG_VNC_THREAD > struct VncRect > { > int x; > @@ -238,14 +233,6 @@ struct VncJob > QLIST_HEAD(, VncRectEntry) rectangles; > QTAILQ_ENTRY(VncJob) next; > }; > -#else > -struct VncJob > -{ > - VncState *vs; > - int rectangles; > - size_t saved_offset; > -}; > -#endif > > struct VncState > { > @@ -300,13 +287,9 @@ struct VncState > QEMUPutLEDEntry *led; > > bool abort; > -#ifndef CONFIG_VNC_THREAD > - VncJob job; > -#else > QemuMutex output_mutex; > QEMUBH *bh; > Buffer jobs_buffer; > -#endif > > /* Encoding specific, if you add something here, don't forget to > * update vnc_async_encoding_start()
diff --git a/configure b/configure index b68c0ca..4767532 100755 --- a/configure +++ b/configure @@ -134,7 +134,6 @@ vnc_tls="" vnc_sasl="" vnc_jpeg="" vnc_png="" -vnc_thread="no" xen="" xen_ctrl_version="" linux_aio="" @@ -666,10 +665,6 @@ for opt do ;; --enable-vnc-png) vnc_png="yes" ;; - --disable-vnc-thread) vnc_thread="no" - ;; - --enable-vnc-thread) vnc_thread="yes" - ;; --disable-slirp) slirp="no" ;; --disable-uuid) uuid="no" @@ -2998,7 +2993,6 @@ if test "$vnc" = "yes" ; then echo "VNC SASL support $vnc_sasl" echo "VNC JPEG support $vnc_jpeg" echo "VNC PNG support $vnc_png" - echo "VNC thread $vnc_thread" fi if test -n "$sparc_cpu"; then echo "Target Sparc Arch $sparc_cpu" @@ -3174,9 +3168,6 @@ if test "$vnc_png" = "yes" ; then echo "CONFIG_VNC_PNG=y" >> $config_host_mak echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak fi -if test "$vnc_thread" = "yes" ; then - echo "CONFIG_VNC_THREAD=y" >> $config_host_mak -fi if test "$fnmatch" = "yes" ; then echo "CONFIG_FNMATCH=y" >> $config_host_mak fi diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 3687c8a..adc07be 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -4,11 +4,7 @@ vnc-obj-y += vnc-enc-tight.o vnc-palette.o vnc-obj-y += vnc-enc-zrle.o vnc-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o -ifdef CONFIG_VNC_THREAD -vnc-obj-y += vnc-jobs-async.o -else -vnc-obj-y += vnc-jobs-sync.o -endif +vnc-obj-y += vnc-jobs.o common-obj-y += keymaps.o common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o diff --git a/ui/vnc-jobs-async.c b/ui/vnc-jobs-async.c deleted file mode 100644 index 087b84d..0000000 --- a/ui/vnc-jobs-async.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * QEMU VNC display driver - * - * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws> - * Copyright (C) 2006 Fabrice Bellard - * Copyright (C) 2009 Red Hat, Inc - * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - - -#include "vnc.h" -#include "vnc-jobs.h" -#include "qemu_socket.h" - -/* - * Locking: - * - * There is three levels of locking: - * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?) - * - VncDisplay global lock: mainly used for framebuffer updates to avoid - * screen corruption if the framebuffer is updated - * while the worker is doing something. - * - VncState::output lock: used to make sure the output buffer is not corrupted - * if two threads try to write on it at the same time - * - * While the VNC worker thread is working, the VncDisplay global lock is hold - * to avoid screen corruptions (this does not block vnc_refresh() because it - * uses trylock()) but the output lock is not hold because the thread work on - * its own output buffer. - * When the encoding job is done, the worker thread will hold the output lock - * and copy its output buffer in vs->output. -*/ - -struct VncJobQueue { - QemuCond cond; - QemuMutex mutex; - QemuThread thread; - Buffer buffer; - bool exit; - QTAILQ_HEAD(, VncJob) jobs; -}; - -typedef struct VncJobQueue VncJobQueue; - -/* - * We use a single global queue, but most of the functions are - * already reetrant, so we can easilly add more than one encoding thread - */ -static VncJobQueue *queue; - -static void vnc_lock_queue(VncJobQueue *queue) -{ - qemu_mutex_lock(&queue->mutex); -} - -static void vnc_unlock_queue(VncJobQueue *queue) -{ - qemu_mutex_unlock(&queue->mutex); -} - -VncJob *vnc_job_new(VncState *vs) -{ - VncJob *job = g_malloc0(sizeof(VncJob)); - - job->vs = vs; - vnc_lock_queue(queue); - QLIST_INIT(&job->rectangles); - vnc_unlock_queue(queue); - return job; -} - -int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h) -{ - VncRectEntry *entry = g_malloc0(sizeof(VncRectEntry)); - - entry->rect.x = x; - entry->rect.y = y; - entry->rect.w = w; - entry->rect.h = h; - - vnc_lock_queue(queue); - QLIST_INSERT_HEAD(&job->rectangles, entry, next); - vnc_unlock_queue(queue); - return 1; -} - -void vnc_job_push(VncJob *job) -{ - vnc_lock_queue(queue); - if (queue->exit || QLIST_EMPTY(&job->rectangles)) { - g_free(job); - } else { - QTAILQ_INSERT_TAIL(&queue->jobs, job, next); - qemu_cond_broadcast(&queue->cond); - } - vnc_unlock_queue(queue); -} - -static bool vnc_has_job_locked(VncState *vs) -{ - VncJob *job; - - QTAILQ_FOREACH(job, &queue->jobs, next) { - if (job->vs == vs || !vs) { - return true; - } - } - return false; -} - -bool vnc_has_job(VncState *vs) -{ - bool ret; - - vnc_lock_queue(queue); - ret = vnc_has_job_locked(vs); - vnc_unlock_queue(queue); - return ret; -} - -void vnc_jobs_clear(VncState *vs) -{ - VncJob *job, *tmp; - - vnc_lock_queue(queue); - QTAILQ_FOREACH_SAFE(job, &queue->jobs, next, tmp) { - if (job->vs == vs || !vs) { - QTAILQ_REMOVE(&queue->jobs, job, next); - } - } - vnc_unlock_queue(queue); -} - -void vnc_jobs_join(VncState *vs) -{ - vnc_lock_queue(queue); - while (vnc_has_job_locked(vs)) { - qemu_cond_wait(&queue->cond, &queue->mutex); - } - vnc_unlock_queue(queue); - vnc_jobs_consume_buffer(vs); -} - -void vnc_jobs_consume_buffer(VncState *vs) -{ - bool flush; - - vnc_lock_output(vs); - if (vs->jobs_buffer.offset) { - vnc_write(vs, vs->jobs_buffer.buffer, vs->jobs_buffer.offset); - buffer_reset(&vs->jobs_buffer); - } - flush = vs->csock != -1 && vs->abort != true; - vnc_unlock_output(vs); - - if (flush) { - vnc_flush(vs); - } -} - -/* - * Copy data for local use - */ -static void vnc_async_encoding_start(VncState *orig, VncState *local) -{ - local->vnc_encoding = orig->vnc_encoding; - local->features = orig->features; - local->ds = orig->ds; - local->vd = orig->vd; - local->lossy_rect = orig->lossy_rect; - local->write_pixels = orig->write_pixels; - local->clientds = orig->clientds; - local->tight = orig->tight; - local->zlib = orig->zlib; - local->hextile = orig->hextile; - local->zrle = orig->zrle; - local->output = queue->buffer; - local->csock = -1; /* Don't do any network work on this thread */ - - buffer_reset(&local->output); -} - -static void vnc_async_encoding_end(VncState *orig, VncState *local) -{ - orig->tight = local->tight; - orig->zlib = local->zlib; - orig->hextile = local->hextile; - orig->zrle = local->zrle; - orig->lossy_rect = local->lossy_rect; - - queue->buffer = local->output; -} - -static int vnc_worker_thread_loop(VncJobQueue *queue) -{ - VncJob *job; - VncRectEntry *entry, *tmp; - VncState vs; - int n_rectangles; - int saved_offset; - - vnc_lock_queue(queue); - while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) { - qemu_cond_wait(&queue->cond, &queue->mutex); - } - /* Here job can only be NULL if queue->exit is true */ - job = QTAILQ_FIRST(&queue->jobs); - vnc_unlock_queue(queue); - - if (queue->exit) { - return -1; - } - - vnc_lock_output(job->vs); - if (job->vs->csock == -1 || job->vs->abort == true) { - vnc_unlock_output(job->vs); - goto disconnected; - } - vnc_unlock_output(job->vs); - - /* Make a local copy of vs and switch output buffers */ - vnc_async_encoding_start(job->vs, &vs); - - /* Start sending rectangles */ - n_rectangles = 0; - vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); - vnc_write_u8(&vs, 0); - saved_offset = vs.output.offset; - vnc_write_u16(&vs, 0); - - vnc_lock_display(job->vs->vd); - QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) { - int n; - - if (job->vs->csock == -1) { - vnc_unlock_display(job->vs->vd); - goto disconnected; - } - - n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y, - entry->rect.w, entry->rect.h); - - if (n >= 0) { - n_rectangles += n; - } - g_free(entry); - } - vnc_unlock_display(job->vs->vd); - - /* Put n_rectangles at the beginning of the message */ - vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; - vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF; - - vnc_lock_output(job->vs); - if (job->vs->csock != -1) { - buffer_reserve(&job->vs->jobs_buffer, vs.output.offset); - buffer_append(&job->vs->jobs_buffer, vs.output.buffer, - vs.output.offset); - /* Copy persistent encoding data */ - vnc_async_encoding_end(job->vs, &vs); - - qemu_bh_schedule(job->vs->bh); - } - vnc_unlock_output(job->vs); - -disconnected: - vnc_lock_queue(queue); - QTAILQ_REMOVE(&queue->jobs, job, next); - vnc_unlock_queue(queue); - qemu_cond_broadcast(&queue->cond); - g_free(job); - return 0; -} - -static VncJobQueue *vnc_queue_init(void) -{ - VncJobQueue *queue = g_malloc0(sizeof(VncJobQueue)); - - qemu_cond_init(&queue->cond); - qemu_mutex_init(&queue->mutex); - QTAILQ_INIT(&queue->jobs); - return queue; -} - -static void vnc_queue_clear(VncJobQueue *q) -{ - qemu_cond_destroy(&queue->cond); - qemu_mutex_destroy(&queue->mutex); - buffer_free(&queue->buffer); - g_free(q); - queue = NULL; /* Unset global queue */ -} - -static void *vnc_worker_thread(void *arg) -{ - VncJobQueue *queue = arg; - - qemu_thread_get_self(&queue->thread); - - while (!vnc_worker_thread_loop(queue)) ; - vnc_queue_clear(queue); - return NULL; -} - -void vnc_start_worker_thread(void) -{ - VncJobQueue *q; - - if (vnc_worker_thread_running()) - return ; - - q = vnc_queue_init(); - qemu_thread_create(&q->thread, vnc_worker_thread, q, QEMU_THREAD_DETACHED); - queue = q; /* Set global queue */ -} - -bool vnc_worker_thread_running(void) -{ - return queue; /* Check global queue */ -} - -void vnc_stop_worker_thread(void) -{ - if (!vnc_worker_thread_running()) - return ; - - /* Remove all jobs and wake up the thread */ - vnc_lock_queue(queue); - queue->exit = true; - vnc_unlock_queue(queue); - vnc_jobs_clear(NULL); - qemu_cond_broadcast(&queue->cond); -} diff --git a/ui/vnc-jobs-sync.c b/ui/vnc-jobs-sync.c deleted file mode 100644 index 49b77af..0000000 --- a/ui/vnc-jobs-sync.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * QEMU VNC display driver - * - * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws> - * Copyright (C) 2006 Fabrice Bellard - * Copyright (C) 2009 Red Hat, Inc - * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "vnc.h" -#include "vnc-jobs.h" - -void vnc_jobs_clear(VncState *vs) -{ -} - -void vnc_jobs_join(VncState *vs) -{ -} - -VncJob *vnc_job_new(VncState *vs) -{ - vs->job.vs = vs; - vs->job.rectangles = 0; - - vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); - vnc_write_u8(vs, 0); - vs->job.saved_offset = vs->output.offset; - vnc_write_u16(vs, 0); - return &vs->job; -} - -void vnc_job_push(VncJob *job) -{ - VncState *vs = job->vs; - - vs->output.buffer[job->saved_offset] = (job->rectangles >> 8) & 0xFF; - vs->output.buffer[job->saved_offset + 1] = job->rectangles & 0xFF; - vnc_flush(job->vs); -} - -int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h) -{ - int n; - - n = vnc_send_framebuffer_update(job->vs, x, y, w, h); - if (n >= 0) - job->rectangles += n; - return n; -} - -bool vnc_has_job(VncState *vs) -{ - return false; -} diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c new file mode 100644 index 0000000..087b84d --- /dev/null +++ b/ui/vnc-jobs.c @@ -0,0 +1,351 @@ +/* + * QEMU VNC display driver + * + * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws> + * Copyright (C) 2006 Fabrice Bellard + * Copyright (C) 2009 Red Hat, Inc + * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "vnc.h" +#include "vnc-jobs.h" +#include "qemu_socket.h" + +/* + * Locking: + * + * There is three levels of locking: + * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?) + * - VncDisplay global lock: mainly used for framebuffer updates to avoid + * screen corruption if the framebuffer is updated + * while the worker is doing something. + * - VncState::output lock: used to make sure the output buffer is not corrupted + * if two threads try to write on it at the same time + * + * While the VNC worker thread is working, the VncDisplay global lock is hold + * to avoid screen corruptions (this does not block vnc_refresh() because it + * uses trylock()) but the output lock is not hold because the thread work on + * its own output buffer. + * When the encoding job is done, the worker thread will hold the output lock + * and copy its output buffer in vs->output. +*/ + +struct VncJobQueue { + QemuCond cond; + QemuMutex mutex; + QemuThread thread; + Buffer buffer; + bool exit; + QTAILQ_HEAD(, VncJob) jobs; +}; + +typedef struct VncJobQueue VncJobQueue; + +/* + * We use a single global queue, but most of the functions are + * already reetrant, so we can easilly add more than one encoding thread + */ +static VncJobQueue *queue; + +static void vnc_lock_queue(VncJobQueue *queue) +{ + qemu_mutex_lock(&queue->mutex); +} + +static void vnc_unlock_queue(VncJobQueue *queue) +{ + qemu_mutex_unlock(&queue->mutex); +} + +VncJob *vnc_job_new(VncState *vs) +{ + VncJob *job = g_malloc0(sizeof(VncJob)); + + job->vs = vs; + vnc_lock_queue(queue); + QLIST_INIT(&job->rectangles); + vnc_unlock_queue(queue); + return job; +} + +int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h) +{ + VncRectEntry *entry = g_malloc0(sizeof(VncRectEntry)); + + entry->rect.x = x; + entry->rect.y = y; + entry->rect.w = w; + entry->rect.h = h; + + vnc_lock_queue(queue); + QLIST_INSERT_HEAD(&job->rectangles, entry, next); + vnc_unlock_queue(queue); + return 1; +} + +void vnc_job_push(VncJob *job) +{ + vnc_lock_queue(queue); + if (queue->exit || QLIST_EMPTY(&job->rectangles)) { + g_free(job); + } else { + QTAILQ_INSERT_TAIL(&queue->jobs, job, next); + qemu_cond_broadcast(&queue->cond); + } + vnc_unlock_queue(queue); +} + +static bool vnc_has_job_locked(VncState *vs) +{ + VncJob *job; + + QTAILQ_FOREACH(job, &queue->jobs, next) { + if (job->vs == vs || !vs) { + return true; + } + } + return false; +} + +bool vnc_has_job(VncState *vs) +{ + bool ret; + + vnc_lock_queue(queue); + ret = vnc_has_job_locked(vs); + vnc_unlock_queue(queue); + return ret; +} + +void vnc_jobs_clear(VncState *vs) +{ + VncJob *job, *tmp; + + vnc_lock_queue(queue); + QTAILQ_FOREACH_SAFE(job, &queue->jobs, next, tmp) { + if (job->vs == vs || !vs) { + QTAILQ_REMOVE(&queue->jobs, job, next); + } + } + vnc_unlock_queue(queue); +} + +void vnc_jobs_join(VncState *vs) +{ + vnc_lock_queue(queue); + while (vnc_has_job_locked(vs)) { + qemu_cond_wait(&queue->cond, &queue->mutex); + } + vnc_unlock_queue(queue); + vnc_jobs_consume_buffer(vs); +} + +void vnc_jobs_consume_buffer(VncState *vs) +{ + bool flush; + + vnc_lock_output(vs); + if (vs->jobs_buffer.offset) { + vnc_write(vs, vs->jobs_buffer.buffer, vs->jobs_buffer.offset); + buffer_reset(&vs->jobs_buffer); + } + flush = vs->csock != -1 && vs->abort != true; + vnc_unlock_output(vs); + + if (flush) { + vnc_flush(vs); + } +} + +/* + * Copy data for local use + */ +static void vnc_async_encoding_start(VncState *orig, VncState *local) +{ + local->vnc_encoding = orig->vnc_encoding; + local->features = orig->features; + local->ds = orig->ds; + local->vd = orig->vd; + local->lossy_rect = orig->lossy_rect; + local->write_pixels = orig->write_pixels; + local->clientds = orig->clientds; + local->tight = orig->tight; + local->zlib = orig->zlib; + local->hextile = orig->hextile; + local->zrle = orig->zrle; + local->output = queue->buffer; + local->csock = -1; /* Don't do any network work on this thread */ + + buffer_reset(&local->output); +} + +static void vnc_async_encoding_end(VncState *orig, VncState *local) +{ + orig->tight = local->tight; + orig->zlib = local->zlib; + orig->hextile = local->hextile; + orig->zrle = local->zrle; + orig->lossy_rect = local->lossy_rect; + + queue->buffer = local->output; +} + +static int vnc_worker_thread_loop(VncJobQueue *queue) +{ + VncJob *job; + VncRectEntry *entry, *tmp; + VncState vs; + int n_rectangles; + int saved_offset; + + vnc_lock_queue(queue); + while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) { + qemu_cond_wait(&queue->cond, &queue->mutex); + } + /* Here job can only be NULL if queue->exit is true */ + job = QTAILQ_FIRST(&queue->jobs); + vnc_unlock_queue(queue); + + if (queue->exit) { + return -1; + } + + vnc_lock_output(job->vs); + if (job->vs->csock == -1 || job->vs->abort == true) { + vnc_unlock_output(job->vs); + goto disconnected; + } + vnc_unlock_output(job->vs); + + /* Make a local copy of vs and switch output buffers */ + vnc_async_encoding_start(job->vs, &vs); + + /* Start sending rectangles */ + n_rectangles = 0; + vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); + vnc_write_u8(&vs, 0); + saved_offset = vs.output.offset; + vnc_write_u16(&vs, 0); + + vnc_lock_display(job->vs->vd); + QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) { + int n; + + if (job->vs->csock == -1) { + vnc_unlock_display(job->vs->vd); + goto disconnected; + } + + n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y, + entry->rect.w, entry->rect.h); + + if (n >= 0) { + n_rectangles += n; + } + g_free(entry); + } + vnc_unlock_display(job->vs->vd); + + /* Put n_rectangles at the beginning of the message */ + vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; + vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF; + + vnc_lock_output(job->vs); + if (job->vs->csock != -1) { + buffer_reserve(&job->vs->jobs_buffer, vs.output.offset); + buffer_append(&job->vs->jobs_buffer, vs.output.buffer, + vs.output.offset); + /* Copy persistent encoding data */ + vnc_async_encoding_end(job->vs, &vs); + + qemu_bh_schedule(job->vs->bh); + } + vnc_unlock_output(job->vs); + +disconnected: + vnc_lock_queue(queue); + QTAILQ_REMOVE(&queue->jobs, job, next); + vnc_unlock_queue(queue); + qemu_cond_broadcast(&queue->cond); + g_free(job); + return 0; +} + +static VncJobQueue *vnc_queue_init(void) +{ + VncJobQueue *queue = g_malloc0(sizeof(VncJobQueue)); + + qemu_cond_init(&queue->cond); + qemu_mutex_init(&queue->mutex); + QTAILQ_INIT(&queue->jobs); + return queue; +} + +static void vnc_queue_clear(VncJobQueue *q) +{ + qemu_cond_destroy(&queue->cond); + qemu_mutex_destroy(&queue->mutex); + buffer_free(&queue->buffer); + g_free(q); + queue = NULL; /* Unset global queue */ +} + +static void *vnc_worker_thread(void *arg) +{ + VncJobQueue *queue = arg; + + qemu_thread_get_self(&queue->thread); + + while (!vnc_worker_thread_loop(queue)) ; + vnc_queue_clear(queue); + return NULL; +} + +void vnc_start_worker_thread(void) +{ + VncJobQueue *q; + + if (vnc_worker_thread_running()) + return ; + + q = vnc_queue_init(); + qemu_thread_create(&q->thread, vnc_worker_thread, q, QEMU_THREAD_DETACHED); + queue = q; /* Set global queue */ +} + +bool vnc_worker_thread_running(void) +{ + return queue; /* Check global queue */ +} + +void vnc_stop_worker_thread(void) +{ + if (!vnc_worker_thread_running()) + return ; + + /* Remove all jobs and wake up the thread */ + vnc_lock_queue(queue); + queue->exit = true; + vnc_unlock_queue(queue); + vnc_jobs_clear(NULL); + qemu_cond_broadcast(&queue->cond); +} diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h index 4c661f9..86e6d88 100644 --- a/ui/vnc-jobs.h +++ b/ui/vnc-jobs.h @@ -38,51 +38,35 @@ bool vnc_has_job(VncState *vs); void vnc_jobs_clear(VncState *vs); void vnc_jobs_join(VncState *vs); -#ifdef CONFIG_VNC_THREAD - void vnc_jobs_consume_buffer(VncState *vs); void vnc_start_worker_thread(void); bool vnc_worker_thread_running(void); void vnc_stop_worker_thread(void); -#endif /* CONFIG_VNC_THREAD */ - /* Locks */ static inline int vnc_trylock_display(VncDisplay *vd) { -#ifdef CONFIG_VNC_THREAD return qemu_mutex_trylock(&vd->mutex); -#else - return 0; -#endif } static inline void vnc_lock_display(VncDisplay *vd) { -#ifdef CONFIG_VNC_THREAD qemu_mutex_lock(&vd->mutex); -#endif } static inline void vnc_unlock_display(VncDisplay *vd) { -#ifdef CONFIG_VNC_THREAD qemu_mutex_unlock(&vd->mutex); -#endif } static inline void vnc_lock_output(VncState *vs) { -#ifdef CONFIG_VNC_THREAD qemu_mutex_lock(&vs->output_mutex); -#endif } static inline void vnc_unlock_output(VncState *vs) { -#ifdef CONFIG_VNC_THREAD qemu_mutex_unlock(&vs->output_mutex); -#endif } #endif /* VNC_JOBS_H */ diff --git a/ui/vnc.c b/ui/vnc.c index 54bc5ad..cf1cae2 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -526,7 +526,6 @@ static void vnc_desktop_resize(VncState *vs) vnc_flush(vs); } -#ifdef CONFIG_VNC_THREAD static void vnc_abort_display_jobs(VncDisplay *vd) { VncState *vs; @@ -545,11 +544,6 @@ static void vnc_abort_display_jobs(VncDisplay *vd) vnc_unlock_output(vs); } } -#else -static void vnc_abort_display_jobs(VncDisplay *vd) -{ -} -#endif static void vnc_dpy_resize(DisplayState *ds) { @@ -867,19 +861,12 @@ static int find_and_clear_dirty_height(struct VncState *vs, return h; } -#ifdef CONFIG_VNC_THREAD static int vnc_update_client_sync(VncState *vs, int has_dirty) { int ret = vnc_update_client(vs, has_dirty); vnc_jobs_join(vs); return ret; } -#else -static int vnc_update_client_sync(VncState *vs, int has_dirty) -{ - return vnc_update_client(vs, has_dirty); -} -#endif static int vnc_update_client(VncState *vs, int has_dirty) { @@ -1066,11 +1053,9 @@ static void vnc_disconnect_finish(VncState *vs) qemu_remove_led_event_handler(vs->led); vnc_unlock_output(vs); -#ifdef CONFIG_VNC_THREAD qemu_mutex_destroy(&vs->output_mutex); qemu_bh_delete(vs->bh); buffer_free(&vs->jobs_buffer); -#endif for (i = 0; i < VNC_STAT_ROWS; ++i) { g_free(vs->lossy_rect[i]); @@ -1286,14 +1271,12 @@ static long vnc_client_read_plain(VncState *vs) return ret; } -#ifdef CONFIG_VNC_THREAD static void vnc_jobs_bh(void *opaque) { VncState *vs = opaque; vnc_jobs_consume_buffer(vs); } -#endif /* * First function called whenever there is more data to be read from @@ -2699,10 +2682,8 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth) vs->as.fmt = AUD_FMT_S16; vs->as.endianness = 0; -#ifdef CONFIG_VNC_THREAD qemu_mutex_init(&vs->output_mutex); vs->bh = qemu_bh_new(vnc_jobs_bh, vs); -#endif QTAILQ_INSERT_HEAD(&vd->clients, vs, next); @@ -2762,10 +2743,8 @@ void vnc_display_init(DisplayState *ds) if (!vs->kbd_layout) exit(1); -#ifdef CONFIG_VNC_THREAD qemu_mutex_init(&vs->mutex); vnc_start_worker_thread(); -#endif dcl->dpy_copy = vnc_dpy_copy; dcl->dpy_update = vnc_dpy_update; diff --git a/ui/vnc.h b/ui/vnc.h index a851ebd..068c2fc 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -29,9 +29,7 @@ #include "qemu-common.h" #include "qemu-queue.h" -#ifdef CONFIG_VNC_THREAD #include "qemu-thread.h" -#endif #include "console.h" #include "monitor.h" #include "audio/audio.h" @@ -146,9 +144,7 @@ struct VncDisplay DisplayState *ds; kbd_layout_t *kbd_layout; int lock_key_sync; -#ifdef CONFIG_VNC_THREAD QemuMutex mutex; -#endif QEMUCursor *cursor; int cursor_msize; @@ -216,7 +212,6 @@ typedef struct VncZywrle { int buf[VNC_ZRLE_TILE_WIDTH * VNC_ZRLE_TILE_HEIGHT]; } VncZywrle; -#ifdef CONFIG_VNC_THREAD struct VncRect { int x; @@ -238,14 +233,6 @@ struct VncJob QLIST_HEAD(, VncRectEntry) rectangles; QTAILQ_ENTRY(VncJob) next; }; -#else -struct VncJob -{ - VncState *vs; - int rectangles; - size_t saved_offset; -}; -#endif struct VncState { @@ -300,13 +287,9 @@ struct VncState QEMUPutLEDEntry *led; bool abort; -#ifndef CONFIG_VNC_THREAD - VncJob job; -#else QemuMutex output_mutex; QEMUBH *bh; Buffer jobs_buffer; -#endif /* Encoding specific, if you add something here, don't forget to * update vnc_async_encoding_start()