From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44738) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnIcJ-0003Wa-7F for qemu-devel@nongnu.org; Tue, 28 Apr 2015 23:24:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YnIcH-0001OF-S8 for qemu-devel@nongnu.org; Tue, 28 Apr 2015 23:24:55 -0400 Received: from mx1.redhat.com ([209.132.183.28]:49441) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnIcH-0001O4-KY for qemu-devel@nongnu.org; Tue, 28 Apr 2015 23:24:53 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t3T3Oq6N014875 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Tue, 28 Apr 2015 23:24:53 -0400 From: Fam Zheng Date: Wed, 29 Apr 2015 11:24:31 +0800 Message-Id: <1430277871-26761-8-git-send-email-famz@redhat.com> In-Reply-To: <1430277871-26761-1-git-send-email-famz@redhat.com> References: <1430277871-26761-1-git-send-email-famz@redhat.com> Subject: [Qemu-devel] [PATCH v4 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 | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/poll-linux.c b/poll-linux.c index 7605004..0efb59d 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,43 @@ 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; + } + + /* The timer must be set even when there is no timeout so the readable + * timerfd is cleared (we never call read(2) on it). + */ + r = timerfd_settime(qpoll->timerfd, 0, &its, NULL); + + assert(r == 0); + 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 +293,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