diff --git a/block/block-copy.c b/block/block-copy.c index 9b4af00614..c2e5090412 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -50,7 +50,7 @@ typedef struct BlockCopyCallState { /* State */ int ret; bool finished; - QemuCoSleepState *sleep_state; + QemuCoSleep sleep; bool cancelled; /* OUT parameters */ @@ -625,8 +625,8 @@ block_copy_dirty_clusters(BlockCopyCallState *call_state) if (ns > 0) { block_copy_task_end(task, -EAGAIN); g_free(task); - qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, ns, - &call_state->sleep_state); + qemu_co_sleep_ns_wakeable(&call_state->sleep, + QEMU_CLOCK_REALTIME, ns); continue; } } @@ -674,9 +674,7 @@ out: void block_copy_kick(BlockCopyCallState *call_state) { - if (call_state->sleep_state) { - qemu_co_sleep_wake(call_state->sleep_state); - } + qemu_co_sleep_wake(&call_state->sleep); } /* diff --git a/block/nbd.c b/block/nbd.c index 1d4668d42d..616f9ae6c4 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -116,7 +116,7 @@ typedef struct BDRVNBDState { CoQueue free_sema; Coroutine *connection_co; Coroutine *teardown_co; - QemuCoSleepState *connection_co_sleep_ns_state; + QemuCoSleep reconnect_sleep; bool drained; bool wait_drained_end; int in_flight; @@ -289,9 +289,7 @@ static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs) BDRVNBDState *s = (BDRVNBDState *)bs->opaque; s->drained = true; - if (s->connection_co_sleep_ns_state) { - qemu_co_sleep_wake(s->connection_co_sleep_ns_state); - } + qemu_co_sleep_wake(&s->reconnect_sleep); nbd_co_establish_connection_cancel(bs, false); @@ -330,9 +328,7 @@ static void nbd_teardown_connection(BlockDriverState *bs) s->state = NBD_CLIENT_QUIT; if (s->connection_co) { - if (s->connection_co_sleep_ns_state) { - qemu_co_sleep_wake(s->connection_co_sleep_ns_state); - } + qemu_co_sleep_wake(&s->reconnect_sleep); nbd_co_establish_connection_cancel(bs, true); } if (qemu_in_coroutine()) { @@ -689,8 +685,8 @@ static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s) } bdrv_inc_in_flight(s->bs); } else { - qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, timeout, - &s->connection_co_sleep_ns_state); + qemu_co_sleep_ns_wakeable(&s->reconnect_sleep, + QEMU_CLOCK_REALTIME, timeout); if (s->drained) { continue; } diff --git a/hw/remote/memory.c b/hw/remote/memory.c index 2d4174614a..472ed2a272 100644 --- a/hw/remote/memory.c +++ b/hw/remote/memory.c @@ -41,10 +41,9 @@ void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp) remote_sysmem_reset(); - for (region = 0; region < msg->num_fds; region++) { - g_autofree char *name; + for (region = 0; region < msg->num_fds; region++, suffix++) { + g_autofree char *name = g_strdup_printf("remote-mem-%u", suffix); subregion = g_new(MemoryRegion, 1); - name = g_strdup_printf("remote-mem-%u", suffix++); memory_region_init_ram_from_fd(subregion, NULL, name, sysmem_info->sizes[region], true, msg->fds[region], diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index 4fa4be079d..6dda705fc2 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -347,13 +347,12 @@ static void probe_pci_info(PCIDevice *dev, Error **errp) PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY; if (size) { - g_autofree char *name; + g_autofree char *name = g_strdup_printf("bar-region-%d", i); pdev->region[i].dev = pdev; pdev->region[i].present = true; if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) { pdev->region[i].memory = true; } - name = g_strdup_printf("bar-region-%d", i); memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev), &proxy_mr_ops, &pdev->region[i], name, size); diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index 3acbf3384c..a72f69fea8 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -140,7 +140,8 @@ static inline int test_bit(long nr, const unsigned long *addr) * @addr: The address to start the search at * @size: The maximum size to search * - * Returns the bit number of the first set bit, or size. + * Returns the bit number of the last set bit, + * or @size if there is no set bit in the bitmap. */ unsigned long find_last_bit(const unsigned long *addr, unsigned long size); @@ -150,6 +151,9 @@ unsigned long find_last_bit(const unsigned long *addr, * @addr: The address to base the search on * @offset: The bitnumber to start searching at * @size: The bitmap size in bits + * + * Returns the bit number of the next set bit, + * or @size if there are no further set bits in the bitmap. */ unsigned long find_next_bit(const unsigned long *addr, unsigned long size, @@ -160,6 +164,9 @@ unsigned long find_next_bit(const unsigned long *addr, * @addr: The address to base the search on * @offset: The bitnumber to start searching at * @size: The bitmap size in bits + * + * Returns the bit number of the next cleared bit, + * or @size if there are no further clear bits in the bitmap. */ unsigned long find_next_zero_bit(const unsigned long *addr, @@ -171,7 +178,8 @@ unsigned long find_next_zero_bit(const unsigned long *addr, * @addr: The address to start the search at * @size: The maximum size to search * - * Returns the bit number of the first set bit. + * Returns the bit number of the first set bit, + * or @size if there is no set bit in the bitmap. */ static inline unsigned long find_first_bit(const unsigned long *addr, unsigned long size) @@ -194,7 +202,8 @@ static inline unsigned long find_first_bit(const unsigned long *addr, * @addr: The address to start the search at * @size: The maximum size to search * - * Returns the bit number of the first cleared bit. + * Returns the bit number of the first cleared bit, + * or @size if there is no clear bit in the bitmap. */ static inline unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index ce5b9c6851..292e61aef0 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -291,20 +291,27 @@ void qemu_co_rwlock_wrlock(CoRwlock *lock); */ void qemu_co_rwlock_unlock(CoRwlock *lock); -typedef struct QemuCoSleepState QemuCoSleepState; +typedef struct QemuCoSleep { + Coroutine *to_wake; +} QemuCoSleep; /** - * Yield the coroutine for a given duration. During this yield, @sleep_state - * (if not NULL) is set to an opaque pointer, which may be used for - * qemu_co_sleep_wake(). Be careful, the pointer is set back to zero when the - * timer fires. Don't save the obtained value to other variables and don't call - * qemu_co_sleep_wake from another aio context. + * Yield the coroutine for a given duration. Initializes @w so that, + * during this yield, it can be passed to qemu_co_sleep_wake() to + * terminate the sleep. */ -void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns, - QemuCoSleepState **sleep_state); +void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w, + QEMUClockType type, int64_t ns); + +/** + * Yield the coroutine until the next call to qemu_co_sleep_wake. + */ +void coroutine_fn qemu_co_sleep(QemuCoSleep *w); + static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns) { - qemu_co_sleep_ns_wakeable(type, ns, NULL); + QemuCoSleep w = { 0 }; + qemu_co_sleep_ns_wakeable(&w, type, ns); } /** @@ -313,7 +320,7 @@ static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns) * qemu_co_sleep_ns() and should be checked to be non-NULL before calling * qemu_co_sleep_wake(). */ -void qemu_co_sleep_wake(QemuCoSleepState *sleep_state); +void qemu_co_sleep_wake(QemuCoSleep *w); /** * Yield until a file descriptor becomes readable diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c index 8c4dac4fd7..571ab521ff 100644 --- a/util/qemu-coroutine-sleep.c +++ b/util/qemu-coroutine-sleep.c @@ -19,43 +19,34 @@ static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns"; -struct QemuCoSleepState { - Coroutine *co; - QEMUTimer *ts; - QemuCoSleepState **user_state_pointer; -}; - -void qemu_co_sleep_wake(QemuCoSleepState *sleep_state) +void qemu_co_sleep_wake(QemuCoSleep *w) { - /* Write of schedule protected by barrier write in aio_co_schedule */ - const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled, - qemu_co_sleep_ns__scheduled, NULL); + Coroutine *co; - assert(scheduled == qemu_co_sleep_ns__scheduled); - if (sleep_state->user_state_pointer) { - *sleep_state->user_state_pointer = NULL; + co = w->to_wake; + w->to_wake = NULL; + if (co) { + /* Write of schedule protected by barrier write in aio_co_schedule */ + const char *scheduled = qatomic_cmpxchg(&co->scheduled, + qemu_co_sleep_ns__scheduled, NULL); + + assert(scheduled == qemu_co_sleep_ns__scheduled); + aio_co_wake(co); } - timer_del(sleep_state->ts); - aio_co_wake(sleep_state->co); } static void co_sleep_cb(void *opaque) { - qemu_co_sleep_wake(opaque); + QemuCoSleep *w = opaque; + qemu_co_sleep_wake(w); } -void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns, - QemuCoSleepState **sleep_state) +void coroutine_fn qemu_co_sleep(QemuCoSleep *w) { - AioContext *ctx = qemu_get_current_aio_context(); - QemuCoSleepState state = { - .co = qemu_coroutine_self(), - .ts = aio_timer_new(ctx, type, SCALE_NS, co_sleep_cb, &state), - .user_state_pointer = sleep_state, - }; + Coroutine *co = qemu_coroutine_self(); - const char *scheduled = qatomic_cmpxchg(&state.co->scheduled, NULL, - qemu_co_sleep_ns__scheduled); + const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL, + qemu_co_sleep_ns__scheduled); if (scheduled) { fprintf(stderr, "%s: Co-routine was already scheduled in '%s'\n", @@ -63,17 +54,27 @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns, abort(); } - if (sleep_state) { - *sleep_state = &state; - } - timer_mod(state.ts, qemu_clock_get_ns(type) + ns); + w->to_wake = co; qemu_coroutine_yield(); - if (sleep_state) { - /* - * Note that *sleep_state is cleared during qemu_co_sleep_wake - * before resuming this coroutine. - */ - assert(*sleep_state == NULL); - } - timer_free(state.ts); + + /* w->to_wake is cleared before resuming this coroutine. */ + assert(w->to_wake == NULL); +} + +void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w, + QEMUClockType type, int64_t ns) +{ + AioContext *ctx = qemu_get_current_aio_context(); + QEMUTimer ts; + + aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w); + timer_mod(&ts, qemu_clock_get_ns(type) + ns); + + /* + * The timer will fire in the current AiOContext, so the callback + * must happen after qemu_co_sleep yields and there is no race + * between timer_mod and qemu_co_sleep. + */ + qemu_co_sleep(w); + timer_del(&ts); }