Revision bd023f95 ui/vnc.c

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;

Also available in: Unified diff