From: Derbyshev Dmitry <dderbyshev@xxxxxxxxxxxxx> This makes it possible to avoid allocations in virEventPollMakePollFDs, as well as generally reduces time spent in kernel if handles remain the same, which should generally be true. --- configure.ac | 28 ++++ src/Makefile.am | 10 +- src/util/vireventepoll.c | 201 +++++++++++++++++++++++ tests/commanddata/{test14.log => test3epoll.log} | 2 + tests/commandtest.c | 4 + 5 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 src/util/vireventepoll.c copy tests/commanddata/{test14.log => test3epoll.log} (94%) diff --git a/configure.ac b/configure.ac index a995a05..9a6a810 100644 --- a/configure.ac +++ b/configure.ac @@ -877,6 +877,34 @@ AC_DEFINE_UNQUOTED([isbase64],[libvirt_gl_isbase64],[Hack to avoid symbol clash] AC_DEFINE_UNQUOTED([base64_encode],[libvirt_gl_base64_encode],[Hack to avoid symbol clash]) AC_DEFINE_UNQUOTED([base64_encode_alloc],[libvirt_gl_base64_encode_alloc],[Hack to avoid symbol clash]) +AC_ARG_ENABLE([epoll], + [AS_HELP_STRING([--enable-epoll],[use epoll(4) on Linux])], + [enable_epoll=$enableval], [enable_epoll=auto]) +if test x$enable_epoll = xno; then + have_linux_epoll=no +else + AC_MSG_CHECKING([for Linux epoll(4)]) + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [ + #ifndef __linux__ + #error This is not Linux + #endif + #include <sys/epoll.h> + ], + [epoll_create1 (EPOLL_CLOEXEC);])], + [have_linux_epoll=yes], + [have_linux_epoll=no]) + AC_MSG_RESULT([$have_linux_epoll]) +fi +if test x$enable_epoll,$have_linux_epoll = xyes,no; then + AC_MSG_ERROR([epoll support explicitly enabled but not available]) +fi +if test "x$have_linux_epoll" = xyes; then + AC_DEFINE_UNQUOTED([HAVE_LINUX_EPOLL], 1, [whether epoll is supported]) +fi + +AM_CONDITIONAL([HAVE_LINUX_EPOLL], [test "x$have_linux_epoll" = xyes]) + AC_CONFIG_FILES([run], [chmod +x,-w run]) AC_CONFIG_FILES([\ diff --git a/src/Makefile.am b/src/Makefile.am index f2643ea..9ad39cb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -89,6 +89,12 @@ augeas_DATA = augeastestdir = $(datadir)/augeas/lenses/tests augeastest_DATA = +if HAVE_LINUX_EPOLL +poll_src=util/vireventepoll.c +else !HAVE_LINUX_EPOLL +poll_src=util/vireventpoll.c +endif !HAVE_LINUX_EPOLL + # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ @@ -113,7 +119,7 @@ UTIL_SOURCES = \ util/virerror.c util/virerror.h \ util/virevent.c util/virevent.h \ util/vireventpollcommon.c util/vireventpoll.h \ - util/vireventpoll.c util/vireventpollinternal.h \ + $(poll_src) util/vireventpollinternal.h \ util/virfile.c util/virfile.h \ util/virfirewall.c util/virfirewall.h \ util/virfirewallpriv.h \ @@ -2376,7 +2382,7 @@ libvirt_setuid_rpc_client_la_SOURCES = \ util/virdbus.c \ util/virerror.c \ util/virevent.c \ - util/vireventpoll.c \ + $(poll_src) \ util/vireventpollcommon.c \ util/virfile.c \ util/virgettext.c \ diff --git a/src/util/vireventepoll.c b/src/util/vireventepoll.c new file mode 100644 index 0000000..5e2a0f5 --- /dev/null +++ b/src/util/vireventepoll.c @@ -0,0 +1,201 @@ +/* + * vireventpoll.c: Poll based event loop for monitoring file handles + * + * Copyright (C) 2007, 2010-2014 Red Hat, Inc. + * Copyright (C) 2007 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + +#include <config.h> + +#include <sys/epoll.h> + +#include "virfile.h" +#include "virlog.h" +#include "vireventpoll.h" +#include "vireventpollinternal.h" + +#define EVENT_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__) + +#define VIR_FROM_THIS VIR_FROM_EVENT + +VIR_LOG_INIT("util.eventpoll"); + +/* Maximum number of events that are returned by epoll in virEventPollRunOnce */ +#define MAX_POLL_EVENTS_AT_ONCE 10 + +int epollfd; + +int virEventPollAddHandleInternal(int watch ATTRIBUTE_UNUSED, + int fd, + int nativeevents) +{ + size_t i; + struct epoll_event ev; + ev.events = nativeevents; + ev.data.fd = fd; + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) < 0) { + if (errno == EEXIST) { + for (i = 0; i < eventLoop.handlesCount; i++) { + if (eventLoop.handles[i].fd == fd && + !eventLoop.handles[i].deleted) { + ev.events |= eventLoop.handles[i].events; + } + } + if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev) < 0) { + return -1; + } + } + else { + return -1; + } + } + return 0; +} + +int virEventPollUpdateHandleInternal(int watch, int fd, int nativeevents) +{ + struct epoll_event ev; + size_t i; + + ev.events = nativeevents; + ev.data.fd = fd; + for (i = 0; i < eventLoop.handlesCount; i++) { + if (eventLoop.handles[i].fd == fd && + !eventLoop.handles[i].deleted && + eventLoop.handles[i].watch != watch) { + ev.events |= eventLoop.handles[i].events; + } + } + + if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev) < 0) { + return -1; + } + return 0; +} + +int virEventPollRemoveHandleInternal(int watch, int fd) +{ + + struct epoll_event ev; + size_t i; + + ev.events = 0; + ev.data.fd = fd; + for (i = 0; i < eventLoop.handlesCount; i++) { + if (eventLoop.handles[i].fd == fd && + !eventLoop.handles[i].deleted && + eventLoop.handles[i].watch != watch) { + ev.events |= eventLoop.handles[i].events; + } + } + + if (ev.events) { + if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev) < 0) { + return -1; + } + } + else { + if (epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev) < 0) { + return -1; + } + } + + return 0; +} + +int virEventPollInitInternal(void) +{ + epollfd = epoll_create1(0); + if (epollfd < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to initialize epoll")); + return -1; + } + return 0; +} + +void virEventPollDeinitInternal(void) +{ + VIR_FORCE_CLOSE(epollfd); +} + +int +virEventPollToNativeEvents(int events) +{ + int ret = 0; + if (events & VIR_EVENT_HANDLE_READABLE) + ret |= EPOLLIN; + if (events & VIR_EVENT_HANDLE_WRITABLE) + ret |= EPOLLOUT; + if (events & VIR_EVENT_HANDLE_ERROR) + ret |= EPOLLERR; + if (events & VIR_EVENT_HANDLE_HANGUP) + ret |= EPOLLHUP; + return ret; +} + +int +virEventPollFromNativeEvents(int events) +{ + int ret = 0; + if (events & EPOLLIN) + ret |= VIR_EVENT_HANDLE_READABLE; + if (events & EPOLLOUT) + ret |= VIR_EVENT_HANDLE_WRITABLE; + if (events & EPOLLERR) + ret |= VIR_EVENT_HANDLE_ERROR; + if (events & EPOLLHUP) + ret |= VIR_EVENT_HANDLE_HANGUP; + return ret; +} + +struct epoll_event events[MAX_POLL_EVENTS_AT_ONCE]; + +int virEventPollWait(int timeout, void **opaque) +{ + int ret; + *opaque = events; + + retry: + ret = epoll_wait(epollfd, events, + MAX_POLL_EVENTS_AT_ONCE, timeout); + if (ret < 0) { + EVENT_DEBUG("Poll got error event %d", errno); + if (errno == EINTR || errno == EAGAIN) + goto retry; + virReportSystemError(errno, "%s", + _("Unable to poll on file handles")); + } + return ret; +} + +void virEventPollOpaqueFree(void *opaque ATTRIBUTE_UNUSED) +{ + return; +} + +int VirWokenFD(void *opaque, size_t n) +{ + return ((struct epoll_event *)opaque)[n].data.fd; +} + +int VirWokenEvents(void *opaque, size_t n) +{ + return ((struct epoll_event *)opaque)[n].events; +} diff --git a/tests/commanddata/test14.log b/tests/commanddata/test3epoll.log similarity index 94% copy from tests/commanddata/test14.log copy to tests/commanddata/test3epoll.log index 703e6da..e4619b3 100644 --- a/tests/commanddata/test14.log +++ b/tests/commanddata/test3epoll.log @@ -8,6 +8,8 @@ ENV:USER=test FD:0 FD:1 FD:2 +FD:6 +FD:8 DAEMON:no CWD:/tmp UMASK:0022 diff --git a/tests/commandtest.c b/tests/commandtest.c index 7bf5447..6b23659 100644 --- a/tests/commandtest.c +++ b/tests/commandtest.c @@ -227,7 +227,11 @@ static int test3(const void *unused ATTRIBUTE_UNUSED) goto cleanup; } +#ifdef HAVE_LINUX_EPOLL + ret = checkoutput("test3epoll", NULL); +#else ret = checkoutput("test3", NULL); +#endif cleanup: virCommandFree(cmd); -- 1.9.5.msysgit.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list