Revision bd023f95

b/Makefile.objs
111 111
ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
112 112
ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
113 113
ui-obj-$(CONFIG_COCOA) += cocoa.o
114
ifdef CONFIG_VNC_THREAD
115
ui-obj-y += vnc-jobs-async.o
116
else
117
ui-obj-y += vnc-jobs-sync.o
118
endif
114 119
common-obj-y += $(addprefix ui/, $(ui-obj-y))
115 120

  
116 121
common-obj-y += iov.o acl.o
117
common-obj-$(CONFIG_IOTHREAD) += qemu-thread.o
122
common-obj-$(CONFIG_THREAD) += qemu-thread.o
118 123
common-obj-y += notify.o event_notifier.o
119 124
common-obj-y += qemu-timer.o
120 125

  
b/configure
270 270
vnc_sasl=""
271 271
vnc_jpeg=""
272 272
vnc_png=""
273
vnc_thread=""
273 274
xen=""
274 275
linux_aio=""
275 276
attr=""
......
585 586
  ;;
586 587
  --enable-vnc-png) vnc_png="yes"
587 588
  ;;
589
  --disable-vnc-thread) vnc_thread="no"
590
  ;;
591
  --enable-vnc-thread) vnc_thread="yes"
592
  ;;
588 593
  --disable-slirp) slirp="no"
589 594
  ;;
590 595
  --disable-uuid) uuid="no"
......
839 844
echo "  --enable-vnc-jpeg        enable JPEG lossy compression for VNC server"
840 845
echo "  --disable-vnc-png        disable PNG compression for VNC server"
841 846
echo "  --enable-vnc-png         enable PNG compression for VNC server"
847
echo "  --disable-vnc-thread     disable threaded VNC server"
848
echo "  --enable-vnc-thread      enable threaded VNC server"
842 849
echo "  --disable-curses         disable curses output"
843 850
echo "  --enable-curses          enable curses output"
844 851
echo "  --disable-curl           disable curl connectivity"
......
2156 2163
echo "VNC SASL support  $vnc_sasl"
2157 2164
echo "VNC JPEG support  $vnc_jpeg"
2158 2165
echo "VNC PNG support   $vnc_png"
2166
echo "VNC thread        $vnc_thread"
2159 2167
if test -n "$sparc_cpu"; then
2160 2168
    echo "Target Sparc Arch $sparc_cpu"
2161 2169
fi
......
2301 2309
  echo "CONFIG_VNC_PNG=y" >> $config_host_mak
2302 2310
  echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak
2303 2311
fi
2312
if test "$vnc_thread" = "yes" ; then
2313
  echo "CONFIG_VNC_THREAD=y" >> $config_host_mak
2314
  echo "CONFIG_THREAD=y" >> $config_host_mak
2315
fi
2304 2316
if test "$fnmatch" = "yes" ; then
2305 2317
  echo "CONFIG_FNMATCH=y" >> $config_host_mak
2306 2318
fi
......
2377 2389
fi
2378 2390
if test "$io_thread" = "yes" ; then
2379 2391
  echo "CONFIG_IOTHREAD=y" >> $config_host_mak
2392
  echo "CONFIG_THREAD=y" >> $config_host_mak
2380 2393
fi
2381 2394
if test "$linux_aio" = "yes" ; then
2382 2395
  echo "CONFIG_LINUX_AIO=y" >> $config_host_mak
b/ui/vnc-jobs-async.c
1
/*
2
 * QEMU VNC display driver
3
 *
4
 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5
 * Copyright (C) 2006 Fabrice Bellard
6
 * Copyright (C) 2009 Red Hat, Inc
7
 * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy
10
 * of this software and associated documentation files (the "Software"), to deal
11
 * in the Software without restriction, including without limitation the rights
12
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 * copies of the Software, and to permit persons to whom the Software is
14
 * furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in
17
 * all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
 * THE SOFTWARE.
26
 */
27

  
28

  
29
#include "vnc.h"
30
#include "vnc-jobs.h"
31

  
32
/*
33
 * Locking:
34
 *
35
 * There is three levels of locking:
36
 * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?)
37
 * - VncDisplay global lock: mainly used for framebuffer updates to avoid
38
 *                      screen corruption if the framebuffer is updated
39
 *			while the worker is doing something.
40
 * - VncState::output lock: used to make sure the output buffer is not corrupted
41
 * 		   	 if two threads try to write on it at the same time
42
 *
43
 * While the VNC worker thread is working, the VncDisplay global lock is hold
44
 * to avoid screen corruptions (this does not block vnc_refresh() because it
45
 * uses trylock()) but the output lock is not hold because the thread work on
46
 * its own output buffer.
47
 * When the encoding job is done, the worker thread will hold the output lock
48
 * and copy its output buffer in vs->output.
49
*/
50

  
51
struct VncJobQueue {
52
    QemuCond cond;
53
    QemuMutex mutex;
54
    QemuThread thread;
55
    Buffer buffer;
56
    bool exit;
57
    QTAILQ_HEAD(, VncJob) jobs;
58
};
59

  
60
typedef struct VncJobQueue VncJobQueue;
61

  
62
/*
63
 * We use a single global queue, but most of the functions are
64
 * already reetrant, so we can easilly add more than one encoding thread
65
 */
66
static VncJobQueue *queue;
67

  
68
static void vnc_lock_queue(VncJobQueue *queue)
69
{
70
    qemu_mutex_lock(&queue->mutex);
71
}
72

  
73
static void vnc_unlock_queue(VncJobQueue *queue)
74
{
75
    qemu_mutex_unlock(&queue->mutex);
76
}
77

  
78
VncJob *vnc_job_new(VncState *vs)
79
{
80
    VncJob *job = qemu_mallocz(sizeof(VncJob));
81

  
82
    job->vs = vs;
83
    vnc_lock_queue(queue);
84
    QLIST_INIT(&job->rectangles);
85
    vnc_unlock_queue(queue);
86
    return job;
87
}
88

  
89
int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
90
{
91
    VncRectEntry *entry = qemu_mallocz(sizeof(VncRectEntry));
92

  
93
    entry->rect.x = x;
94
    entry->rect.y = y;
95
    entry->rect.w = w;
96
    entry->rect.h = h;
97

  
98
    vnc_lock_queue(queue);
99
    QLIST_INSERT_HEAD(&job->rectangles, entry, next);
100
    vnc_unlock_queue(queue);
101
    return 1;
102
}
103

  
104
void vnc_job_push(VncJob *job)
105
{
106
    vnc_lock_queue(queue);
107
    if (queue->exit || QLIST_EMPTY(&job->rectangles)) {
108
        qemu_free(job);
109
    } else {
110
        QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
111
        qemu_cond_broadcast(&queue->cond);
112
    }
113
    vnc_unlock_queue(queue);
114
}
115

  
116
static bool vnc_has_job_locked(VncState *vs)
117
{
118
    VncJob *job;
119

  
120
    QTAILQ_FOREACH(job, &queue->jobs, next) {
121
        if (job->vs == vs || !vs) {
122
            return true;
123
        }
124
    }
125
    return false;
126
}
127

  
128
bool vnc_has_job(VncState *vs)
129
{
130
    bool ret;
131

  
132
    vnc_lock_queue(queue);
133
    ret = vnc_has_job_locked(vs);
134
    vnc_unlock_queue(queue);
135
    return ret;
136
}
137

  
138
void vnc_jobs_clear(VncState *vs)
139
{
140
    VncJob *job, *tmp;
141

  
142
    vnc_lock_queue(queue);
143
    QTAILQ_FOREACH_SAFE(job, &queue->jobs, next, tmp) {
144
        if (job->vs == vs || !vs) {
145
            QTAILQ_REMOVE(&queue->jobs, job, next);
146
        }
147
    }
148
    vnc_unlock_queue(queue);
149
}
150

  
151
void vnc_jobs_join(VncState *vs)
152
{
153
    vnc_lock_queue(queue);
154
    while (vnc_has_job_locked(vs)) {
155
        qemu_cond_wait(&queue->cond, &queue->mutex);
156
    }
157
    vnc_unlock_queue(queue);
158
}
159

  
160
/*
161
 * Copy data for local use
162
 */
163
static void vnc_async_encoding_start(VncState *orig, VncState *local)
164
{
165
    local->vnc_encoding = orig->vnc_encoding;
166
    local->features = orig->features;
167
    local->ds = orig->ds;
168
    local->vd = orig->vd;
169
    local->write_pixels = orig->write_pixels;
170
    local->clientds = orig->clientds;
171
    local->tight = orig->tight;
172
    local->zlib = orig->zlib;
173
    local->hextile = orig->hextile;
174
    local->output =  queue->buffer;
175
    local->csock = -1; /* Don't do any network work on this thread */
176

  
177
    buffer_reset(&local->output);
178
}
179

  
180
static void vnc_async_encoding_end(VncState *orig, VncState *local)
181
{
182
    orig->tight = local->tight;
183
    orig->zlib = local->zlib;
184
    orig->hextile = local->hextile;
185
}
186

  
187
static int vnc_worker_thread_loop(VncJobQueue *queue)
188
{
189
    VncJob *job;
190
    VncRectEntry *entry, *tmp;
191
    VncState vs;
192
    int n_rectangles;
193
    int saved_offset;
194
    bool flush;
195

  
196
    vnc_lock_queue(queue);
197
    while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) {
198
        qemu_cond_wait(&queue->cond, &queue->mutex);
199
    }
200
    /* Here job can only be NULL if queue->exit is true */
201
    job = QTAILQ_FIRST(&queue->jobs);
202
    vnc_unlock_queue(queue);
203

  
204
    if (queue->exit) {
205
        return -1;
206
    }
207

  
208
    vnc_lock_output(job->vs);
209
    if (job->vs->csock == -1 || job->vs->abort == true) {
210
        goto disconnected;
211
    }
212
    vnc_unlock_output(job->vs);
213

  
214
    /* Make a local copy of vs and switch output buffers */
215
    vnc_async_encoding_start(job->vs, &vs);
216

  
217
    /* Start sending rectangles */
218
    n_rectangles = 0;
219
    vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
220
    vnc_write_u8(&vs, 0);
221
    saved_offset = vs.output.offset;
222
    vnc_write_u16(&vs, 0);
223

  
224
    vnc_lock_display(job->vs->vd);
225
    QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
226
        int n;
227

  
228
        if (job->vs->csock == -1) {
229
            vnc_unlock_display(job->vs->vd);
230
            goto disconnected;
231
        }
232

  
233
        n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
234
                                        entry->rect.w, entry->rect.h);
235

  
236
        if (n >= 0) {
237
            n_rectangles += n;
238
        }
239
        qemu_free(entry);
240
    }
241
    vnc_unlock_display(job->vs->vd);
242

  
243
    /* Put n_rectangles at the beginning of the message */
244
    vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
245
    vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
246

  
247
    /* Switch back buffers */
248
    vnc_lock_output(job->vs);
249
    if (job->vs->csock == -1) {
250
        goto disconnected;
251
    }
252

  
253
    vnc_write(job->vs, vs.output.buffer, vs.output.offset);
254

  
255
disconnected:
256
    /* Copy persistent encoding data */
257
    vnc_async_encoding_end(job->vs, &vs);
258
    flush = (job->vs->csock != -1 && job->vs->abort != true);
259
    vnc_unlock_output(job->vs);
260

  
261
    if (flush) {
262
        vnc_flush(job->vs);
263
    }
264

  
265
    vnc_lock_queue(queue);
266
    QTAILQ_REMOVE(&queue->jobs, job, next);
267
    vnc_unlock_queue(queue);
268
    qemu_cond_broadcast(&queue->cond);
269
    qemu_free(job);
270
    return 0;
271
}
272

  
273
static VncJobQueue *vnc_queue_init(void)
274
{
275
    VncJobQueue *queue = qemu_mallocz(sizeof(VncJobQueue));
276

  
277
    qemu_cond_init(&queue->cond);
278
    qemu_mutex_init(&queue->mutex);
279
    QTAILQ_INIT(&queue->jobs);
280
    return queue;
281
}
282

  
283
static void vnc_queue_clear(VncJobQueue *q)
284
{
285
    qemu_cond_destroy(&queue->cond);
286
    qemu_mutex_destroy(&queue->mutex);
287
    buffer_free(&queue->buffer);
288
    qemu_free(q);
289
    queue = NULL; /* Unset global queue */
290
}
291

  
292
static void *vnc_worker_thread(void *arg)
293
{
294
    VncJobQueue *queue = arg;
295

  
296
    qemu_thread_self(&queue->thread);
297

  
298
    while (!vnc_worker_thread_loop(queue)) ;
299
    vnc_queue_clear(queue);
300
    return NULL;
301
}
302

  
303
void vnc_start_worker_thread(void)
304
{
305
    VncJobQueue *q;
306

  
307
    if (vnc_worker_thread_running())
308
        return ;
309

  
310
    q = vnc_queue_init();
311
    qemu_thread_create(&q->thread, vnc_worker_thread, q);
312
    queue = q; /* Set global queue */
313
}
314

  
315
bool vnc_worker_thread_running(void)
316
{
317
    return queue; /* Check global queue */
318
}
319

  
320
void vnc_stop_worker_thread(void)
321
{
322
    if (!vnc_worker_thread_running())
323
        return ;
324

  
325
    /* Remove all jobs and wake up the thread */
326
    vnc_lock_queue(queue);
327
    queue->exit = true;
328
    vnc_unlock_queue(queue);
329
    vnc_jobs_clear(NULL);
330
    qemu_cond_broadcast(&queue->cond);
331
}
b/ui/vnc-jobs-sync.c
1
/*
2
 * QEMU VNC display driver
3
 *
4
 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5
 * Copyright (C) 2006 Fabrice Bellard
6
 * Copyright (C) 2009 Red Hat, Inc
7
 * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy
10
 * of this software and associated documentation files (the "Software"), to deal
11
 * in the Software without restriction, including without limitation the rights
12
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 * copies of the Software, and to permit persons to whom the Software is
14
 * furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in
17
 * all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
 * THE SOFTWARE.
26
 */
27

  
28
#include "vnc.h"
29
#include "vnc-jobs.h"
30

  
31
void vnc_jobs_clear(VncState *vs)
32
{
33
}
34

  
35
void vnc_jobs_join(VncState *vs)
36
{
37
}
38

  
39
VncJob *vnc_job_new(VncState *vs)
40
{
41
    vs->job.vs = vs;
42
    vs->job.rectangles = 0;
43

  
44
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
45
    vnc_write_u8(vs, 0);
46
    vs->job.saved_offset = vs->output.offset;
47
    vnc_write_u16(vs, 0);
48
    return &vs->job;
49
}
50

  
51
void vnc_job_push(VncJob *job)
52
{
53
    VncState *vs = job->vs;
54

  
55
    vs->output.buffer[job->saved_offset] = (job->rectangles >> 8) & 0xFF;
56
    vs->output.buffer[job->saved_offset + 1] = job->rectangles & 0xFF;
57
    vnc_flush(job->vs);
58
}
59

  
60
int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
61
{
62
    int n;
63

  
64
    n = vnc_send_framebuffer_update(job->vs, x, y, w, h);
65
    if (n >= 0)
66
        job->rectangles += n;
67
    return n;
68
}
69

  
70
bool vnc_has_job(VncState *vs)
71
{
72
    return false;
73
}
b/ui/vnc-jobs.h
1
/*
2
 * QEMU VNC display driver
3
 *
4
 * From libvncserver/rfb/rfbproto.h
5
 * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
6
 * Copyright (C) 2000-2002 Constantin Kaplinsky.  All Rights Reserved.
7
 * Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
8
 * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
9
 *
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 */
29

  
30
#ifndef VNC_JOBS_H
31
#define VNC_JOBS_H
32

  
33
/* Jobs */
34
VncJob *vnc_job_new(VncState *vs);
35
int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h);
36
void vnc_job_push(VncJob *job);
37
bool vnc_has_job(VncState *vs);
38
void vnc_jobs_clear(VncState *vs);
39
void vnc_jobs_join(VncState *vs);
40

  
41
#ifdef CONFIG_VNC_THREAD
42

  
43
void vnc_start_worker_thread(void);
44
bool vnc_worker_thread_running(void);
45
void vnc_stop_worker_thread(void);
46

  
47
#endif /* CONFIG_VNC_THREAD */
48

  
49
/* Locks */
50
static inline int vnc_trylock_display(VncDisplay *vd)
51
{
52
#ifdef CONFIG_VNC_THREAD
53
    return qemu_mutex_trylock(&vd->mutex);
54
#else
55
    return 0;
56
#endif
57
}
58

  
59
static inline void vnc_lock_display(VncDisplay *vd)
60
{
61
#ifdef CONFIG_VNC_THREAD
62
    qemu_mutex_lock(&vd->mutex);
63
#endif
64
}
65

  
66
static inline void vnc_unlock_display(VncDisplay *vd)
67
{
68
#ifdef CONFIG_VNC_THREAD
69
    qemu_mutex_unlock(&vd->mutex);
70
#endif
71
}
72

  
73
static inline void vnc_lock_output(VncState *vs)
74
{
75
#ifdef CONFIG_VNC_THREAD
76
    qemu_mutex_lock(&vs->output_mutex);
77
#endif
78
}
79

  
80
static inline void vnc_unlock_output(VncState *vs)
81
{
82
#ifdef CONFIG_VNC_THREAD
83
    qemu_mutex_unlock(&vs->output_mutex);
84
#endif
85
}
86

  
87
#endif /* VNC_JOBS_H */
b/ui/vnc.c
25 25
 */
26 26

  
27 27
#include "vnc.h"
28
#include "vnc-jobs.h"
28 29
#include "sysemu.h"
29 30
#include "qemu_socket.h"
30 31
#include "qemu-timer.h"
......
45 46
    } \
46 47
}
47 48

  
48

  
49 49
static VncDisplay *vnc_display; /* needed for info vnc */
50 50
static DisplayChangeListener *dcl;
51 51

  
......
359 359
*/
360 360

  
361 361
static int vnc_update_client(VncState *vs, int has_dirty);
362
static int vnc_update_client_sync(VncState *vs, int has_dirty);
362 363
static void vnc_disconnect_start(VncState *vs);
363 364
static void vnc_disconnect_finish(VncState *vs);
364 365
static void vnc_init_timer(VncDisplay *vd);
......
502 503
    }
503 504
    vs->client_width = ds_get_width(ds);
504 505
    vs->client_height = ds_get_height(ds);
506
    vnc_lock_output(vs);
505 507
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
506 508
    vnc_write_u8(vs, 0);
507 509
    vnc_write_u16(vs, 1); /* number of rects */
508 510
    vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
509 511
                           VNC_ENCODING_DESKTOPRESIZE);
512
    vnc_unlock_output(vs);
510 513
    vnc_flush(vs);
511 514
}
512 515

  
516
#ifdef CONFIG_VNC_THREAD
517
static void vnc_abort_display_jobs(VncDisplay *vd)
518
{
519
    VncState *vs;
520

  
521
    QTAILQ_FOREACH(vs, &vd->clients, next) {
522
        vnc_lock_output(vs);
523
        vs->abort = true;
524
        vnc_unlock_output(vs);
525
    }
526
    QTAILQ_FOREACH(vs, &vd->clients, next) {
527
        vnc_jobs_join(vs);
528
    }
529
    QTAILQ_FOREACH(vs, &vd->clients, next) {
530
        vnc_lock_output(vs);
531
        vs->abort = false;
532
        vnc_unlock_output(vs);
533
    }
534
}
535
#else
536
static void vnc_abort_display_jobs(VncDisplay *vd)
537
{
538
}
539
#endif
540

  
513 541
static void vnc_dpy_resize(DisplayState *ds)
514 542
{
515 543
    VncDisplay *vd = ds->opaque;
516 544
    VncState *vs;
517 545

  
546
    vnc_abort_display_jobs(vd);
547

  
518 548
    /* server surface */
519 549
    if (!vd->server)
520 550
        vd->server = qemu_mallocz(sizeof(*vd->server));
......
642 672
    return 1;
643 673
}
644 674

  
645
static int send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
675
int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
646 676
{
647 677
    int n = 0;
648 678

  
......
671 701
static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
672 702
{
673 703
    /* send bitblit op to the vnc client */
704
    vnc_lock_output(vs);
674 705
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
675 706
    vnc_write_u8(vs, 0);
676 707
    vnc_write_u16(vs, 1); /* number of rects */
677 708
    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
678 709
    vnc_write_u16(vs, src_x);
679 710
    vnc_write_u16(vs, src_y);
711
    vnc_unlock_output(vs);
680 712
    vnc_flush(vs);
681 713
}
682 714

  
......
693 725
    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
694 726
        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
695 727
            vs->force_update = 1;
696
            vnc_update_client(vs, 1);
728
            vnc_update_client_sync(vs, 1);
697 729
            /* vs might be free()ed here */
698 730
        }
699 731
    }
......
813 845
    return h;
814 846
}
815 847

  
848
#ifdef CONFIG_VNC_THREAD
849
static int vnc_update_client_sync(VncState *vs, int has_dirty)
850
{
851
    int ret = vnc_update_client(vs, has_dirty);
852
    vnc_jobs_join(vs);
853
    return ret;
854
}
855
#else
856
static int vnc_update_client_sync(VncState *vs, int has_dirty)
857
{
858
    return vnc_update_client(vs, has_dirty);
859
}
860
#endif
861

  
816 862
static int vnc_update_client(VncState *vs, int has_dirty)
817 863
{
818 864
    if (vs->need_update && vs->csock != -1) {
819 865
        VncDisplay *vd = vs->vd;
866
        VncJob *job;
820 867
        int y;
821
        int n_rectangles;
822
        int saved_offset;
823 868
        int width, height;
824
        int n;
869
        int n = 0;
870

  
825 871

  
826 872
        if (vs->output.offset && !vs->audio_cap && !vs->force_update)
827 873
            /* kernel send buffers are full -> drop frames to throttle */
......
836 882
         * happening in parallel don't disturb us, the next pass will
837 883
         * send them to the client.
838 884
         */
839
        n_rectangles = 0;
840
        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
841
        vnc_write_u8(vs, 0);
842
        saved_offset = vs->output.offset;
843
        vnc_write_u16(vs, 0);
885
        job = vnc_job_new(vs);
844 886

  
845 887
        width = MIN(vd->server->width, vs->client_width);
846 888
        height = MIN(vd->server->height, vs->client_height);
......
857 899
                } else {
858 900
                    if (last_x != -1) {
859 901
                        int h = find_and_clear_dirty_height(vs, y, last_x, x);
860
                        n = send_framebuffer_update(vs, last_x * 16, y,
861
                                                    (x - last_x) * 16, h);
862
                        n_rectangles += n;
902

  
903
                        n += vnc_job_add_rect(job, last_x * 16, y,
904
                                              (x - last_x) * 16, h);
863 905
                    }
864 906
                    last_x = -1;
865 907
                }
866 908
            }
867 909
            if (last_x != -1) {
868 910
                int h = find_and_clear_dirty_height(vs, y, last_x, x);
869
                n = send_framebuffer_update(vs, last_x * 16, y,
870
                                            (x - last_x) * 16, h);
871
                n_rectangles += n;
911
                n += vnc_job_add_rect(job, last_x * 16, y,
912
                                      (x - last_x) * 16, h);
872 913
            }
873 914
        }
874
        vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
875
        vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
876
        vnc_flush(vs);
915

  
916
        vnc_job_push(job);
877 917
        vs->force_update = 0;
878
        return n_rectangles;
918
        return n;
879 919
    }
880 920

  
881 921
    if (vs->csock == -1)
......
891 931

  
892 932
    switch (cmd) {
893 933
    case AUD_CNOTIFY_DISABLE:
934
        vnc_lock_output(vs);
894 935
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
895 936
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
896 937
        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
938
        vnc_unlock_output(vs);
897 939
        vnc_flush(vs);
898 940
        break;
899 941

  
900 942
    case AUD_CNOTIFY_ENABLE:
943
        vnc_lock_output(vs);
901 944
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
902 945
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
903 946
        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
947
        vnc_unlock_output(vs);
904 948
        vnc_flush(vs);
905 949
        break;
906 950
    }
......
914 958
{
915 959
    VncState *vs = opaque;
916 960

  
961
    vnc_lock_output(vs);
917 962
    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
918 963
    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
919 964
    vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
920 965
    vnc_write_u32(vs, size);
921 966
    vnc_write(vs, buf, size);
967
    vnc_unlock_output(vs);
922 968
    vnc_flush(vs);
923 969
}
924 970

  
......
960 1006

  
961 1007
static void vnc_disconnect_finish(VncState *vs)
962 1008
{
1009
    vnc_jobs_join(vs); /* Wait encoding jobs */
1010

  
1011
    vnc_lock_output(vs);
963 1012
    vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED);
964 1013

  
965 1014
    buffer_free(&vs->input);
......
988 1037
    vnc_remove_timer(vs->vd);
989 1038
    if (vs->vd->lock_key_sync)
990 1039
        qemu_remove_led_event_handler(vs->led);
1040
    vnc_unlock_output(vs);
1041

  
1042
#ifdef CONFIG_VNC_THREAD
1043
    qemu_mutex_destroy(&vs->output_mutex);
1044
#endif
991 1045
    qemu_free(vs);
992 1046
}
993 1047

  
......
1107 1161
 * the client socket. Will delegate actual work according to whether
1108 1162
 * SASL SSF layers are enabled (thus requiring encryption calls)
1109 1163
 */
1110
void vnc_client_write(void *opaque)
1164
static void vnc_client_write_locked(void *opaque)
1111 1165
{
1112 1166
    VncState *vs = opaque;
1113 1167

  
......
1121 1175
        vnc_client_write_plain(vs);
1122 1176
}
1123 1177

  
1178
void vnc_client_write(void *opaque)
1179
{
1180
    VncState *vs = opaque;
1181

  
1182
    vnc_lock_output(vs);
1183
    if (vs->output.offset) {
1184
        vnc_client_write_locked(opaque);
1185
    } else {
1186
        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
1187
    }
1188
    vnc_unlock_output(vs);
1189
}
1190

  
1124 1191
void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
1125 1192
{
1126 1193
    vs->read_handler = func;
......
1272 1339

  
1273 1340
void vnc_flush(VncState *vs)
1274 1341
{
1275
    if (vs->csock != -1 && vs->output.offset)
1276
        vnc_client_write(vs);
1342
    vnc_lock_output(vs);
1343
    if (vs->csock != -1 && vs->output.offset) {
1344
        vnc_client_write_locked(vs);
1345
    }
1346
    vnc_unlock_output(vs);
1277 1347
}
1278 1348

  
1279 1349
uint8_t read_u8(uint8_t *data, size_t offset)
......
1308 1378
    int absolute = kbd_mouse_is_absolute();
1309 1379

  
1310 1380
    if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
1381
        vnc_lock_output(vs);
1311 1382
        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1312 1383
        vnc_write_u8(vs, 0);
1313 1384
        vnc_write_u16(vs, 1);
1314 1385
        vnc_framebuffer_update(vs, absolute, 0,
1315 1386
                               ds_get_width(vs->ds), ds_get_height(vs->ds),
1316 1387
                               VNC_ENCODING_POINTER_TYPE_CHANGE);
1388
        vnc_unlock_output(vs);
1317 1389
        vnc_flush(vs);
1318 1390
    }
1319 1391
    vs->absolute = absolute;
......
1617 1689

  
1618 1690
static void send_ext_key_event_ack(VncState *vs)
1619 1691
{
1692
    vnc_lock_output(vs);
1620 1693
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1621 1694
    vnc_write_u8(vs, 0);
1622 1695
    vnc_write_u16(vs, 1);
1623 1696
    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1624 1697
                           VNC_ENCODING_EXT_KEY_EVENT);
1698
    vnc_unlock_output(vs);
1625 1699
    vnc_flush(vs);
1626 1700
}
1627 1701

  
1628 1702
static void send_ext_audio_ack(VncState *vs)
1629 1703
{
1704
    vnc_lock_output(vs);
1630 1705
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1631 1706
    vnc_write_u8(vs, 0);
1632 1707
    vnc_write_u16(vs, 1);
1633 1708
    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1634 1709
                           VNC_ENCODING_AUDIO);
1710
    vnc_unlock_output(vs);
1635 1711
    vnc_flush(vs);
1636 1712
}
1637 1713

  
......
1794 1870
{
1795 1871
    if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
1796 1872
        /* Sending a WMVi message to notify the client*/
1873
        vnc_lock_output(vs);
1797 1874
        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1798 1875
        vnc_write_u8(vs, 0);
1799 1876
        vnc_write_u16(vs, 1); /* number of rects */
1800 1877
        vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), 
1801 1878
                               ds_get_height(vs->ds), VNC_ENCODING_WMVi);
1802 1879
        pixel_format_message(vs);
1880
        vnc_unlock_output(vs);
1803 1881
        vnc_flush(vs);
1804 1882
    } else {
1805 1883
        set_pixel_conversion(vs);
......
2227 2305

  
2228 2306
    vga_hw_update();
2229 2307

  
2308
    if (vnc_trylock_display(vd)) {
2309
        vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
2310
        qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) +
2311
                       vd->timer_interval);
2312
        return;
2313
    }
2314

  
2230 2315
    has_dirty = vnc_refresh_server_surface(vd);
2316
    vnc_unlock_display(vd);
2231 2317

  
2232 2318
    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
2233 2319
        rects += vnc_update_client(vs, has_dirty);
2234 2320
        /* vs might be free()ed here */
2235 2321
    }
2322

  
2236 2323
    /* vd->timer could be NULL now if the last client disconnected,
2237 2324
     * in this case don't update the timer */
2238 2325
    if (vd->timer == NULL)
......
2291 2378
    vs->as.fmt = AUD_FMT_S16;
2292 2379
    vs->as.endianness = 0;
2293 2380

  
2381
#ifdef CONFIG_VNC_THREAD
2382
    qemu_mutex_init(&vs->output_mutex);
2383
#endif
2384

  
2294 2385
    QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
2295 2386

  
2296 2387
    vga_hw_update();
......
2348 2439
    if (!vs->kbd_layout)
2349 2440
        exit(1);
2350 2441

  
2442
#ifdef CONFIG_VNC_THREAD
2443
    qemu_mutex_init(&vs->mutex);
2444
    vnc_start_worker_thread();
2445
#endif
2446

  
2351 2447
    dcl->dpy_copy = vnc_dpy_copy;
2352 2448
    dcl->dpy_update = vnc_dpy_update;
2353 2449
    dcl->dpy_resize = vnc_dpy_resize;
b/ui/vnc.h
29 29

  
30 30
#include "qemu-common.h"
31 31
#include "qemu-queue.h"
32
#ifdef CONFIG_VNC_THREAD
33
#include "qemu-thread.h"
34
#endif
32 35
#include "console.h"
33 36
#include "monitor.h"
34 37
#include "audio/audio.h"
......
59 62
} Buffer;
60 63

  
61 64
typedef struct VncState VncState;
65
typedef struct VncJob VncJob;
66
typedef struct VncRect VncRect;
67
typedef struct VncRectEntry VncRectEntry;
62 68

  
63 69
typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
64 70

  
......
101 107
    DisplayState *ds;
102 108
    kbd_layout_t *kbd_layout;
103 109
    int lock_key_sync;
110
#ifdef CONFIG_VNC_THREAD
111
    QemuMutex mutex;
112
#endif
104 113

  
105 114
    QEMUCursor *cursor;
106 115
    int cursor_msize;
......
152 161
    int level;
153 162
} VncZlib;
154 163

  
164
#ifdef CONFIG_VNC_THREAD
165
struct VncRect
166
{
167
    int x;
168
    int y;
169
    int w;
170
    int h;
171
};
172

  
173
struct VncRectEntry
174
{
175
    struct VncRect rect;
176
    QLIST_ENTRY(VncRectEntry) next;
177
};
178

  
179
struct VncJob
180
{
181
    VncState *vs;
182

  
183
    QLIST_HEAD(, VncRectEntry) rectangles;
184
    QTAILQ_ENTRY(VncJob) next;
185
};
186
#else
187
struct VncJob
188
{
189
    VncState *vs;
190
    int rectangles;
191
    size_t saved_offset;
192
};
193
#endif
194

  
155 195
struct VncState
156 196
{
157 197
    int csock;
......
199 239
    uint8_t modifiers_state[256];
200 240
    QEMUPutLEDEntry *led;
201 241

  
202
    /* Encoding specific */
242
    bool abort;
243
#ifndef CONFIG_VNC_THREAD
244
    VncJob job;
245
#else
246
    QemuMutex output_mutex;
247
#endif
248

  
249
    /* Encoding specific, if you add something here, don't forget to
250
     *  update vnc_async_encoding_start()
251
     */
203 252
    VncTight tight;
204 253
    VncZlib zlib;
205 254
    VncHextile hextile;
......
431 480
void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v);
432 481

  
433 482
/* Encodings */
483
int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
484

  
434 485
int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
435 486

  
436 487
int vnc_hextile_send_framebuffer_update(VncState *vs, int x,

Also available in: Unified diff