diff options
Diffstat (limited to 'main-loop.c')
-rw-r--r-- | main-loop.c | 147 |
1 files changed, 85 insertions, 62 deletions
diff --git a/main-loop.c b/main-loop.c index fc738d12a5..1ebdc4baf1 100644 --- a/main-loop.c +++ b/main-loop.c @@ -218,17 +218,19 @@ int main_loop_init(void) return 0; } - +static fd_set rfds, wfds, xfds; +static int nfds; static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */ static int n_poll_fds; static int max_priority; +#ifndef _WIN32 static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds, - fd_set *xfds, struct timeval *tv) + fd_set *xfds, int *cur_timeout) { GMainContext *context = g_main_context_default(); int i; - int timeout = 0, cur_timeout; + int timeout = 0; g_main_context_prepare(context, &max_priority); @@ -253,10 +255,8 @@ static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds, } } - cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000); - if (timeout >= 0 && timeout < cur_timeout) { - tv->tv_sec = timeout / 1000; - tv->tv_usec = (timeout % 1000) * 1000; + if (timeout >= 0 && timeout < *cur_timeout) { + *cur_timeout = timeout; } } @@ -288,7 +288,29 @@ static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds, } } -#ifdef _WIN32 +static int os_host_main_loop_wait(int timeout) +{ + struct timeval tv; + int ret; + + glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout); + + if (timeout > 0) { + qemu_mutex_unlock_iothread(); + } + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); + + if (timeout > 0) { + qemu_mutex_lock_iothread(); + } + + glib_select_poll(&rfds, &wfds, &xfds, (ret < 0)); + return ret; +} +#else /***********************************************************/ /* Polling handling */ @@ -328,6 +350,7 @@ void qemu_del_polling_cb(PollingFunc *func, void *opaque) /* Wait objects support */ typedef struct WaitObjects { int num; + int revents[MAXIMUM_WAIT_OBJECTS + 1]; HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1]; void *opaque[MAXIMUM_WAIT_OBJECTS + 1]; @@ -344,6 +367,7 @@ int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) w->events[w->num] = handle; w->func[w->num] = func; w->opaque[w->num] = opaque; + w->revents[w->num] = 0; w->num++; return 0; } @@ -362,6 +386,7 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) w->events[i] = w->events[i + 1]; w->func[i] = w->func[i + 1]; w->opaque[i] = w->opaque[i + 1]; + w->revents[i] = w->revents[i + 1]; } } if (found) { @@ -369,61 +394,76 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) } } -static void os_host_main_loop_wait(int *timeout) +void qemu_fd_register(int fd) { - int ret, ret2, i; + WSAEventSelect(fd, qemu_event_handle, FD_READ | FD_ACCEPT | FD_CLOSE | + FD_CONNECT | FD_WRITE | FD_OOB); +} + +static int os_host_main_loop_wait(int timeout) +{ + GMainContext *context = g_main_context_default(); + int ret, i; PollingEntry *pe; + WaitObjects *w = &wait_objects; + static struct timeval tv0; /* XXX: need to suppress polling by better using win32 events */ ret = 0; for (pe = first_polling_entry; pe != NULL; pe = pe->next) { ret |= pe->func(pe->opaque); } - if (ret == 0) { - int err; - WaitObjects *w = &wait_objects; + if (ret != 0) { + return ret; + } - qemu_mutex_unlock_iothread(); - ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout); - qemu_mutex_lock_iothread(); - if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { - if (w->func[ret - WAIT_OBJECT_0]) { - w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); - } + 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, &timeout, + poll_fds, ARRAY_SIZE(poll_fds)); + g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds)); - /* Check for additional signaled events */ - for (i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) { - /* Check if event is signaled */ - ret2 = WaitForSingleObject(w->events[i], 0); - if (ret2 == WAIT_OBJECT_0) { - if (w->func[i]) { - w->func[i](w->opaque[i]); - } - } else if (ret2 != WAIT_TIMEOUT) { - err = GetLastError(); - fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err); - } + for (i = 0; i < w->num; i++) { + poll_fds[n_poll_fds + i].fd = (DWORD) w->events[i]; + poll_fds[n_poll_fds + i].events = G_IO_IN; + } + + qemu_mutex_unlock_iothread(); + ret = g_poll(poll_fds, n_poll_fds + w->num, timeout); + qemu_mutex_lock_iothread(); + if (ret > 0) { + for (i = 0; i < w->num; i++) { + w->revents[i] = poll_fds[n_poll_fds + i].revents; + } + for (i = 0; i < w->num; i++) { + if (w->revents[i] && w->func[i]) { + w->func[i](w->opaque[i]); } - } else if (ret != WAIT_TIMEOUT) { - err = GetLastError(); - fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err); } } - *timeout = 0; -} -#else -static inline void os_host_main_loop_wait(int *timeout) -{ + if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) { + 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. + */ + + return ret; } #endif int main_loop_wait(int nonblocking) { - fd_set rfds, wfds, xfds; - int ret, nfds; - struct timeval tv; - int timeout; + int ret, timeout; if (nonblocking) { timeout = 0; @@ -432,11 +472,6 @@ int main_loop_wait(int nonblocking) qemu_bh_update_timeout(&timeout); } - os_host_main_loop_wait(&timeout); - - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - /* poll any events */ /* XXX: separate device handlers from system ones */ nfds = -1; @@ -448,19 +483,7 @@ int main_loop_wait(int nonblocking) slirp_select_fill(&nfds, &rfds, &wfds, &xfds); #endif qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds); - glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv); - - if (timeout > 0) { - qemu_mutex_unlock_iothread(); - } - - ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); - - if (timeout > 0) { - qemu_mutex_lock_iothread(); - } - - glib_select_poll(&rfds, &wfds, &xfds, (ret < 0)); + ret = os_host_main_loop_wait(timeout); qemu_iohandler_poll(&rfds, &wfds, &xfds, ret); #ifdef CONFIG_SLIRP slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0)); |