From 172061a0a0d98c974ea8d5ed715195237bc44225 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 29 Oct 2012 15:28:36 +0100 Subject: main-loop: unify qemu_init_main_loop between QEMU and tools Signed-off-by: Paolo Bonzini --- main-loop.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index eb3b6e6..baefe41 100644 --- a/main-loop.c +++ b/main-loop.c @@ -199,10 +199,13 @@ static int qemu_signal_init(void) } #endif -int main_loop_init(void) +int qemu_init_main_loop(void) { int ret; + init_clocks(); + init_timer_alarm(); + qemu_mutex_lock_iothread(); ret = qemu_signal_init(); if (ret) { -- cgit v1.1 From f627aab1ccea119fd94ca9e9df120cea6aab0c67 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 29 Oct 2012 23:45:23 +0100 Subject: aio: introduce AioContext, move bottom halves there Start introducing AioContext, which will let us remove globals from aio.c/async.c, and introduce multiple I/O threads. The bottom half functions now take an additional AioContext argument. A bottom half is created with a specific AioContext that remains the same throughout the lifetime. qemu_bh_new is just a wrapper that uses a global context. Signed-off-by: Paolo Bonzini --- main-loop.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index baefe41..40fdbd3 100644 --- a/main-loop.c +++ b/main-loop.c @@ -26,6 +26,7 @@ #include "qemu-timer.h" #include "slirp/slirp.h" #include "main-loop.h" +#include "qemu-aio.h" #ifndef _WIN32 @@ -199,6 +200,8 @@ static int qemu_signal_init(void) } #endif +static AioContext *qemu_aio_context; + int qemu_init_main_loop(void) { int ret; @@ -218,6 +221,7 @@ int qemu_init_main_loop(void) return ret; } + qemu_aio_context = aio_context_new(); return 0; } @@ -481,7 +485,7 @@ int main_loop_wait(int nonblocking) if (nonblocking) { timeout = 0; } else { - qemu_bh_update_timeout(&timeout); + aio_bh_update_timeout(qemu_aio_context, &timeout); } /* poll any events */ @@ -510,3 +514,15 @@ int main_loop_wait(int nonblocking) return ret; } + +/* Functions to operate on the main QEMU AioContext. */ + +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) +{ + return aio_bh_new(qemu_aio_context, cb, opaque); +} + +int qemu_bh_poll(void) +{ + return aio_bh_poll(qemu_aio_context); +} -- cgit v1.1 From a915f4bc977c4f3aab08a78023c1303664d1c606 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Sep 2012 12:28:51 +0200 Subject: aio: add I/O handlers to the AioContext interface With this patch, I/O handlers (including event notifier handlers) can be attached to a single AioContext. Signed-off-by: Paolo Bonzini --- main-loop.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index 40fdbd3..8f0117e 100644 --- a/main-loop.c +++ b/main-loop.c @@ -526,3 +526,36 @@ int qemu_bh_poll(void) { return aio_bh_poll(qemu_aio_context); } + +void qemu_aio_flush(void) +{ + aio_flush(qemu_aio_context); +} + +bool qemu_aio_wait(void) +{ + return aio_wait(qemu_aio_context); +} + +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); + + qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque); +} + +#ifdef CONFIG_POSIX +void qemu_aio_set_event_notifier(EventNotifier *notifier, + EventNotifierHandler *io_read, + AioFlushEventNotifierHandler *io_flush) +{ + qemu_aio_set_fd_handler(event_notifier_get_fd(notifier), + (IOHandler *)io_read, NULL, + (AioFlushHandler *)io_flush, notifier); +} +#endif -- cgit v1.1 From 7c0628b20e7c56b7e04abb8b5f8d7da3f7cb87e8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 24 Sep 2012 14:37:53 +0200 Subject: aio: add non-blocking variant of aio_wait This will be used when polling the GSource attached to an AioContext. Reviewed-by: Anthony Liguori Signed-off-by: Paolo Bonzini --- main-loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index 8f0117e..1fdc3bd 100644 --- a/main-loop.c +++ b/main-loop.c @@ -534,7 +534,7 @@ void qemu_aio_flush(void) bool qemu_aio_wait(void) { - return aio_wait(qemu_aio_context); + return aio_poll(qemu_aio_context, true); } void qemu_aio_set_fd_handler(int fd, -- cgit v1.1 From f42b22077bc63a482d7a8755b54e33475ab78541 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 9 Jun 2012 04:01:51 +0200 Subject: aio: add Win32 implementation The Win32 implementation will only accept EventNotifiers, thus a few drivers are disabled under Windows. EventNotifiers are a good match for the GSource implementation, too, because the Win32 port of glib allows to place their HANDLEs in a GPollFD. Signed-off-by: Paolo Bonzini --- main-loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index 1fdc3bd..a86c275 100644 --- a/main-loop.c +++ b/main-loop.c @@ -537,6 +537,7 @@ bool qemu_aio_wait(void) return aio_poll(qemu_aio_context, true); } +#ifdef CONFIG_POSIX void qemu_aio_set_fd_handler(int fd, IOHandler *io_read, IOHandler *io_write, @@ -549,7 +550,6 @@ void qemu_aio_set_fd_handler(int fd, qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque); } -#ifdef CONFIG_POSIX void qemu_aio_set_event_notifier(EventNotifier *notifier, EventNotifierHandler *io_read, AioFlushEventNotifierHandler *io_flush) -- cgit v1.1 From 82cbbdc6a0958b49c77639a60906e30d02e6bb7b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 24 Sep 2012 15:07:08 +0200 Subject: main-loop: use GSource to poll AIO file descriptors This lets us remove the hooks for the main loop in async.c. Reviewed-by: Anthony Liguori Signed-off-by: Paolo Bonzini --- main-loop.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index a86c275..365c9d3 100644 --- a/main-loop.c +++ b/main-loop.c @@ -205,6 +205,7 @@ static AioContext *qemu_aio_context; int qemu_init_main_loop(void) { int ret; + GSource *src; init_clocks(); init_timer_alarm(); @@ -222,6 +223,9 @@ int qemu_init_main_loop(void) } qemu_aio_context = aio_context_new(); + src = aio_get_g_source(qemu_aio_context); + g_source_attach(src, NULL); + g_source_unref(src); return 0; } @@ -484,8 +488,6 @@ int main_loop_wait(int nonblocking) if (nonblocking) { timeout = 0; - } else { - aio_bh_update_timeout(qemu_aio_context, &timeout); } /* poll any events */ @@ -508,10 +510,6 @@ int main_loop_wait(int nonblocking) qemu_run_all_timers(); - /* Check bottom-halves last in case any of the earlier events triggered - them. */ - qemu_bh_poll(); - return ret; } @@ -522,11 +520,6 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) return aio_bh_new(qemu_aio_context, cb, opaque); } -int qemu_bh_poll(void) -{ - return aio_bh_poll(qemu_aio_context); -} - void qemu_aio_flush(void) { aio_flush(qemu_aio_context); @@ -546,16 +539,12 @@ void qemu_aio_set_fd_handler(int fd, { aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, io_flush, opaque); - - qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque); } +#endif void qemu_aio_set_event_notifier(EventNotifier *notifier, EventNotifierHandler *io_read, AioFlushEventNotifierHandler *io_flush) { - qemu_aio_set_fd_handler(event_notifier_get_fd(notifier), - (IOHandler *)io_read, NULL, - (AioFlushHandler *)io_flush, notifier); + aio_set_event_notifier(qemu_aio_context, notifier, io_read, io_flush); } -#endif -- cgit v1.1 From 4c8d0d27676778febad3802a95218d5ceaca171e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 24 May 2010 17:27:14 +0200 Subject: main-loop: use aio_notify for qemu_notify_event Reviewed-by: Anthony Liguori Signed-off-by: Paolo Bonzini --- main-loop.c | 106 +++++------------------------------------------------------- 1 file changed, 8 insertions(+), 98 deletions(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index 365c9d3..e43c7c8 100644 --- a/main-loop.c +++ b/main-loop.c @@ -32,70 +32,6 @@ #include "compatfd.h" -static int io_thread_fd = -1; - -void qemu_notify_event(void) -{ - /* Write 8 bytes to be compatible with eventfd. */ - static const uint64_t val = 1; - ssize_t ret; - - if (io_thread_fd == -1) { - return; - } - do { - ret = write(io_thread_fd, &val, sizeof(val)); - } while (ret < 0 && errno == EINTR); - - /* EAGAIN is fine, a read must be pending. */ - if (ret < 0 && errno != EAGAIN) { - fprintf(stderr, "qemu_notify_event: write() failed: %s\n", - strerror(errno)); - exit(1); - } -} - -static void qemu_event_read(void *opaque) -{ - int fd = (intptr_t)opaque; - ssize_t len; - char buffer[512]; - - /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */ - do { - len = read(fd, buffer, sizeof(buffer)); - } while ((len == -1 && errno == EINTR) || len == sizeof(buffer)); -} - -static int qemu_event_init(void) -{ - int err; - int fds[2]; - - err = qemu_eventfd(fds); - if (err == -1) { - return -errno; - } - err = fcntl_setfl(fds[0], O_NONBLOCK); - if (err < 0) { - goto fail; - } - err = fcntl_setfl(fds[1], O_NONBLOCK); - if (err < 0) { - goto fail; - } - qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL, - (void *)(intptr_t)fds[0]); - - io_thread_fd = fds[1]; - return 0; - -fail: - close(fds[0]); - close(fds[1]); - return err; -} - /* If we have signalfd, we mask out the signals we want to handle and then * use signalfd to listen for them. We rely on whatever the current signal * handler is to dispatch the signals when we receive them. @@ -165,43 +101,22 @@ static int qemu_signal_init(void) #else /* _WIN32 */ -static HANDLE qemu_event_handle = NULL; - -static void dummy_event_handler(void *opaque) -{ -} - -static int qemu_event_init(void) +static int qemu_signal_init(void) { - qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!qemu_event_handle) { - fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError()); - return -1; - } - qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL); return 0; } +#endif + +static AioContext *qemu_aio_context; void qemu_notify_event(void) { - if (!qemu_event_handle) { + if (!qemu_aio_context) { return; } - if (!SetEvent(qemu_event_handle)) { - fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n", - GetLastError()); - exit(1); - } + aio_notify(qemu_aio_context); } -static int qemu_signal_init(void) -{ - return 0; -} -#endif - -static AioContext *qemu_aio_context; - int qemu_init_main_loop(void) { int ret; @@ -216,12 +131,6 @@ int qemu_init_main_loop(void) return ret; } - /* Note eventfd must be drained before signalfd handlers run */ - ret = qemu_event_init(); - if (ret) { - return ret; - } - qemu_aio_context = aio_context_new(); src = aio_get_g_source(qemu_aio_context); g_source_attach(src, NULL); @@ -411,7 +320,8 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) void qemu_fd_register(int fd) { - WSAEventSelect(fd, qemu_event_handle, FD_READ | FD_ACCEPT | FD_CLOSE | + WSAEventSelect(fd, event_notifier_get_handle(&qemu_aio_context->notifier), + FD_READ | FD_ACCEPT | FD_CLOSE | FD_CONNECT | FD_WRITE | FD_OOB); } -- cgit v1.1 From f9ab4654e370ceedb745523b607a628e297cb6ab Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 2 Nov 2012 15:43:23 +0100 Subject: vl: unify calls to init_timer_alarm init_timer_alarm was being called twice. This is not needed. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- main-loop.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index e43c7c8..234a313 100644 --- a/main-loop.c +++ b/main-loop.c @@ -123,7 +123,10 @@ int qemu_init_main_loop(void) GSource *src; init_clocks(); - init_timer_alarm(); + if (init_timer_alarm() < 0) { + fprintf(stderr, "could not initialize alarm timer\n"); + exit(1); + } qemu_mutex_lock_iothread(); ret = qemu_signal_init(); -- cgit v1.1 From 49cf57281b74ccb64587ccc0626fc55a01227a15 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 2 Nov 2012 15:43:24 +0100 Subject: vl: delay thread initialization after daemonization Commit ac4119c (chardev: Use timer instead of bottom-half to postpone open event, 2012-10-12) moved the alarm timer initialization to an earlier point but failed to consider that it depends on qemu_init_main_loop. Later, commit 1c53786 (vl: init main loop earlier, 2012-10-30) fixed this, but left -daemonize in two different ways. First, timers need to be reinitialized after forking. Second, the global mutex was being held by the parent, and thus dropped after forking. The first is now fixed using pthread_atfork. For the second part, make sure that the global mutex is not taken before daemonization, and similarly delay qemu_thread_self. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- main-loop.c | 1 - 1 file changed, 1 deletion(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index 234a313..c87624e 100644 --- a/main-loop.c +++ b/main-loop.c @@ -128,7 +128,6 @@ int qemu_init_main_loop(void) exit(1); } - qemu_mutex_lock_iothread(); ret = qemu_signal_init(); if (ret) { return ret; -- cgit v1.1 From c57b6656c3168bccca7f78b3f740e9149893b3da Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 13 Nov 2012 16:35:13 +0100 Subject: aio: Get rid of qemu_aio_flush() There are no remaining users, and new users should probably be using bdrv_drain_all() in the first place. Signed-off-by: Kevin Wolf --- main-loop.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index c87624e..7dba6f6 100644 --- a/main-loop.c +++ b/main-loop.c @@ -432,11 +432,6 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) return aio_bh_new(qemu_aio_context, cb, opaque); } -void qemu_aio_flush(void) -{ - aio_flush(qemu_aio_context); -} - bool qemu_aio_wait(void) { return aio_poll(qemu_aio_context, true); -- cgit v1.1 From 737e150e89c44c6b33691a627e24bac7fb58f349 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Dec 2012 18:19:44 +0100 Subject: block: move include files to include/block/ Signed-off-by: Paolo Bonzini --- main-loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index 7dba6f6..f900611 100644 --- a/main-loop.c +++ b/main-loop.c @@ -26,7 +26,7 @@ #include "qemu-timer.h" #include "slirp/slirp.h" #include "main-loop.h" -#include "qemu-aio.h" +#include "block/aio.h" #ifndef _WIN32 -- cgit v1.1 From 1de7afc984b49af164e2619e6850b9732b173b34 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Dec 2012 18:20:00 +0100 Subject: misc: move include files to include/qemu/ Signed-off-by: Paolo Bonzini --- main-loop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index f900611..54f38ae 100644 --- a/main-loop.c +++ b/main-loop.c @@ -23,14 +23,14 @@ */ #include "qemu-common.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "slirp/slirp.h" -#include "main-loop.h" +#include "qemu/main-loop.h" #include "block/aio.h" #ifndef _WIN32 -#include "compatfd.h" +#include "qemu/compatfd.h" /* If we have signalfd, we mask out the signals we want to handle and then * use signalfd to listen for them. We rely on whatever the current signal -- cgit v1.1 From 5e3bc735d93dd23f074b5116fd11e1ad8cd4962f Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Tue, 8 Jan 2013 16:30:56 +0100 Subject: Check return values from g_poll and select The current implementation of os_host_main_loop_wait() on Windows, returns 1 only when a g_poll() event occurs because the return value of select() is overridden. This is wrong as we may skip a socket event, as shown in this example: 1. select() returns 0 2. g_poll() returns 1 (socket event occurs) 3. os_host_main_loop_wait() returns 1 4. qemu_iohandler_poll() sees no socket event because select() has return before the event occurs 5. select() returns 1 6. g_poll() returns 0 (g_poll overrides select's return value) 7. os_host_main_loop_wait() returns 0 8. qemu_iohandler_poll() doesn't check for socket events because the return value of os_host_main_loop_wait() is zero. 9. goto 5 This patch use one variable for each of these return values, so we don't miss a select() event anymore. Also move the call to select() after g_poll(), this will improve latency as we don't have to go through two os_host_main_loop_wait() calls to detect a socket event. Reviewed-by: Paolo Bonzini Signed-off-by: Fabien Chouteau Signed-off-by: Anthony Liguori --- main-loop.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'main-loop.c') diff --git a/main-loop.c b/main-loop.c index 54f38ae..6f52ac3 100644 --- a/main-loop.c +++ b/main-loop.c @@ -330,7 +330,7 @@ void qemu_fd_register(int fd) static int os_host_main_loop_wait(uint32_t timeout) { GMainContext *context = g_main_context_default(); - int ret, i; + int select_ret, g_poll_ret, ret, i; PollingEntry *pe; WaitObjects *w = &wait_objects; gint poll_timeout; @@ -345,13 +345,6 @@ static int os_host_main_loop_wait(uint32_t timeout) return ret; } - if (nfds >= 0) { - ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0); - if (ret != 0) { - timeout = 0; - } - } - 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)); @@ -367,9 +360,9 @@ static int os_host_main_loop_wait(uint32_t timeout) } qemu_mutex_unlock_iothread(); - ret = g_poll(poll_fds, n_poll_fds + w->num, poll_timeout); + g_poll_ret = g_poll(poll_fds, n_poll_fds + w->num, poll_timeout); qemu_mutex_lock_iothread(); - if (ret > 0) { + if (g_poll_ret > 0) { for (i = 0; i < w->num; i++) { w->revents[i] = poll_fds[n_poll_fds + i].revents; } @@ -384,12 +377,18 @@ static int os_host_main_loop_wait(uint32_t timeout) g_main_context_dispatch(context); } - /* If an edge-triggered socket event occurred, select will return a - * positive result on the next iteration. We do not need to do anything - * here. + /* Call select after g_poll to avoid a useless iteration and therefore + * improve socket latency. */ - return ret; + if (nfds >= 0) { + select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0); + if (select_ret != 0) { + timeout = 0; + } + } + + return select_ret || g_poll_ret; } #endif -- cgit v1.1