core: Add support for eventfd On systems that support it, using an eventfd for simple signalling is much more efficient than using a pipe. Add detection of eventfd to the configure script and wire it up in the POSIX event abstraction. Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
diff --git a/configure.ac b/configure.ac index 4d3cfae..5984380 100644 --- a/configure.ac +++ b/configure.ac
@@ -225,6 +225,44 @@ AC_MSG_ERROR([clock_gettime() is required on this platform]) fi +dnl eventfd support +if test "x$backend" = xlinux || test "x$backend" = xsunos; then + AC_ARG_ENABLE([eventfd], + [AS_HELP_STRING([--enable-eventfd], [use eventfd for signalling [default=auto]])], + [use_eventfd=$enableval], + [use_eventfd=auto]) + if test "x$use_eventfd" != xno; then + AC_CHECK_HEADER([sys/eventfd.h], [eventfd_h=yes], [eventfd_h=]) + if test "x$eventfd_h" = xyes; then + AC_CHECK_DECLS([EFD_NONBLOCK, EFD_CLOEXEC], [eventfd_h_ok=yes], [eventfd_h_ok=], [[#include <sys/eventfd.h>]]) + if test "x$eventfd_h_ok" = xyes; then + AC_CHECK_FUNC([eventfd], [eventfd_ok=yes], [eventfd_ok=]) + if test "x$eventfd_ok" = xyes; then + AC_DEFINE([HAVE_EVENTFD], [1], [Define to 1 if the system has eventfd functionality.]) + elif test "x$use_eventfd" = xyes; then + AC_MSG_ERROR([eventfd() function not found; glibc 2.9+ required]) + fi + elif test "x$use_eventfd" = xyes; then + AC_MSG_ERROR([eventfd header not usable; glibc 2.9+ required]) + fi + elif test "x$use_eventfd" = xyes; then + AC_MSG_ERROR([eventfd header not available; glibc 2.9+ required]) + fi + fi + AC_MSG_CHECKING([whether to use eventfd for signalling]) + if test "x$use_eventfd" = xno; then + AC_MSG_RESULT([no (disabled by user)]) + elif test "x$eventfd_h" != xyes; then + AC_MSG_RESULT([no (header not available)]) + elif test "x$eventfd_h_ok" != xyes; then + AC_MSG_RESULT([no (header not usable)]) + elif test "x$eventfd_ok" != xyes; then + AC_MSG_RESULT([no (functions not available)]) + else + AC_MSG_RESULT([yes]) + fi +fi + dnl timerfd support if test "x$backend" = xlinux || test "x$backend" = xsunos; then AC_ARG_ENABLE([timerfd],
diff --git a/libusb/os/events_posix.c b/libusb/os/events_posix.c index 01064af..952ea5f 100644 --- a/libusb/os/events_posix.c +++ b/libusb/os/events_posix.c
@@ -22,11 +22,22 @@ #include <errno.h> #include <fcntl.h> +#ifdef HAVE_EVENTFD +#include <sys/eventfd.h> +#endif #ifdef HAVE_TIMERFD #include <sys/timerfd.h> #endif #include <unistd.h> +#ifdef HAVE_EVENTFD +#define EVENT_READ_FD(e) ((e)->eventfd) +#define EVENT_WRITE_FD(e) ((e)->eventfd) +#else +#define EVENT_READ_FD(e) ((e)->pipefd[0]) +#define EVENT_WRITE_FD(e) ((e)->pipefd[1]) +#endif + #ifdef HAVE_NFDS_T typedef nfds_t usbi_nfds_t; #else @@ -35,6 +46,15 @@ int usbi_create_event(usbi_event_t *event) { +#ifdef HAVE_EVENTFD + event->eventfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (event->eventfd == -1) { + usbi_err(NULL, "failed to create eventfd, errno=%d", errno); + return LIBUSB_ERROR_OTHER; + } + + return 0; +#else #if defined(HAVE_PIPE2) int ret = pipe2(event->pipefd, O_CLOEXEC); #else @@ -87,34 +107,40 @@ close(event->pipefd[1]); close(event->pipefd[0]); return LIBUSB_ERROR_OTHER; +#endif } void usbi_destroy_event(usbi_event_t *event) { +#ifdef HAVE_EVENTFD + if (close(event->eventfd) == -1) + usbi_warn(NULL, "failed to close eventfd, errno=%d", errno); +#else if (close(event->pipefd[1]) == -1) usbi_warn(NULL, "failed to close pipe write end, errno=%d", errno); if (close(event->pipefd[0]) == -1) usbi_warn(NULL, "failed to close pipe read end, errno=%d", errno); +#endif } void usbi_signal_event(usbi_event_t *event) { - unsigned char dummy = 1; + uint64_t dummy = 1; ssize_t r; - r = write(event->pipefd[1], &dummy, sizeof(dummy)); + r = write(EVENT_WRITE_FD(event), &dummy, sizeof(dummy)); if (r != sizeof(dummy)) - usbi_warn(NULL, "pipe write failed"); + usbi_warn(NULL, "event write failed"); } void usbi_clear_event(usbi_event_t *event) { - unsigned char dummy; + uint64_t dummy; ssize_t r; - r = read(event->pipefd[0], &dummy, sizeof(dummy)); + r = read(EVENT_READ_FD(event), &dummy, sizeof(dummy)); if (r != sizeof(dummy)) - usbi_warn(NULL, "pipe read failed"); + usbi_warn(NULL, "event read failed"); } #ifdef HAVE_TIMERFD
diff --git a/libusb/os/events_posix.h b/libusb/os/events_posix.h index 401de04..d81b5c4 100644 --- a/libusb/os/events_posix.h +++ b/libusb/os/events_posix.h
@@ -26,12 +26,21 @@ typedef int usbi_os_handle_t; #define USBI_OS_HANDLE_FORMAT_STRING "fd %d" +#ifdef HAVE_EVENTFD +typedef struct usbi_event { + int eventfd; +} usbi_event_t; +#define USBI_EVENT_OS_HANDLE(e) ((e)->eventfd) +#define USBI_EVENT_POLL_EVENTS POLLIN +#define USBI_INVALID_EVENT { -1 } +#else typedef struct usbi_event { int pipefd[2]; } usbi_event_t; #define USBI_EVENT_OS_HANDLE(e) ((e)->pipefd[0]) #define USBI_EVENT_POLL_EVENTS POLLIN #define USBI_INVALID_EVENT { { -1, -1 } } +#endif #ifdef HAVE_TIMERFD #define HAVE_OS_TIMER 1
diff --git a/libusb/version_nano.h b/libusb/version_nano.h index bf72b26..c972e09 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h
@@ -1 +1 @@ -#define LIBUSB_NANO 11532 +#define LIBUSB_NANO 11533