From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58965) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YibsM-0005Tj-Ap for qemu-devel@nongnu.org; Thu, 16 Apr 2015 00:58:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YibsJ-0003I6-4V for qemu-devel@nongnu.org; Thu, 16 Apr 2015 00:58:06 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57756) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YibsI-0003Hv-SU for qemu-devel@nongnu.org; Thu, 16 Apr 2015 00:58:03 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id 73EA339A5A3 for ; Thu, 16 Apr 2015 04:58:02 +0000 (UTC) From: Fam Zheng Date: Thu, 16 Apr 2015 12:57:36 +0800 Message-Id: <1429160256-27231-8-git-send-email-famz@redhat.com> In-Reply-To: <1429160256-27231-1-git-send-email-famz@redhat.com> References: <1429160256-27231-1-git-send-email-famz@redhat.com> Subject: [Qemu-devel] [PATCH v3 7/7] poll-linux: Add timerfd support List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Kevin Wolf , Paolo Bonzini , Stefan Hajnoczi In qemu_poll_timerfd, we arm the timerfd with timeout_ns. The timerfd is also watched by epollfd, so that when there is no other events, epoll_wait will still return on time, even though we pass -1 (wait infinitely). Signed-off-by: Fam Zheng --- poll-linux.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/poll-linux.c b/poll-linux.c index 7605004..154da8b 100644 --- a/poll-linux.c +++ b/poll-linux.c @@ -12,20 +12,52 @@ */ #include + +#define USE_TIMERFD CONFIG_TIMERFD + +#ifdef USE_TIMERFD +#include +#endif + #include #include #include "qemu-common.h" #include "qemu/timer.h" #include "qemu/poll.h" + struct QEMUPoll { int epollfd; +#if USE_TIMERFD + int timerfd; +#endif struct epoll_event *events; int max_events; int nevents; GHashTable *fds; }; +static void qemu_poll_init_timerfd(QEMUPoll *qpoll) +{ +#if USE_TIMERFD + int r; + struct epoll_event ev; + qpoll->timerfd = timerfd_create(CLOCK_MONOTONIC, + TFD_NONBLOCK | TFD_CLOEXEC); + if (qpoll->timerfd < 0) { + perror("timerfd_create"); + abort(); + } + ev.events = EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP; + ev.data.fd = qpoll->timerfd; + r = epoll_ctl(qpoll->epollfd, EPOLL_CTL_ADD, qpoll->timerfd, &ev); + if (r) { + perror("epoll_ctl add timerfd"); + abort(); + } +#endif +} + QEMUPoll *qemu_poll_new(void) { int epollfd; @@ -40,6 +72,7 @@ QEMUPoll *qemu_poll_new(void) qpoll->events = g_new(struct epoll_event, 1); qpoll->fds = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, g_free); + qemu_poll_init_timerfd(qpoll); return qpoll; } @@ -48,10 +81,13 @@ void qemu_poll_free(QEMUPoll *qpoll) g_free(qpoll->events); g_hash_table_destroy(qpoll->fds); close(qpoll->epollfd); +#if USE_TIMERFD + close(qpoll->timerfd); +#endif g_free(qpoll); } -int qemu_poll(QEMUPoll *qpoll, int64_t timeout_ns) +static int qemu_poll_ppoll(QEMUPoll *qpoll, int64_t timeout_ns) { int r; struct pollfd fd = { @@ -78,6 +114,47 @@ int qemu_poll(QEMUPoll *qpoll, int64_t timeout_ns) return r; } +#if USE_TIMERFD +static int qemu_poll_timerfd(QEMUPoll *qpoll, int64_t timeout_ns) +{ + int r; + struct itimerspec its = { { 0 } }; + + if (timeout_ns > 0) { + its.it_value.tv_sec = timeout_ns / 1000000000LL; + its.it_value.tv_nsec = timeout_ns % 1000000000LL; + } + + r = timerfd_settime(qpoll->timerfd, 0, &its, NULL); + if (r) { + struct pollfd fd = { + .fd = qpoll->epollfd, + .events = POLLIN | POLLOUT | POLLERR | POLLHUP, + }; + perror("timerfd_settime"); + abort(); + r = ppoll(&fd, 1, &its.it_value, NULL); + } + if (r < 0) { + return r; + } + r = epoll_wait(qpoll->epollfd, + qpoll->events, + qpoll->max_events, + timeout_ns > 0 ? -1 : timeout_ns); + qpoll->nevents = r; + return r; +} +#endif + +int qemu_poll(QEMUPoll *qpoll, int64_t timeout_ns) +{ +#if USE_TIMERFD + return qemu_poll_timerfd(qpoll, timeout_ns); +#endif + return qemu_poll_ppoll(qpoll, timeout_ns); +} + static inline uint32_t epoll_event_from_gio_events(int gio_events) { @@ -220,6 +297,11 @@ int qemu_poll_get_events(QEMUPoll *qpoll, for (i = 0; i < MIN(qpoll->nevents, max_events); i++) { ev = &qpoll->events[i]; fd = ev->data.fd; +#if USE_TIMERFD + if (fd == qpoll->timerfd) { + continue; + } +#endif p = g_hash_table_lookup(qpoll->fds, &fd); assert(p); -- 1.9.3