HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
bool progress;
int count;
+ int timeout;
progress = false;
/*
* If there are callbacks left that have been queued, we need to call then.
* Do not call select in this case, because it is possible that the caller
- * does not need a complete flush (as is the case for qemu_aio_wait loops).
+ * does not need a complete flush (as is the case for aio_poll loops).
*/
if (aio_bh_poll(ctx)) {
blocking = false;
progress = true;
}
+ /* Run timers */
+ progress |= timerlistgroup_run_timers(&ctx->tlg);
+
/*
* Then dispatch any pending callbacks from the GSource.
*
- * We have to walk very carefully in case qemu_aio_set_fd_handler is
+ * We have to walk very carefully in case aio_set_fd_handler is
* called while we're walking.
*/
node = QLIST_FIRST(&ctx->aio_handlers);
node->io_notify(node->e);
/* aio_notify() does not count as progress */
- if (node->opaque != &ctx->notifier) {
+ if (node->e != &ctx->notifier) {
progress = true;
}
}
ctx->walking_handlers--;
- /* early return if we only have the aio_notify() fd */
- if (count == 1) {
- return progress;
- }
-
/* wait until next event */
while (count > 0) {
- int timeout = blocking ? INFINITE : 0;
- int ret = WaitForMultipleObjects(count, events, FALSE, timeout);
+ int ret;
+
+ timeout = blocking ?
+ qemu_timeout_ns_to_ms(timerlistgroup_deadline_ns(&ctx->tlg)) : 0;
+ ret = WaitForMultipleObjects(count, events, FALSE, timeout);
/* if we have any signaled events, dispatch event */
if ((DWORD) (ret - WAIT_OBJECT_0) >= count) {
blocking = false;
/* we have to walk very carefully in case
- * qemu_aio_set_fd_handler is called while we're walking */
+ * aio_set_fd_handler is called while we're walking */
node = QLIST_FIRST(&ctx->aio_handlers);
while (node) {
AioHandler *tmp;
node->io_notify(node->e);
/* aio_notify() does not count as progress */
- if (node->opaque != &ctx->notifier) {
+ if (node->e != &ctx->notifier) {
progress = true;
}
}
events[ret - WAIT_OBJECT_0] = events[--count];
}
+ if (blocking) {
+ /* Run the timers a second time. We do this because otherwise aio_wait
+ * will not note progress - and will stop a drain early - if we have
+ * a timer that was not ready to run entering g_poll but is ready
+ * after g_poll. This will only do anything if a timer has expired.
+ */
+ progress |= timerlistgroup_run_timers(&ctx->tlg);
+ }
+
return progress;
}