X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=main-loop.c;h=c3c9c28fbab786e0c50a5d1882d155680f0d46b9;hb=607bb022f2a44797cbf40e85e84da4134e2f0e01;hp=8c9b58c14c897766313558bd8839d612fb5749c9;hpb=f708e736d0dafc05f8b7e9e73d6440c930b94686;p=qemu.git diff --git a/main-loop.c b/main-loop.c index 8c9b58c14..c3c9c28fb 100644 --- a/main-loop.c +++ b/main-loop.c @@ -24,7 +24,8 @@ #include "qemu-common.h" #include "qemu/timer.h" -#include "slirp/slirp.h" +#include "qemu/sockets.h" // struct in_addr needed for libslirp.h +#include "slirp/libslirp.h" #include "qemu/main-loop.h" #include "block/aio.h" @@ -109,6 +110,11 @@ static int qemu_signal_init(void) static AioContext *qemu_aio_context; +AioContext *qemu_get_aio_context(void) +{ + return qemu_aio_context; +} + void qemu_notify_event(void) { if (!qemu_aio_context) { @@ -125,10 +131,6 @@ int qemu_init_main_loop(void) GSource *src; init_clocks(); - if (init_timer_alarm() < 0) { - fprintf(stderr, "could not initialize alarm timer\n"); - exit(1); - } ret = qemu_signal_init(); if (ret) { @@ -149,10 +151,11 @@ static int max_priority; static int glib_pollfds_idx; static int glib_n_poll_fds; -static void glib_pollfds_fill(uint32_t *cur_timeout) +static void glib_pollfds_fill(int64_t *cur_timeout) { GMainContext *context = g_main_context_default(); int timeout = 0; + int64_t timeout_ns; int n; g_main_context_prepare(context, &max_priority); @@ -168,9 +171,13 @@ static void glib_pollfds_fill(uint32_t *cur_timeout) glib_n_poll_fds); } while (n != glib_n_poll_fds); - if (timeout >= 0 && timeout < *cur_timeout) { - *cur_timeout = timeout; + if (timeout < 0) { + timeout_ns = -1; + } else { + timeout_ns = (int64_t)timeout * (int64_t)SCALE_MS; } + + *cur_timeout = qemu_soonest_timeout(timeout_ns, *cur_timeout); } static void glib_pollfds_poll(void) @@ -183,19 +190,44 @@ static void glib_pollfds_poll(void) } } -static int os_host_main_loop_wait(uint32_t timeout) +#define MAX_MAIN_LOOP_SPIN (1000) + +static int os_host_main_loop_wait(int64_t timeout) { int ret; + static int spin_counter; glib_pollfds_fill(&timeout); - if (timeout > 0) { + /* If the I/O thread is very busy or we are incorrectly busy waiting in + * the I/O thread, this can lead to starvation of the BQL such that the + * VCPU threads never run. To make sure we can detect the later case, + * print a message to the screen. If we run into this condition, create + * a fake timeout in order to give the VCPU threads a chance to run. + */ + if (!timeout && (spin_counter > MAX_MAIN_LOOP_SPIN)) { + static bool notified; + + if (!notified) { + fprintf(stderr, + "main-loop: WARNING: I/O thread spun for %d iterations\n", + MAX_MAIN_LOOP_SPIN); + notified = true; + } + + timeout = SCALE_MS; + } + + if (timeout) { + spin_counter = 0; qemu_mutex_unlock_iothread(); + } else { + spin_counter++; } - ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout); + ret = qemu_poll_ns((GPollFD *)gpollfds->data, gpollfds->len, timeout); - if (timeout > 0) { + if (timeout) { qemu_mutex_lock_iothread(); } @@ -303,11 +335,11 @@ static int pollfds_fill(GArray *pollfds, fd_set *rfds, fd_set *wfds, GPollFD *pfd = &g_array_index(pollfds, GPollFD, i); int fd = pfd->fd; int events = pfd->events; - if (events & (G_IO_IN | G_IO_HUP | G_IO_ERR)) { + if (events & G_IO_IN) { FD_SET(fd, rfds); nfds = MAX(nfds, fd); } - if (events & (G_IO_OUT | G_IO_ERR)) { + if (events & G_IO_OUT) { FD_SET(fd, wfds); nfds = MAX(nfds, fd); } @@ -330,10 +362,10 @@ static void pollfds_poll(GArray *pollfds, int nfds, fd_set *rfds, int revents = 0; if (FD_ISSET(fd, rfds)) { - revents |= G_IO_IN | G_IO_HUP | G_IO_ERR; + revents |= G_IO_IN; } if (FD_ISSET(fd, wfds)) { - revents |= G_IO_OUT | G_IO_ERR; + revents |= G_IO_OUT; } if (FD_ISSET(fd, xfds)) { revents |= G_IO_PRI; @@ -342,7 +374,7 @@ static void pollfds_poll(GArray *pollfds, int nfds, fd_set *rfds, } } -static int os_host_main_loop_wait(uint32_t timeout) +static int os_host_main_loop_wait(int64_t timeout) { GMainContext *context = g_main_context_default(); GPollFD poll_fds[1024 * 2]; /* this is probably overkill */ @@ -351,6 +383,7 @@ static int os_host_main_loop_wait(uint32_t timeout) PollingEntry *pe; WaitObjects *w = &wait_objects; gint poll_timeout; + int64_t poll_timeout_ns; static struct timeval tv0; fd_set rfds, wfds, xfds; int nfds; @@ -364,6 +397,20 @@ static int os_host_main_loop_wait(uint32_t timeout) return ret; } + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + nfds = pollfds_fill(gpollfds, &rfds, &wfds, &xfds); + if (nfds >= 0) { + select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0); + if (select_ret != 0) { + timeout = 0; + } + if (select_ret > 0) { + pollfds_poll(gpollfds, nfds, &rfds, &wfds, &xfds); + } + } + g_main_context_prepare(context, &max_priority); n_poll_fds = g_main_context_query(context, max_priority, &poll_timeout, poll_fds, ARRAY_SIZE(poll_fds)); @@ -374,12 +421,17 @@ static int os_host_main_loop_wait(uint32_t timeout) poll_fds[n_poll_fds + i].events = G_IO_IN; } - if (poll_timeout < 0 || timeout < poll_timeout) { - poll_timeout = timeout; + if (poll_timeout < 0) { + poll_timeout_ns = -1; + } else { + poll_timeout_ns = (int64_t)poll_timeout * (int64_t)SCALE_MS; } + poll_timeout_ns = qemu_soonest_timeout(poll_timeout_ns, timeout); + qemu_mutex_unlock_iothread(); - g_poll_ret = g_poll(poll_fds, n_poll_fds + w->num, poll_timeout); + g_poll_ret = qemu_poll_ns(poll_fds, n_poll_fds + w->num, poll_timeout_ns); + qemu_mutex_lock_iothread(); if (g_poll_ret > 0) { for (i = 0; i < w->num; i++) { @@ -396,24 +448,6 @@ static int os_host_main_loop_wait(uint32_t timeout) g_main_context_dispatch(context); } - /* Call select after g_poll to avoid a useless iteration and therefore - * improve socket latency. - */ - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&xfds); - nfds = pollfds_fill(gpollfds, &rfds, &wfds, &xfds); - if (nfds >= 0) { - select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0); - if (select_ret != 0) { - timeout = 0; - } - if (select_ret > 0) { - pollfds_poll(gpollfds, nfds, &rfds, &wfds, &xfds); - } - } - return select_ret || g_poll_ret; } #endif @@ -422,6 +456,7 @@ int main_loop_wait(int nonblocking) { int ret; uint32_t timeout = UINT32_MAX; + int64_t timeout_ns; if (nonblocking) { timeout = 0; @@ -431,17 +466,27 @@ int main_loop_wait(int nonblocking) g_array_set_size(gpollfds, 0); /* reset for new iteration */ /* XXX: separate device handlers from system ones */ #ifdef CONFIG_SLIRP - slirp_update_timeout(&timeout); - slirp_pollfds_fill(gpollfds); + slirp_pollfds_fill(gpollfds, &timeout); #endif qemu_iohandler_fill(gpollfds); - ret = os_host_main_loop_wait(timeout); + + if (timeout == UINT32_MAX) { + timeout_ns = -1; + } else { + timeout_ns = (uint64_t)timeout * (int64_t)(SCALE_MS); + } + + timeout_ns = qemu_soonest_timeout(timeout_ns, + timerlistgroup_deadline_ns( + &main_loop_tlg)); + + ret = os_host_main_loop_wait(timeout_ns); qemu_iohandler_poll(gpollfds, ret); #ifdef CONFIG_SLIRP slirp_pollfds_poll(gpollfds, (ret < 0)); #endif - qemu_run_all_timers(); + qemu_clock_run_all_timers(); return ret; } @@ -462,17 +507,14 @@ bool qemu_aio_wait(void) void qemu_aio_set_fd_handler(int fd, IOHandler *io_read, IOHandler *io_write, - AioFlushHandler *io_flush, void *opaque) { - aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, io_flush, - opaque); + aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, opaque); } #endif void qemu_aio_set_event_notifier(EventNotifier *notifier, - EventNotifierHandler *io_read, - AioFlushEventNotifierHandler *io_flush) + EventNotifierHandler *io_read) { - aio_set_event_notifier(qemu_aio_context, notifier, io_read, io_flush); + aio_set_event_notifier(qemu_aio_context, notifier, io_read); }