diff options
-rw-r--r-- | block/file-posix.c | 50 | ||||
-rw-r--r-- | block/nbd-client.c | 12 | ||||
-rw-r--r-- | block/nbd-client.h | 2 | ||||
-rw-r--r-- | block/nbd.c | 2 | ||||
-rw-r--r-- | block/parallels.c | 3 | ||||
-rw-r--r-- | hw/9pfs/9p.c | 8 | ||||
-rw-r--r-- | hw/display/cirrus_vga_rop2.h | 4 | ||||
-rw-r--r-- | hw/input/virtio-input.c | 33 | ||||
-rw-r--r-- | hw/intc/apic_common.c | 33 | ||||
-rw-r--r-- | hw/scsi/scsi-generic.c | 5 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi-dataplane.c | 20 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 41 | ||||
-rw-r--r-- | include/hw/i386/apic_internal.h | 2 | ||||
-rw-r--r-- | include/hw/virtio/virtio-input.h | 5 | ||||
-rw-r--r-- | include/hw/virtio/virtio-scsi.h | 14 | ||||
-rw-r--r-- | include/qemu/thread-win32.h | 7 | ||||
-rw-r--r-- | memory.c | 10 | ||||
-rw-r--r-- | nbd/client.c | 2 | ||||
-rw-r--r-- | qemu-img.c | 196 | ||||
-rw-r--r-- | target/i386/translate.c | 7 | ||||
-rw-r--r-- | tests/virtio-9p-test.c | 4 | ||||
-rw-r--r-- | ui/egl-helpers.c | 58 | ||||
-rw-r--r-- | ui/vnc.c | 17 | ||||
-rw-r--r-- | util/oslib-posix.c | 16 | ||||
-rw-r--r-- | util/qemu-thread-win32.c | 136 |
25 files changed, 363 insertions, 324 deletions
diff --git a/block/file-posix.c b/block/file-posix.c index 53febd3767..0841a08785 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -144,6 +144,7 @@ typedef struct BDRVRawState { bool has_write_zeroes:1; bool discard_zeroes:1; bool use_linux_aio:1; + bool page_cache_inconsistent:1; bool has_fallocate; bool needs_alignment; } BDRVRawState; @@ -219,28 +220,28 @@ static int probe_logical_blocksize(int fd, unsigned int *sector_size_p) { unsigned int sector_size; bool success = false; + int i; errno = ENOTSUP; - - /* Try a few ioctls to get the right size */ + static const unsigned long ioctl_list[] = { #ifdef BLKSSZGET - if (ioctl(fd, BLKSSZGET, §or_size) >= 0) { - *sector_size_p = sector_size; - success = true; - } + BLKSSZGET, #endif #ifdef DKIOCGETBLOCKSIZE - if (ioctl(fd, DKIOCGETBLOCKSIZE, §or_size) >= 0) { - *sector_size_p = sector_size; - success = true; - } + DKIOCGETBLOCKSIZE, #endif #ifdef DIOCGSECTORSIZE - if (ioctl(fd, DIOCGSECTORSIZE, §or_size) >= 0) { - *sector_size_p = sector_size; - success = true; - } + DIOCGSECTORSIZE, #endif + }; + + /* Try a few ioctls to get the right size */ + for (i = 0; i < (int)ARRAY_SIZE(ioctl_list); i++) { + if (ioctl(fd, ioctl_list[i], §or_size) >= 0) { + *sector_size_p = sector_size; + success = true; + } + } return success ? 0 : -errno; } @@ -824,10 +825,31 @@ static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb) static ssize_t handle_aiocb_flush(RawPosixAIOData *aiocb) { + BDRVRawState *s = aiocb->bs->opaque; int ret; + if (s->page_cache_inconsistent) { + return -EIO; + } + ret = qemu_fdatasync(aiocb->aio_fildes); if (ret == -1) { + /* There is no clear definition of the semantics of a failing fsync(), + * so we may have to assume the worst. The sad truth is that this + * assumption is correct for Linux. Some pages are now probably marked + * clean in the page cache even though they are inconsistent with the + * on-disk contents. The next fdatasync() call would succeed, but no + * further writeback attempt will be made. We can't get back to a state + * in which we know what is on disk (we would have to rewrite + * everything that was touched since the last fdatasync() at least), so + * make bdrv_flush() fail permanently. Given that the behaviour isn't + * really defined, I have little hope that other OSes are doing better. + * + * Obviously, this doesn't affect O_DIRECT, which bypasses the page + * cache. */ + if ((s->open_flags & O_DIRECT) == 0) { + s->page_cache_inconsistent = true; + } return -errno; } return 0; diff --git a/block/nbd-client.c b/block/nbd-client.c index 0dc12c2d67..1e2952fdae 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -33,17 +33,15 @@ #define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs)) #define INDEX_TO_HANDLE(bs, index) ((index) ^ ((uint64_t)(intptr_t)bs)) -static void nbd_recv_coroutines_enter_all(BlockDriverState *bs) +static void nbd_recv_coroutines_enter_all(NBDClientSession *s) { - NBDClientSession *s = nbd_get_client_session(bs); int i; for (i = 0; i < MAX_NBD_REQUESTS; i++) { if (s->recv_coroutine[i]) { - qemu_coroutine_enter(s->recv_coroutine[i]); + aio_co_wake(s->recv_coroutine[i]); } } - BDRV_POLL_WHILE(bs, s->read_reply_co); } static void nbd_teardown_connection(BlockDriverState *bs) @@ -58,7 +56,7 @@ static void nbd_teardown_connection(BlockDriverState *bs) qio_channel_shutdown(client->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); - nbd_recv_coroutines_enter_all(bs); + BDRV_POLL_WHILE(bs, client->read_reply_co); nbd_client_detach_aio_context(bs); object_unref(OBJECT(client->sioc)); @@ -76,7 +74,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) for (;;) { assert(s->reply.handle == 0); ret = nbd_receive_reply(s->ioc, &s->reply); - if (ret < 0) { + if (ret <= 0) { break; } @@ -103,6 +101,8 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) aio_co_wake(s->recv_coroutine[i]); qemu_coroutine_yield(); } + + nbd_recv_coroutines_enter_all(s); s->read_reply_co = NULL; } diff --git a/block/nbd-client.h b/block/nbd-client.h index 8cdfc92e94..891ba44a20 100644 --- a/block/nbd-client.h +++ b/block/nbd-client.h @@ -30,8 +30,6 @@ typedef struct NBDClientSession { Coroutine *recv_coroutine[MAX_NBD_REQUESTS]; NBDReply reply; - - bool is_unix; } NBDClientSession; NBDClientSession *nbd_get_client_session(BlockDriverState *bs); diff --git a/block/nbd.c b/block/nbd.c index f478f80b4a..1b832c2132 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -285,8 +285,6 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, Error **errp) goto done; } - s->client.is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX; - done: QDECREF(addr); qobject_decref(crumpled_addr); diff --git a/block/parallels.c b/block/parallels.c index 6bf93753e8..4173b3fb9d 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -687,7 +687,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, if (local_err != NULL) { goto fail_options; } - if (!bdrv_has_zero_init(bs->file->bs) || + + if (!(flags & BDRV_O_RESIZE) || !bdrv_has_zero_init(bs->file->bs) || bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs)) != 0) { s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE; } diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index b8c0b99358..48babce836 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1550,6 +1550,10 @@ static void coroutine_fn v9fs_lcreate(void *opaque) err = -ENOENT; goto out_nofid; } + if (fidp->fid_type != P9_FID_NONE) { + err = -EINVAL; + goto out; + } flags = get_dotl_openflags(pdu->s, flags); err = v9fs_co_open2(pdu, fidp, &name, gid, @@ -2153,6 +2157,10 @@ static void coroutine_fn v9fs_create(void *opaque) err = -EINVAL; goto out_nofid; } + if (fidp->fid_type != P9_FID_NONE) { + err = -EINVAL; + goto out; + } if (perm & P9_STAT_MODE_DIR) { err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777, fidp->uid, -1, &stbuf); diff --git a/hw/display/cirrus_vga_rop2.h b/hw/display/cirrus_vga_rop2.h index b86bcd6e09..b208b7348a 100644 --- a/hw/display/cirrus_vga_rop2.h +++ b/hw/display/cirrus_vga_rop2.h @@ -29,8 +29,8 @@ #elif DEPTH == 24 #define PUTPIXEL(s, a, c) do { \ ROP_OP(s, a, c); \ - ROP_OP(s, a + 1, (col >> 8)); \ - ROP_OP(s, a + 2, (col >> 16)); \ + ROP_OP(s, a + 1, (c >> 8)); \ + ROP_OP(s, a + 2, (c >> 16)); \ } while (0) #elif DEPTH == 32 #define PUTPIXEL(s, a, c) ROP_OP_32(s, a, c) diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index b678ee9f20..0e42f0d02c 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -22,7 +22,6 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) { VirtQueueElement *elem; - unsigned have, need; int i, len; if (!vinput->active) { @@ -32,10 +31,10 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) /* queue up events ... */ if (vinput->qindex == vinput->qsize) { vinput->qsize++; - vinput->queue = realloc(vinput->queue, vinput->qsize * - sizeof(virtio_input_event)); + vinput->queue = g_realloc(vinput->queue, vinput->qsize * + sizeof(vinput->queue[0])); } - vinput->queue[vinput->qindex++] = *event; + vinput->queue[vinput->qindex++].event = *event; /* ... until we see a report sync ... */ if (event->type != cpu_to_le16(EV_SYN) || @@ -44,24 +43,24 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) } /* ... then check available space ... */ - need = sizeof(virtio_input_event) * vinput->qindex; - virtqueue_get_avail_bytes(vinput->evt, &have, NULL, need, 0); - if (have < need) { - vinput->qindex = 0; - trace_virtio_input_queue_full(); - return; - } - - /* ... and finally pass them to the guest */ for (i = 0; i < vinput->qindex; i++) { elem = virtqueue_pop(vinput->evt, sizeof(VirtQueueElement)); if (!elem) { - /* should not happen, we've checked for space beforehand */ - fprintf(stderr, "%s: Huh? No vq elem available ...\n", __func__); + while (--i >= 0) { + virtqueue_unpop(vinput->evt, vinput->queue[i].elem, 0); + } + vinput->qindex = 0; + trace_virtio_input_queue_full(); return; } + vinput->queue[i].elem = elem; + } + + /* ... and finally pass them to the guest */ + for (i = 0; i < vinput->qindex; i++) { + elem = vinput->queue[i].elem; len = iov_from_buf(elem->in_sg, elem->in_num, - 0, vinput->queue+i, sizeof(virtio_input_event)); + 0, &vinput->queue[i].event, sizeof(virtio_input_event)); virtqueue_push(vinput->evt, elem, len); g_free(elem); } @@ -272,6 +271,8 @@ static void virtio_input_finalize(Object *obj) QTAILQ_REMOVE(&vinput->cfg_list, cfg, node); g_free(cfg); } + + g_free(vinput->queue); } static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) { diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 7a6e771ed1..c3829e31b5 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -387,25 +387,6 @@ static bool apic_common_sipi_needed(void *opaque) return s->wait_for_sipi != 0; } -static bool apic_irq_delivered_needed(void *opaque) -{ - APICCommonState *s = APIC_COMMON(opaque); - return s->cpu == X86_CPU(first_cpu) && apic_irq_delivered != 0; -} - -static void apic_irq_delivered_pre_save(void *opaque) -{ - APICCommonState *s = APIC_COMMON(opaque); - s->apic_irq_delivered = apic_irq_delivered; -} - -static int apic_irq_delivered_post_load(void *opaque, int version_id) -{ - APICCommonState *s = APIC_COMMON(opaque); - apic_irq_delivered = s->apic_irq_delivered; - return 0; -} - static const VMStateDescription vmstate_apic_common_sipi = { .name = "apic_sipi", .version_id = 1, @@ -418,19 +399,6 @@ static const VMStateDescription vmstate_apic_common_sipi = { } }; -static const VMStateDescription vmstate_apic_irq_delivered = { - .name = "apic_irq_delivered", - .version_id = 1, - .minimum_version_id = 1, - .needed = apic_irq_delivered_needed, - .pre_save = apic_irq_delivered_pre_save, - .post_load = apic_irq_delivered_post_load, - .fields = (VMStateField[]) { - VMSTATE_INT32(apic_irq_delivered, APICCommonState), - VMSTATE_END_OF_LIST() - } -}; - static const VMStateDescription vmstate_apic_common = { .name = "apic", .version_id = 3, @@ -465,7 +433,6 @@ static const VMStateDescription vmstate_apic_common = { }, .subsections = (const VMStateDescription*[]) { &vmstate_apic_common_sipi, - &vmstate_apic_irq_delivered, NULL } }; diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 2933119e7d..a55ff87c22 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -237,9 +237,8 @@ static void scsi_read_complete(void * opaque, int ret) assert(max_transfer); stl_be_p(&r->buf[8], max_transfer); /* Also take care of the opt xfer len. */ - if (ldl_be_p(&r->buf[12]) > max_transfer) { - stl_be_p(&r->buf[12], max_transfer); - } + stl_be_p(&r->buf[12], + MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); } scsi_req_data(&r->req, len); scsi_req_unref(&r->req); diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 74c95e0e60..944ea4eb53 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -52,28 +52,40 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp) static bool virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) { - VirtIOSCSI *s = (VirtIOSCSI *)vdev; + bool progress; + VirtIOSCSI *s = VIRTIO_SCSI(vdev); + virtio_scsi_acquire(s); assert(s->ctx && s->dataplane_started); - return virtio_scsi_handle_cmd_vq(s, vq); + progress = virtio_scsi_handle_cmd_vq(s, vq); + virtio_scsi_release(s); + return progress; } static bool virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { + bool progress; VirtIOSCSI *s = VIRTIO_SCSI(vdev); + virtio_scsi_acquire(s); assert(s->ctx && s->dataplane_started); - return virtio_scsi_handle_ctrl_vq(s, vq); + progress = virtio_scsi_handle_ctrl_vq(s, vq); + virtio_scsi_release(s); + return progress; } static bool virtio_scsi_data_plane_handle_event(VirtIODevice *vdev, VirtQueue *vq) { + bool progress; VirtIOSCSI *s = VIRTIO_SCSI(vdev); + virtio_scsi_acquire(s); assert(s->ctx && s->dataplane_started); - return virtio_scsi_handle_event_vq(s, vq); + progress = virtio_scsi_handle_event_vq(s, vq); + virtio_scsi_release(s); + return progress; } static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n, diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 1dbc4bced9..bd62d08251 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -422,31 +422,15 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) } } -static inline void virtio_scsi_acquire(VirtIOSCSI *s) -{ - if (s->ctx) { - aio_context_acquire(s->ctx); - } -} - -static inline void virtio_scsi_release(VirtIOSCSI *s) -{ - if (s->ctx) { - aio_context_release(s->ctx); - } -} - bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req; bool progress = false; - virtio_scsi_acquire(s); while ((req = virtio_scsi_pop_req(s, vq))) { progress = true; virtio_scsi_handle_ctrl_req(s, req); } - virtio_scsi_release(s); return progress; } @@ -460,7 +444,9 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) return; } } + virtio_scsi_acquire(s); virtio_scsi_handle_ctrl_vq(s, vq); + virtio_scsi_release(s); } static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req) @@ -604,7 +590,6 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); - virtio_scsi_acquire(s); do { virtio_queue_set_notification(vq, 0); @@ -632,7 +617,6 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { virtio_scsi_handle_cmd_req_submit(s, req); } - virtio_scsi_release(s); return progress; } @@ -647,7 +631,9 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) return; } } + virtio_scsi_acquire(s); virtio_scsi_handle_cmd_vq(s, vq); + virtio_scsi_release(s); } static void virtio_scsi_get_config(VirtIODevice *vdev, @@ -723,12 +709,10 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, return; } - virtio_scsi_acquire(s); - req = virtio_scsi_pop_req(s, vs->event_vq); if (!req) { s->events_dropped = true; - goto out; + return; } if (s->events_dropped) { @@ -738,7 +722,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, if (virtio_scsi_parse_req(req, 0, sizeof(VirtIOSCSIEvent))) { virtio_scsi_bad_req(req); - goto out; + return; } evt = &req->resp.event; @@ -758,19 +742,14 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, evt->lun[3] = dev->lun & 0xFF; } virtio_scsi_complete_req(req); -out: - virtio_scsi_release(s); } bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq) { - virtio_scsi_acquire(s); if (s->events_dropped) { virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0); - virtio_scsi_release(s); return true; } - virtio_scsi_release(s); return false; } @@ -784,7 +763,9 @@ static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) return; } } + virtio_scsi_acquire(s); virtio_scsi_handle_event_vq(s, vq); + virtio_scsi_release(s); } static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense) @@ -794,8 +775,10 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense) if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) && dev->type != TYPE_ROM) { + virtio_scsi_acquire(s); virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE, sense.asc | (sense.ascq << 8)); + virtio_scsi_release(s); } } @@ -817,9 +800,11 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, } if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { + virtio_scsi_acquire(s); virtio_scsi_push_event(s, sd, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_RESCAN); + virtio_scsi_release(s); } } @@ -831,9 +816,11 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, SCSIDevice *sd = SCSI_DEVICE(dev); if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { + virtio_scsi_acquire(s); virtio_scsi_push_event(s, sd, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_REMOVED); + virtio_scsi_release(s); } qdev_simple_device_unplug_cb(hotplug_dev, dev, errp); diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index 20ad28c95b..1209eb483a 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -189,8 +189,6 @@ struct APICCommonState { DeviceState *vapic; hwaddr vapic_paddr; /* note: persistence via kvmvapic */ bool legacy_instance_id; - - int apic_irq_delivered; /* for saving static variable */ }; typedef struct VAPICState { diff --git a/include/hw/virtio/virtio-input.h b/include/hw/virtio/virtio-input.h index 55db31087a..91df57eca4 100644 --- a/include/hw/virtio/virtio-input.h +++ b/include/hw/virtio/virtio-input.h @@ -62,7 +62,10 @@ struct VirtIOInput { VirtQueue *evt, *sts; char *serial; - virtio_input_event *queue; + struct { + virtio_input_event event; + VirtQueueElement *elem; + } *queue; uint32_t qindex, qsize; bool active; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index f536f77e68..8ae0acaa1f 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -121,6 +121,20 @@ typedef struct VirtIOSCSIReq { } req; } VirtIOSCSIReq; +static inline void virtio_scsi_acquire(VirtIOSCSI *s) +{ + if (s->ctx) { + aio_context_acquire(s->ctx); + } +} + +static inline void virtio_scsi_release(VirtIOSCSI *s) +{ + if (s->ctx) { + aio_context_release(s->ctx); + } +} + void virtio_scsi_common_realize(DeviceState *dev, Error **errp, VirtIOHandleOutput ctrl, VirtIOHandleOutput evt, VirtIOHandleOutput cmd); diff --git a/include/qemu/thread-win32.h b/include/qemu/thread-win32.h index 5fb6541ae9..4c4a261cf4 100644 --- a/include/qemu/thread-win32.h +++ b/include/qemu/thread-win32.h @@ -4,8 +4,7 @@ #include <windows.h> struct QemuMutex { - CRITICAL_SECTION lock; - LONG owner; + SRWLOCK lock; }; typedef struct QemuRecMutex QemuRecMutex; @@ -19,9 +18,7 @@ int qemu_rec_mutex_trylock(QemuRecMutex *mutex); void qemu_rec_mutex_unlock(QemuRecMutex *mutex); struct QemuCond { - LONG waiters, target; - HANDLE sema; - HANDLE continue_event; + CONDITION_VARIABLE var; }; struct QemuSemaphore { @@ -906,12 +906,6 @@ void memory_region_transaction_begin(void) ++memory_region_transaction_depth; } -static void memory_region_clear_pending(void) -{ - memory_region_update_pending = false; - ioeventfd_update_pending = false; -} - void memory_region_transaction_commit(void) { AddressSpace *as; @@ -927,14 +921,14 @@ void memory_region_transaction_commit(void) QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { address_space_update_topology(as); } - + memory_region_update_pending = false; MEMORY_LISTENER_CALL_GLOBAL(commit, Forward); } else if (ioeventfd_update_pending) { QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { address_space_update_ioeventfds(as); } + ioeventfd_update_pending = false; } - memory_region_clear_pending(); } } diff --git a/nbd/client.c b/nbd/client.c index 3dc2564cd0..a58fb02cb4 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -812,6 +812,6 @@ ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply) LOG("invalid magic (got 0x%" PRIx32 ")", magic); return -EINVAL; } - return 0; + return sizeof(buf); } diff --git a/qemu-img.c b/qemu-img.c index 98b836b030..b220cf71d7 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -88,6 +88,16 @@ static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...) exit(EXIT_FAILURE); } +static void QEMU_NORETURN missing_argument(const char *option) +{ + error_exit("missing argument for option '%s'", option); +} + +static void QEMU_NORETURN unrecognized_option(const char *option) +{ + error_exit("unrecognized option '%s'", option); +} + /* Please keep in synch with qemu-img.texi */ static void QEMU_NORETURN help(void) { @@ -406,13 +416,18 @@ static int img_create(int argc, char **argv) {"object", required_argument, 0, OPTION_OBJECT}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "F:b:f:he6o:q", + c = getopt_long(argc, argv, ":F:b:f:he6o:q", long_options, NULL); if (c == -1) { break; } switch(c) { + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); break; @@ -651,13 +666,18 @@ static int img_check(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hf:r:T:q", + c = getopt_long(argc, argv, ":hf:r:T:q", long_options, &option_index); if (c == -1) { break; } switch(c) { + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); break; @@ -855,13 +875,18 @@ static int img_commit(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "f:ht:b:dpq", + c = getopt_long(argc, argv, ":f:ht:b:dpq", long_options, NULL); if (c == -1) { break; } switch(c) { + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); break; @@ -1190,13 +1215,18 @@ static int img_compare(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hf:F:T:pqs", + c = getopt_long(argc, argv, ":hf:F:T:pqs", long_options, NULL); if (c == -1) { break; } switch (c) { + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); break; @@ -1926,13 +1956,18 @@ static int img_convert(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hf:O:B:ce6o:s:l:S:pt:T:qnm:W", + c = getopt_long(argc, argv, ":hf:O:B:ce6o:s:l:S:pt:T:qnm:W", long_options, NULL); if (c == -1) { break; } switch(c) { + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); break; @@ -2502,13 +2537,18 @@ static int img_info(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "f:h", + c = getopt_long(argc, argv, ":f:h", long_options, &option_index); if (c == -1) { break; } switch(c) { + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); break; @@ -2713,13 +2753,18 @@ static int img_map(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "f:h", + c = getopt_long(argc, argv, ":f:h", long_options, &option_index); if (c == -1) { break; } switch (c) { + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); break; @@ -2835,13 +2880,18 @@ static int img_snapshot(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "la:c:d:hq", + c = getopt_long(argc, argv, ":la:c:d:hq", long_options, NULL); if (c == -1) { break; } switch(c) { + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); return 0; @@ -2988,13 +3038,18 @@ static int img_rebase(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hf:F:b:upt:T:q", + c = getopt_long(argc, argv, ":hf:F:b:upt:T:q", long_options, NULL); if (c == -1) { break; } switch(c) { + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); return 0; @@ -3355,13 +3410,18 @@ static int img_resize(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "f:hq", + c = getopt_long(argc, argv, ":f:hq", long_options, NULL); if (c == -1) { break; } switch(c) { + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); break; @@ -3493,54 +3553,59 @@ static int img_amend(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "ho:f:t:pq", + c = getopt_long(argc, argv, ":ho:f:t:pq", long_options, NULL); if (c == -1) { break; } switch (c) { - case 'h': - case '?': - help(); - break; - case 'o': - if (!is_valid_option_list(optarg)) { - error_report("Invalid option list: %s", optarg); - ret = -1; - goto out_no_progress; - } - if (!options) { - options = g_strdup(optarg); - } else { - char *old_options = options; - options = g_strdup_printf("%s,%s", options, optarg); - g_free(old_options); - } - break; - case 'f': - fmt = optarg; - break; - case 't': - cache = optarg; - break; - case 'p': - progress = true; - break; - case 'q': - quiet = true; - break; - case OPTION_OBJECT: - opts = qemu_opts_parse_noisily(&qemu_object_opts, - optarg, true); - if (!opts) { - ret = -1; - goto out_no_progress; - } - break; - case OPTION_IMAGE_OPTS: - image_opts = true; - break; + case ':': + missing_argument(argv[optind - 1]); + break; + case '?': + unrecognized_option(argv[optind - 1]); + break; + case 'h': + help(); + break; + case 'o': + if (!is_valid_option_list(optarg)) { + error_report("Invalid option list: %s", optarg); + ret = -1; + goto out_no_progress; + } + if (!options) { + options = g_strdup(optarg); + } else { + char *old_options = options; + options = g_strdup_printf("%s,%s", options, optarg); + g_free(old_options); + } + break; + case 'f': + fmt = optarg; + break; + case 't': + cache = optarg; + break; + case 'p': + progress = true; + break; + case 'q': + quiet = true; + break; + case OPTION_OBJECT: + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + ret = -1; + goto out_no_progress; + } + break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -3759,14 +3824,19 @@ static int img_bench(int argc, char **argv) {"no-drain", no_argument, 0, OPTION_NO_DRAIN}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hc:d:f:no:qs:S:t:w", long_options, NULL); + c = getopt_long(argc, argv, ":hc:d:f:no:qs:S:t:w", long_options, NULL); if (c == -1) { break; } switch (c) { - case 'h': + case ':': + missing_argument(argv[optind - 1]); + break; case '?': + unrecognized_option(argv[optind - 1]); + break; + case 'h': help(); break; case 'c': @@ -4093,7 +4163,7 @@ static int img_dd(int argc, char **argv) { 0, 0, 0, 0 } }; - while ((c = getopt_long(argc, argv, "hf:O:", long_options, NULL))) { + while ((c = getopt_long(argc, argv, ":hf:O:", long_options, NULL))) { if (c == EOF) { break; } @@ -4104,10 +4174,12 @@ static int img_dd(int argc, char **argv) case 'f': fmt = optarg; break; + case ':': + missing_argument(argv[optind - 1]); + break; case '?': - error_report("Try 'qemu-img --help' for more information."); - ret = -1; - goto out; + unrecognized_option(argv[optind - 1]); + break; case 'h': help(); break; @@ -4336,8 +4408,14 @@ int main(int argc, char **argv) qemu_add_opts(&qemu_source_opts); qemu_add_opts(&qemu_trace_opts); - while ((c = getopt_long(argc, argv, "+hVT:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "+:hVT:", long_options, NULL)) != -1) { switch (c) { + case ':': + missing_argument(argv[optind - 1]); + return 0; + case '?': + unrecognized_option(argv[optind - 1]); + return 0; case 'h': help(); return 0; diff --git a/target/i386/translate.c b/target/i386/translate.c index 72c1b03a2a..1d1372fb43 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -4418,6 +4418,13 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, s->vex_l = 0; s->vex_v = 0; next_byte: + /* x86 has an upper limit of 15 bytes for an instruction. Since we + * do not want to decode and generate IR for an illegal + * instruction, the following check limits the instruction size to + * 25 bytes: 14 prefix + 1 opc + 6 (modrm+sib+ofs) + 4 imm */ + if (s->pc - pc_start > 14) { + goto illegal_op; + } b = cpu_ldub_code(env, s->pc); s->pc++; /* Collect prefixes. */ diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 43a1ad813f..ad33d96387 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -256,8 +256,8 @@ static void v9fs_req_recv(P9Req *req, uint8_t id) qvirtio_wait_queue_isr(v9p->dev, v9p->vq, 1000 * 1000); v9fs_memread(req, &hdr, 7); - le32_to_cpus(&hdr.size); - le16_to_cpus(&hdr.tag); + hdr.size = ldl_le_p(&hdr.size); + hdr.tag = lduw_le_p(&hdr.tag); if (hdr.size >= 7) { break; } diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 584dd1b04d..b7b6b2e3cc 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -192,6 +192,56 @@ EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win) /* ---------------------------------------------------------------------- */ +/* + * Taken from glamor_egl.h from the Xorg xserver, which is MIT licensed + * + * Create an EGLDisplay from a native display type. This is a little quirky + * for a few reasons. + * + * 1: GetPlatformDisplayEXT and GetPlatformDisplay are the API you want to + * use, but have different function signatures in the third argument; this + * happens not to matter for us, at the moment, but it means epoxy won't alias + * them together. + * + * 2: epoxy 1.3 and earlier don't understand EGL client extensions, which + * means you can't call "eglGetPlatformDisplayEXT" directly, as the resolver + * will crash. + * + * 3: You can't tell whether you have EGL 1.5 at this point, because + * eglQueryString(EGL_VERSION) is a property of the display, which we don't + * have yet. So you have to query for extensions no matter what. Fortunately + * epoxy_has_egl_extension _does_ let you query for client extensions, so + * we don't have to write our own extension string parsing. + * + * 4. There is no EGL_KHR_platform_base to complement the EXT one, thus one + * needs to know EGL 1.5 is supported in order to use the eglGetPlatformDisplay + * function pointer. + * We can workaround this (circular dependency) by probing for the EGL 1.5 + * platform extensions (EGL_KHR_platform_gbm and friends) yet it doesn't seem + * like mesa will be able to advertise these (even though it can do EGL 1.5). + */ +static EGLDisplay qemu_egl_get_display(void *native) +{ + EGLDisplay dpy = EGL_NO_DISPLAY; + +#ifdef EGL_MESA_platform_gbm + /* In practise any EGL 1.5 implementation would support the EXT extension */ + if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) { + PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT = + (void *) eglGetProcAddress("eglGetPlatformDisplayEXT"); + if (getPlatformDisplayEXT) { + dpy = getPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, native, NULL); + } + } +#endif + + if (dpy == EGL_NO_DISPLAY) { + /* fallback */ + dpy = eglGetDisplay(native); + } + return dpy; +} + int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug) { static const EGLint conf_att_gl[] = { @@ -222,12 +272,8 @@ int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug) setenv("LIBGL_DEBUG", "verbose", true); } - egl_dbg("eglGetDisplay (dpy %p) ...\n", dpy); -#ifdef EGL_MESA_platform_gbm - qemu_egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, dpy, NULL); -#else - qemu_egl_display = eglGetDisplay(dpy); -#endif + egl_dbg("qemu_egl_get_display (dpy %p) ...\n", dpy); + qemu_egl_display = qemu_egl_get_display(dpy); if (qemu_egl_display == EGL_NO_DISPLAY) { error_report("egl: eglGetDisplay failed"); return -1; @@ -3401,6 +3401,7 @@ vnc_display_create_creds(bool x509, static int vnc_display_get_address(const char *addrstr, bool websocket, + bool reverse, int displaynum, int to, bool has_ipv4, @@ -3480,21 +3481,22 @@ static int vnc_display_get_address(const char *addrstr, inet->port = g_strdup(port); } } else { + int offset = reverse ? 0 : 5900; if (parse_uint_full(port, &baseport, 10) < 0) { error_setg(errp, "can't convert to a number: %s", port); goto cleanup; } if (baseport > 65535 || - baseport + 5900 > 65535) { + baseport + offset > 65535) { error_setg(errp, "port %s out of range", port); goto cleanup; } inet->port = g_strdup_printf( - "%d", (int)baseport + 5900); + "%d", (int)baseport + offset); if (to) { inet->has_to = true; - inet->to = to + 5900; + inet->to = to + offset; } } @@ -3516,6 +3518,7 @@ static int vnc_display_get_address(const char *addrstr, } static int vnc_display_get_addresses(QemuOpts *opts, + bool reverse, SocketAddress ***retsaddr, size_t *retnsaddr, SocketAddress ***retwsaddr, @@ -3555,7 +3558,7 @@ static int vnc_display_get_addresses(QemuOpts *opts, qemu_opt_iter_init(&addriter, opts, "vnc"); while ((addr = qemu_opt_iter_next(&addriter)) != NULL) { int rv; - rv = vnc_display_get_address(addr, false, 0, to, + rv = vnc_display_get_address(addr, false, reverse, 0, to, has_ipv4, has_ipv6, ipv4, ipv6, &saddr, errp); @@ -3580,7 +3583,7 @@ static int vnc_display_get_addresses(QemuOpts *opts, qemu_opt_iter_init(&addriter, opts, "websocket"); while ((addr = qemu_opt_iter_next(&addriter)) != NULL) { - if (vnc_display_get_address(addr, true, displaynum, to, + if (vnc_display_get_address(addr, true, reverse, displaynum, to, has_ipv4, has_ipv6, ipv4, ipv6, &wsaddr, errp) < 0) { @@ -3777,7 +3780,8 @@ void vnc_display_open(const char *id, Error **errp) return; } - if (vnc_display_get_addresses(opts, &saddr, &nsaddr, + reverse = qemu_opt_get_bool(opts, "reverse", false); + if (vnc_display_get_addresses(opts, reverse, &saddr, &nsaddr, &wsaddr, &nwsaddr, errp) < 0) { goto fail; } @@ -3803,7 +3807,6 @@ void vnc_display_open(const char *id, Error **errp) } } - reverse = qemu_opt_get_bool(opts, "reverse", false); lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true); key_delay_ms = qemu_opt_get_number(opts, "key-delay-ms", 1); sasl = qemu_opt_get_bool(opts, "sasl", false); diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 3fe6089c3e..4d9189e9ef 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -55,7 +55,7 @@ #include "qemu/error-report.h" #endif -#define MAX_MEM_PREALLOC_THREAD_COUNT (MIN(sysconf(_SC_NPROCESSORS_ONLN), 16)) +#define MAX_MEM_PREALLOC_THREAD_COUNT 16 struct MemsetThread { char *addr; @@ -381,6 +381,18 @@ static void *do_touch_pages(void *arg) return NULL; } +static inline int get_memset_num_threads(int smp_cpus) +{ + long host_procs = sysconf(_SC_NPROCESSORS_ONLN); + int ret = 1; + + if (host_procs > 0) { + ret = MIN(MIN(host_procs, MAX_MEM_PREALLOC_THREAD_COUNT), smp_cpus); + } + /* In case sysconf() fails, we fall back to single threaded */ + return ret; +} + static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, int smp_cpus) { @@ -389,7 +401,7 @@ static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, int i = 0; memset_thread_failed = false; - memset_num_threads = MIN(smp_cpus, MAX_MEM_PREALLOC_THREAD_COUNT); + memset_num_threads = get_memset_num_threads(smp_cpus); memset_thread = g_new0(MemsetThread, memset_num_threads); numpages_per_thread = (numpages / memset_num_threads); size_per_thread = (hpagesize * numpages_per_thread); diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c index 29c3e4dd85..59befd5202 100644 --- a/util/qemu-thread-win32.c +++ b/util/qemu-thread-win32.c @@ -10,6 +10,11 @@ * See the COPYING file in the top-level directory. * */ + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#endif + #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/thread.h" @@ -39,44 +44,30 @@ static void error_exit(int err, const char *msg) void qemu_mutex_init(QemuMutex *mutex) { - mutex->owner = 0; - InitializeCriticalSection(&mutex->lock); + InitializeSRWLock(&mutex->lock); } void qemu_mutex_destroy(QemuMutex *mutex) { - assert(mutex->owner == 0); - DeleteCriticalSection(&mutex->lock); + InitializeSRWLock(&mutex->lock); } void qemu_mutex_lock(QemuMutex *mutex) { - EnterCriticalSection(&mutex->lock); - - /* Win32 CRITICAL_SECTIONs are recursive. Assert that we're not - * using them as such. - */ - assert(mutex->owner == 0); - mutex->owner = GetCurrentThreadId(); + AcquireSRWLockExclusive(&mutex->lock); } int qemu_mutex_trylock(QemuMutex *mutex) { int owned; - owned = TryEnterCriticalSection(&mutex->lock); - if (owned) { - assert(mutex->owner == 0); - mutex->owner = GetCurrentThreadId(); - } + owned = TryAcquireSRWLockExclusive(&mutex->lock); return !owned; } void qemu_mutex_unlock(QemuMutex *mutex) { - assert(mutex->owner == GetCurrentThreadId()); - mutex->owner = 0; - LeaveCriticalSection(&mutex->lock); + ReleaseSRWLockExclusive(&mutex->lock); } void qemu_rec_mutex_init(QemuRecMutex *mutex) @@ -107,124 +98,27 @@ void qemu_rec_mutex_unlock(QemuRecMutex *mutex) void qemu_cond_init(QemuCond *cond) { memset(cond, 0, sizeof(*cond)); - - cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL); - if (!cond->sema) { - error_exit(GetLastError(), __func__); - } - cond->continue_event = CreateEvent(NULL, /* security */ - FALSE, /* auto-reset */ - FALSE, /* not signaled */ - NULL); /* name */ - if (!cond->continue_event) { - error_exit(GetLastError(), __func__); - } + InitializeConditionVariable(&cond->var); } void qemu_cond_destroy(QemuCond *cond) { - BOOL result; - result = CloseHandle(cond->continue_event); - if (!result) { - error_exit(GetLastError(), __func__); - } - cond->continue_event = 0; - result = CloseHandle(cond->sema); - if (!result) { - error_exit(GetLastError(), __func__); - } - cond->sema = 0; + InitializeConditionVariable(&cond->var); } void qemu_cond_signal(QemuCond *cond) { - DWORD result; - - /* - * Signal only when there are waiters. cond->waiters is - * incremented by pthread_cond_wait under the external lock, - * so we are safe about that. - */ - if (cond->waiters == 0) { - return; - } - - /* - * Waiting threads decrement it outside the external lock, but - * only if another thread is executing pthread_cond_broadcast and - * has the mutex. So, it also cannot be decremented concurrently - * with this particular access. - */ - cond->target = cond->waiters - 1; - result = SignalObjectAndWait(cond->sema, cond->continue_event, - INFINITE, FALSE); - if (result == WAIT_ABANDONED || result == WAIT_FAILED) { - error_exit(GetLastError(), __func__); - } + WakeConditionVariable(&cond->var); } void qemu_cond_broadcast(QemuCond *cond) { - BOOLEAN result; - /* - * As in pthread_cond_signal, access to cond->waiters and - * cond->target is locked via the external mutex. - */ - if (cond->waiters == 0) { - return; - } - - cond->target = 0; - result = ReleaseSemaphore(cond->sema, cond->waiters, NULL); - if (!result) { - error_exit(GetLastError(), __func__); - } - - /* - * At this point all waiters continue. Each one takes its - * slice of the semaphore. Now it's our turn to wait: Since - * the external mutex is held, no thread can leave cond_wait, - * yet. For this reason, we can be sure that no thread gets - * a chance to eat *more* than one slice. OTOH, it means - * that the last waiter must send us a wake-up. - */ - WaitForSingleObject(cond->continue_event, INFINITE); + WakeAllConditionVariable(&cond->var); } void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex) { - /* - * This access is protected under the mutex. - */ - cond->waiters++; - - /* - * Unlock external mutex and wait for signal. - * NOTE: we've held mutex locked long enough to increment - * waiters count above, so there's no problem with - * leaving mutex unlocked before we wait on semaphore. - */ - qemu_mutex_unlock(mutex); - WaitForSingleObject(cond->sema, INFINITE); - - /* Now waiters must rendez-vous with the signaling thread and - * let it continue. For cond_broadcast this has heavy contention - * and triggers thundering herd. So goes life. - * - * Decrease waiters count. The mutex is not taken, so we have - * to do this atomically. - * - * All waiters contend for the mutex at the end of this function - * until the signaling thread relinquishes it. To ensure - * each waiter consumes exactly one slice of the semaphore, - * the signaling thread stops until it is told by the last - * waiter that it can go on. - */ - if (InterlockedDecrement(&cond->waiters) == cond->target) { - SetEvent(cond->continue_event); - } - - qemu_mutex_lock(mutex); + SleepConditionVariableSRW(&cond->var, &mutex->lock, INFINITE, 0); } void qemu_sem_init(QemuSemaphore *sem, int init) |