core: Introduce platform events abstraction
authorChris Dickens <christopher.a.dickens@gmail.com>
Wed, 12 Aug 2020 23:06:38 +0000 (16:06 -0700)
committerChris Dickens <christopher.a.dickens@gmail.com>
Wed, 12 Aug 2020 23:06:38 +0000 (16:06 -0700)
The way in which system handles or resources are represented differs
greatly between Unix-like operating systems and Windows. Ever since
Windows support was added to libusb, Windows been emulating principles
of Unix-like operating systems such as file descriptors and poll().

This commit introduces an abstraction layer that completely removes the
need to perform any emulation. Fundamentally there are three things that
each platform provides to libusb:

  1) A signallable event
  2) A timer (not required, but useful)
  3) A means to wait for event sources such as the above to be triggered

The POSIX abstraction for Unix-like operating systems uses file
descriptors as the "handles" to the underlying system resources. The
signallable event is implemented using a pipe, the timer as a timerfd
(where supported) and the poll() system call is used to wait for events.

The Windows abstraction uses native HANDLEs as the "handles" to the
underlying system resources. The signallable event is implemented using
a manual-reset event, the timer as a manual-reset waitable timer, and
the WaitForMultipleObjects() system call is used to wait for events.

Closes #252

Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
40 files changed:
Xcode/config.h
Xcode/libusb.xcodeproj/project.pbxproj
android/config.h
android/jni/libusb.mk
configure.ac
libusb/Makefile.am
libusb/core.c
libusb/hotplug.c
libusb/io.c
libusb/libusbi.h
libusb/os/events_posix.c [new file with mode: 0644]
libusb/os/events_posix.h [new file with mode: 0644]
libusb/os/events_windows.c [new file with mode: 0644]
libusb/os/events_windows.h [new file with mode: 0644]
libusb/os/linux_netlink.c
libusb/os/linux_udev.c
libusb/os/linux_usbfs.c
libusb/os/poll_posix.c [deleted file]
libusb/os/poll_posix.h [deleted file]
libusb/os/poll_windows.c [deleted file]
libusb/os/poll_windows.h [deleted file]
libusb/os/windows_winusb.c
libusb/version_nano.h
msvc/config.h
msvc/libusb_dll_2013.vcxproj
msvc/libusb_dll_2013.vcxproj.filters
msvc/libusb_dll_2015.vcxproj
msvc/libusb_dll_2015.vcxproj.filters
msvc/libusb_dll_2017.vcxproj
msvc/libusb_dll_2017.vcxproj.filters
msvc/libusb_dll_2019.vcxproj
msvc/libusb_dll_2019.vcxproj.filters
msvc/libusb_static_2013.vcxproj
msvc/libusb_static_2013.vcxproj.filters
msvc/libusb_static_2015.vcxproj
msvc/libusb_static_2015.vcxproj.filters
msvc/libusb_static_2017.vcxproj
msvc/libusb_static_2017.vcxproj.filters
msvc/libusb_static_2019.vcxproj
msvc/libusb_static_2019.vcxproj.filters

index 23660781760717215642ec4beb77cb21c9376f24..3385553b14791737f2485af66897d289be38437f 100644 (file)
@@ -8,6 +8,9 @@
 /* Define to 1 to enable message logging. */
 #define ENABLE_LOGGING 1
 
+/* Define to 1 if using the POSIX events abstraction. */
+#define EVENTS_POSIX 1
+
 /* On 10.12 and later, use newly available clock_*() functions */
 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
 /* Define to 1 if you have the `clock_gettime' function. */
@@ -26,9 +29,6 @@
 /* Define to 1 if you have the <sys/time.h> header file. */
 #define HAVE_SYS_TIME_H 1
 
-/* Define to 1 if using the POSIX poll() implementation. */
-#define POLL_POSIX 1
-
 /* Define to 1 if using POSIX threads. */
 #define THREADS_POSIX 1
 
index 54e0ff736d2e39c56fca543d260982f02454adc7..dd33f3555f186d252639c2f5d7754334cacaf7a4 100644 (file)
@@ -42,7 +42,6 @@
                008FBF901628B7E800BC5BE2 /* libusbi.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF671628B7E800BC5BE2 /* libusbi.h */; };
                008FBF921628B7E800BC5BE2 /* darwin_usb.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBF6C1628B7E800BC5BE2 /* darwin_usb.c */; };
                008FBF931628B7E800BC5BE2 /* darwin_usb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF6D1628B7E800BC5BE2 /* darwin_usb.h */; };
-               008FBF971628B7E800BC5BE2 /* poll_posix.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF711628B7E800BC5BE2 /* poll_posix.h */; };
                008FBF9A1628B7E800BC5BE2 /* threads_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBF741628B7E800BC5BE2 /* threads_posix.c */; };
                008FBF9B1628B7E800BC5BE2 /* threads_posix.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF751628B7E800BC5BE2 /* threads_posix.h */; };
                008FBFA01628B7E800BC5BE2 /* sync.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBF7A1628B7E800BC5BE2 /* sync.c */; };
@@ -65,8 +64,9 @@
                008FC0311628BC7800BC5BE2 /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; };
                1438D77A17A2ED9F00166101 /* hotplug.c in Sources */ = {isa = PBXBuildFile; fileRef = 1438D77817A2ED9F00166101 /* hotplug.c */; };
                1438D77B17A2ED9F00166101 /* hotplug.h in Headers */ = {isa = PBXBuildFile; fileRef = 1438D77917A2ED9F00166101 /* hotplug.h */; };
-               1438D77D17A2EDCD00166101 /* poll_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 1438D77C17A2EDCD00166101 /* poll_posix.c */; };
                1438D77F17A2F0EA00166101 /* strerror.c in Sources */ = {isa = PBXBuildFile; fileRef = 1438D77E17A2F0EA00166101 /* strerror.c */; };
+               2018D95F24E453BA001589B2 /* events_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 2018D95E24E453BA001589B2 /* events_posix.c */; };
+               2018D96124E453D0001589B2 /* events_posix.h in Headers */ = {isa = PBXBuildFile; fileRef = 2018D96024E453D0001589B2 /* events_posix.h */; };
                20468D70243298C100650534 /* sam3u_benchmark.c in Sources */ = {isa = PBXBuildFile; fileRef = 20468D6E243298C100650534 /* sam3u_benchmark.c */; };
                20468D7E2432990100650534 /* testlibusb.c in Sources */ = {isa = PBXBuildFile; fileRef = 20468D7C2432990000650534 /* testlibusb.c */; };
                20468D7F2432993300650534 /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; };
                008FBF671628B7E800BC5BE2 /* libusbi.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = libusbi.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                008FBF6C1628B7E800BC5BE2 /* darwin_usb.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = darwin_usb.c; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
                008FBF6D1628B7E800BC5BE2 /* darwin_usb.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = darwin_usb.h; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
-               008FBF711628B7E800BC5BE2 /* poll_posix.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = poll_posix.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                008FBF741628B7E800BC5BE2 /* threads_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = threads_posix.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                008FBF751628B7E800BC5BE2 /* threads_posix.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = threads_posix.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                008FBF7A1628B7E800BC5BE2 /* sync.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = sync.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                008FC0261628BC6B00BC5BE2 /* listdevs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = listdevs; sourceTree = BUILT_PRODUCTS_DIR; };
                1438D77817A2ED9F00166101 /* hotplug.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = hotplug.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                1438D77917A2ED9F00166101 /* hotplug.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = hotplug.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
-               1438D77C17A2EDCD00166101 /* poll_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = poll_posix.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                1438D77E17A2F0EA00166101 /* strerror.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = strerror.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                1443EE8416417E63007E0579 /* common.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = common.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; };
                1443EE8516417E63007E0579 /* debug.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = debug.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; };
                1443EE8716417E63007E0579 /* libusb.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = libusb.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; };
                1443EE8816417E63007E0579 /* release.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = release.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; };
                1443EE8916417EA6007E0579 /* libusb_release.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = libusb_release.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; };
+               2018D95E24E453BA001589B2 /* events_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = events_posix.c; sourceTree = "<group>"; };
+               2018D96024E453D0001589B2 /* events_posix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = events_posix.h; sourceTree = "<group>"; };
                20468D67243298AE00650534 /* sam3u_benchmark */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sam3u_benchmark; sourceTree = BUILT_PRODUCTS_DIR; };
                20468D6E243298C100650534 /* sam3u_benchmark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sam3u_benchmark.c; sourceTree = "<group>"; usesTabs = 1; };
                20468D75243298D300650534 /* testlibusb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testlibusb; sourceTree = BUILT_PRODUCTS_DIR; };
                        children = (
                                008FBF6C1628B7E800BC5BE2 /* darwin_usb.c */,
                                008FBF6D1628B7E800BC5BE2 /* darwin_usb.h */,
-                               1438D77C17A2EDCD00166101 /* poll_posix.c */,
-                               008FBF711628B7E800BC5BE2 /* poll_posix.h */,
+                               2018D95E24E453BA001589B2 /* events_posix.c */,
+                               2018D96024E453D0001589B2 /* events_posix.h */,
                                008FBF741628B7E800BC5BE2 /* threads_posix.c */,
                                008FBF751628B7E800BC5BE2 /* threads_posix.h */,
                        );
                        files = (
                                008FBFA51628B84200BC5BE2 /* config.h in Headers */,
                                008FBF931628B7E800BC5BE2 /* darwin_usb.h in Headers */,
+                               2018D96124E453D0001589B2 /* events_posix.h in Headers */,
                                1438D77B17A2ED9F00166101 /* hotplug.h in Headers */,
                                008FBF891628B7E800BC5BE2 /* libusb.h in Headers */,
                                008FBF901628B7E800BC5BE2 /* libusbi.h in Headers */,
-                               008FBF971628B7E800BC5BE2 /* poll_posix.h in Headers */,
                                008FBF9B1628B7E800BC5BE2 /* threads_posix.h in Headers */,
                                008FBFA11628B7E800BC5BE2 /* version.h in Headers */,
                                008FBFA21628B7E800BC5BE2 /* version_nano.h in Headers */,
                                008FBF861628B7E800BC5BE2 /* core.c in Sources */,
                                008FBF921628B7E800BC5BE2 /* darwin_usb.c in Sources */,
                                008FBF871628B7E800BC5BE2 /* descriptor.c in Sources */,
+                               2018D95F24E453BA001589B2 /* events_posix.c in Sources */,
                                1438D77A17A2ED9F00166101 /* hotplug.c in Sources */,
                                008FBF881628B7E800BC5BE2 /* io.c in Sources */,
-                               1438D77D17A2EDCD00166101 /* poll_posix.c in Sources */,
                                1438D77F17A2F0EA00166101 /* strerror.c in Sources */,
                                008FBFA01628B7E800BC5BE2 /* sync.c in Sources */,
                                008FBF9A1628B7E800BC5BE2 /* threads_posix.c in Sources */,
index 341c01f13f33111f453d830b010d0a81b1c9d0ee..4a4b995c19b79988046d2421c51d5d444de97bc6 100644 (file)
@@ -26,6 +26,9 @@
 /* Define to 1 to enable message logging. */
 #define ENABLE_LOGGING 1
 
+/* Define to 1 if using the POSIX events abstraction. */
+#define EVENTS_POSIX 1
+
 /* Define to 1 if you have the <asm/types.h> header file. */
 #define HAVE_ASM_TYPES_H 1
 
@@ -41,9 +44,6 @@
 /* Define to 1 if you have the <sys/time.h> header file. */
 #define HAVE_SYS_TIME_H 1
 
-/* Define to 1 if using the POSIX poll() implementation. */
-#define POLL_POSIX 1
-
 /* Define to 1 if using POSIX threads. */
 #define THREADS_POSIX 1
 
index 3308e79c7f64fba7493803a6ca16b2832ba39f58..656f903634819e5f0e40f46273dda020e4796733 100644 (file)
@@ -35,7 +35,7 @@ LOCAL_SRC_FILES := \
   $(LIBUSB_ROOT_REL)/libusb/sync.c \
   $(LIBUSB_ROOT_REL)/libusb/strerror.c \
   $(LIBUSB_ROOT_REL)/libusb/os/linux_usbfs.c \
-  $(LIBUSB_ROOT_REL)/libusb/os/poll_posix.c \
+  $(LIBUSB_ROOT_REL)/libusb/os/events_posix.c \
   $(LIBUSB_ROOT_REL)/libusb/os/threads_posix.c \
   $(LIBUSB_ROOT_REL)/libusb/os/linux_netlink.c
 
index d3860536b2e12490a93c73a26c15f95f5c0b6e74..4d3cfae3f95c99c3c369f3827eb7712398675781 100644 (file)
@@ -75,13 +75,13 @@ case $host in
 *-darwin*)
        AC_MSG_RESULT([Darwin/Mac OS X])
        backend=darwin
-       poll=posix
+       events=posix
        threads=posix
        ;;
 *-haiku*)
        AC_MSG_RESULT([Haiku])
        backend=haiku
-       poll=posix
+       events=posix
        threads=posix
        ;;
 *-linux* | *-uclinux*)
@@ -96,37 +96,37 @@ case $host in
                ;;
        esac
        backend=linux
-       poll=posix
+       events=posix
        threads=posix
        ;;
 *-netbsd*)
        AC_MSG_RESULT([NetBSD])
        backend=netbsd
-       poll=posix
+       events=posix
        threads=posix
        ;;
 *-openbsd*)
        AC_MSG_RESULT([OpenBSD])
        backend=openbsd
-       poll=posix
+       events=posix
        threads=posix
        ;;
 *-solaris*)
        AC_MSG_RESULT([SunOS])
        backend=sunos
-       poll=posix
+       events=posix
        threads=posix
        ;;
 *-cygwin*)
        AC_MSG_RESULT([Windows (using Cygwin)])
        backend=windows
-       poll=windows
+       events=windows
        threads=posix
        ;;
 *-mingw* | *msys*)
        AC_MSG_RESULT([Windows])
        backend=windows
-       poll=windows
+       events=windows
        threads=windows
        test "x$enable_shared" = xyes && create_import_lib=yes
        EXTRA_CFLAGS="-fno-omit-frame-pointer"
@@ -136,19 +136,19 @@ case $host in
        AC_MSG_WARN([The host being compiled for is not supported.])
        AC_MSG_WARN([The library may compile but will not function in any useful manner.])
        backend="null"
-       poll=posix
+       events=posix
        threads="posix"
        ;;
 esac
 
-if test "x$poll" = xposix; then
-       AC_DEFINE([POLL_POSIX], [1], [Define to 1 if using the POSIX poll() implementation.])
+if test "x$events" = xposix; then
+       AC_DEFINE([EVENTS_POSIX], [1], [Define to 1 if using the POSIX events abstraction.])
        AC_CHECK_TYPES([nfds_t], [], [], [[#include <poll.h>]])
        AC_CHECK_FUNCS([pipe2])
-elif test "x$poll" = xwindows; then
-       AC_DEFINE([POLL_WINDOWS], [1], [Define to 1 if using the Windows poll() implementation.])
+elif test "x$events" = xwindows; then
+       AC_DEFINE([EVENTS_WINDOWS], [1], [Define to 1 if using the Windows events abstraction.])
 else
-       AC_MSG_ERROR([Unknown poll implementation])
+       AC_MSG_ERROR([Unknown events abstraction])
 fi
 
 if test "x$threads" = xposix; then
@@ -314,6 +314,8 @@ AC_ARG_ENABLE([tests-build],
 AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != xno])
 AM_CONDITIONAL([BUILD_TESTS], [test "x$build_tests" != xno])
 AM_CONDITIONAL([CREATE_IMPORT_LIB], [test "x$create_import_lib" = xyes])
+AM_CONDITIONAL([EVENTS_POSIX], [test "x$events" = xposix])
+AM_CONDITIONAL([EVENTS_WINDOWS], [test "x$events" = xwindows])
 AM_CONDITIONAL([HAVE_SIGACTION], [test "x$have_sigaction" = xyes])
 AM_CONDITIONAL([OS_DARWIN], [test "x$backend" = xdarwin])
 AM_CONDITIONAL([OS_HAIKU], [test "x$backend" = xhaiku])
@@ -323,8 +325,6 @@ AM_CONDITIONAL([OS_NULL], [test "x$backend" = xnull])
 AM_CONDITIONAL([OS_OPENBSD], [test "x$backend" = xopenbsd])
 AM_CONDITIONAL([OS_SUNOS], [test "x$backend" = xsunos])
 AM_CONDITIONAL([OS_WINDOWS], [test "x$backend" = xwindows])
-AM_CONDITIONAL([POLL_POSIX], [test "x$poll" = xposix])
-AM_CONDITIONAL([POLL_WINDOWS], [test "x$poll" = xwindows])
 AM_CONDITIONAL([THREADS_POSIX], [test "x$threads" = xposix])
 AM_CONDITIONAL([THREADS_WINDOWS], [test "x$threads" = xwindows])
 AM_CONDITIONAL([USE_UDEV], [test "x$use_udev" = xyes])
index 6b933436e72a26e3d07faa4c68fd994d4dde0634..72cd5027df320f924ac14f229a33583022ba7044 100644 (file)
@@ -5,13 +5,13 @@ AM_CXXFLAGS += -fvisibility=hidden $(THREAD_CFLAGS)
 
 lib_LTLIBRARIES = libusb-1.0.la
 
-POSIX_POLL_SRC = os/poll_posix.h os/poll_posix.c
-WINDOWS_POLL_SRC = os/poll_windows.h os/poll_windows.c
+POSIX_EVENTS_SRC = os/events_posix.h os/events_posix.c
+WINDOWS_EVENTS_SRC = os/events_windows.h os/events_windows.c
 
-if POLL_POSIX
-POLL_SRC = $(POSIX_POLL_SRC)
+if EVENTS_POSIX
+EVENTS_SRC = $(POSIX_EVENTS_SRC)
 else
-POLL_SRC = $(WINDOWS_POLL_SRC)
+EVENTS_SRC = $(WINDOWS_EVENTS_SRC)
 endif
 
 POSIX_THREADS_SRC = os/threads_posix.h os/threads_posix.c
@@ -90,6 +90,6 @@ endif
 libusb_1_0_la_LDFLAGS = $(LT_LDFLAGS)
 libusb_1_0_la_SOURCES = libusbi.h version.h version_nano.h \
        core.c descriptor.c hotplug.h hotplug.c io.c strerror.c sync.c \
-       $(POLL_SRC) $(THREADS_SRC) $(OS_SRC)
+       $(EVENTS_SRC) $(THREADS_SRC) $(OS_SRC)
 
 pkginclude_HEADERS = libusb.h
index 89cfec3a68280197c7f23b60327cc212ca3be43e..692350acdb15c1c4ad70f6f8d71650931f9a4261 100644 (file)
@@ -1188,44 +1188,6 @@ void API_EXPORTED libusb_unref_device(libusb_device *dev)
        }
 }
 
-/*
- * Signal the event pipe so that the event handling thread will be
- * interrupted to process an internal event.
- */
-int usbi_signal_event(struct libusb_context *ctx)
-{
-       unsigned char dummy = 1;
-       ssize_t r;
-
-       /* write some data on event pipe to interrupt event handlers */
-       r = usbi_write(ctx->event_pipe[1], &dummy, sizeof(dummy));
-       if (r != sizeof(dummy)) {
-               usbi_warn(ctx, "internal signalling write failed");
-               return LIBUSB_ERROR_IO;
-       }
-
-       return 0;
-}
-
-/*
- * Clear the event pipe so that the event handling will no longer be
- * interrupted.
- */
-int usbi_clear_event(struct libusb_context *ctx)
-{
-       unsigned char dummy;
-       ssize_t r;
-
-       /* read some data on event pipe to clear it */
-       r = usbi_read(ctx->event_pipe[0], &dummy, sizeof(dummy));
-       if (r != sizeof(dummy)) {
-               usbi_warn(ctx, "internal signalling read failed");
-               return LIBUSB_ERROR_IO;
-       }
-
-       return 0;
-}
-
 /** \ingroup libusb_dev
  * Wrap a platform-specific system device handle and obtain a libusb device
  * handle for the underlying device. The handle allows you to use libusb to
@@ -1500,7 +1462,7 @@ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
                pending_events = usbi_pending_events(ctx);
                ctx->device_close++;
                if (!pending_events)
-                       usbi_signal_event(ctx);
+                       usbi_signal_event(&ctx->event);
                usbi_mutex_unlock(&ctx->event_data_lock);
 
                /* take event handling lock */
@@ -1517,7 +1479,7 @@ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
                ctx->device_close--;
                pending_events = usbi_pending_events(ctx);
                if (!pending_events)
-                       usbi_clear_event(ctx);
+                       usbi_clear_event(&ctx->event);
                usbi_mutex_unlock(&ctx->event_data_lock);
 
                /* Release event handling lock and wake up event waiters */
index c02cc56e5826894af335c7da9631c6cc27b2bf5a..86aeed8ee0dcb70f4579b543a440e40bc5d271ba 100644 (file)
@@ -223,7 +223,7 @@ void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device
        pending_events = usbi_pending_events(ctx);
        list_add_tail(&message->list, &ctx->hotplug_msgs);
        if (!pending_events)
-               usbi_signal_event(ctx);
+               usbi_signal_event(&ctx->event);
        usbi_mutex_unlock(&ctx->event_data_lock);
 }
 
@@ -347,7 +347,7 @@ void API_EXPORTED libusb_hotplug_deregister_callback(libusb_context *ctx,
                pending_events = usbi_pending_events(ctx);
                ctx->event_flags |= USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
                if (!pending_events)
-                       usbi_signal_event(ctx);
+                       usbi_signal_event(&ctx->event);
                usbi_mutex_unlock(&ctx->event_data_lock);
        }
 }
index 27350fa530773cf081f3f2b84a90accfada4c0b6..31a586eeb4cb80cab4361981ea96dd81a5ea3327 100644 (file)
 #include "hotplug.h"
 
 #include <errno.h>
-#ifdef HAVE_TIMERFD
-#include <sys/timerfd.h>
-#include <unistd.h>
-#endif
 
 /**
  * \page libusb_io Synchronous and asynchronous device I/O
@@ -1121,44 +1117,40 @@ int usbi_io_init(struct libusb_context *ctx)
        usbi_mutex_init(&ctx->event_data_lock);
        usbi_tls_key_create(&ctx->event_handling_key);
        list_init(&ctx->flying_transfers);
-       list_init(&ctx->ipollfds);
-       list_init(&ctx->removed_ipollfds);
+       list_init(&ctx->event_sources);
+       list_init(&ctx->removed_event_sources);
        list_init(&ctx->hotplug_msgs);
        list_init(&ctx->completed_transfers);
 
-       /* FIXME should use an eventfd on kernels that support it */
-       r = usbi_pipe(ctx->event_pipe);
-       if (r < 0) {
-               r = LIBUSB_ERROR_OTHER;
+       r = usbi_create_event(&ctx->event);
+       if (r < 0)
                goto err;
-       }
 
-       r = usbi_add_pollfd(ctx, ctx->event_pipe[0], POLLIN);
+       r = usbi_add_event_source(ctx, USBI_EVENT_OS_HANDLE(&ctx->event), USBI_EVENT_POLL_EVENTS);
        if (r < 0)
-               goto err_close_pipe;
+               goto err_destroy_event;
 
-#ifdef HAVE_TIMERFD
-       ctx->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
-       if (ctx->timerfd >= 0) {
-               usbi_dbg("using timerfd for timeouts");
-               r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN);
+#ifdef HAVE_OS_TIMER
+       r = usbi_create_timer(&ctx->timer);
+       if (r == 0) {
+               usbi_dbg("using timer for timeouts");
+               r = usbi_add_event_source(ctx, USBI_TIMER_OS_HANDLE(&ctx->timer), USBI_TIMER_POLL_EVENTS);
                if (r < 0)
-                       goto err_close_timerfd;
+                       goto err_destroy_timer;
        } else {
-               usbi_dbg("timerfd not available, errno=%d", errno);
+               usbi_dbg("timer not available for timeouts");
        }
 #endif
 
        return 0;
 
-#ifdef HAVE_TIMERFD
-err_close_timerfd:
-       close(ctx->timerfd);
-       usbi_remove_pollfd(ctx, ctx->event_pipe[0]);
+#ifdef HAVE_OS_TIMER
+err_destroy_timer:
+       usbi_destroy_timer(&ctx->timer);
+       usbi_remove_event_source(ctx, USBI_EVENT_OS_HANDLE(&ctx->event));
 #endif
-err_close_pipe:
-       usbi_close(ctx->event_pipe[0]);
-       usbi_close(ctx->event_pipe[1]);
+err_destroy_event:
+       usbi_destroy_event(&ctx->event);
 err:
        usbi_mutex_destroy(&ctx->flying_transfers_lock);
        usbi_mutex_destroy(&ctx->events_lock);
@@ -1169,35 +1161,34 @@ err:
        return r;
 }
 
-static void cleanup_removed_pollfds(struct libusb_context *ctx)
+static void cleanup_removed_event_sources(struct libusb_context *ctx)
 {
-       struct usbi_pollfd *ipollfd, *tmp;
+       struct usbi_event_source *ievent_source, *tmp;
 
-       for_each_removed_pollfd_safe(ctx, ipollfd, tmp) {
-               list_del(&ipollfd->list);
-               free(ipollfd);
+       for_each_removed_event_source_safe(ctx, ievent_source, tmp) {
+               list_del(&ievent_source->list);
+               free(ievent_source);
        }
 }
 
 void usbi_io_exit(struct libusb_context *ctx)
 {
-       usbi_remove_pollfd(ctx, ctx->event_pipe[0]);
-       usbi_close(ctx->event_pipe[0]);
-       usbi_close(ctx->event_pipe[1]);
-#ifdef HAVE_TIMERFD
-       if (usbi_using_timerfd(ctx)) {
-               usbi_remove_pollfd(ctx, ctx->timerfd);
-               close(ctx->timerfd);
+#ifdef HAVE_OS_TIMER
+       if (usbi_using_timer(ctx)) {
+               usbi_remove_event_source(ctx, USBI_TIMER_OS_HANDLE(&ctx->timer));
+               usbi_destroy_timer(&ctx->timer);
        }
 #endif
+       usbi_remove_event_source(ctx, USBI_EVENT_OS_HANDLE(&ctx->event));
+       usbi_destroy_event(&ctx->event);
        usbi_mutex_destroy(&ctx->flying_transfers_lock);
        usbi_mutex_destroy(&ctx->events_lock);
        usbi_mutex_destroy(&ctx->event_waiters_lock);
        usbi_cond_destroy(&ctx->event_waiters_cond);
        usbi_mutex_destroy(&ctx->event_data_lock);
        usbi_tls_key_delete(ctx->event_handling_key);
-       free(ctx->pollfds);
-       cleanup_removed_pollfds(ctx);
+       cleanup_removed_event_sources(ctx);
+       free(ctx->event_data);
 }
 
 static int calculate_timeout(struct usbi_transfer *itransfer)
@@ -1322,55 +1313,39 @@ void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer)
        free(ptr);
 }
 
-#ifdef HAVE_TIMERFD
-static int disarm_timerfd(struct libusb_context *ctx)
-{
-       const struct itimerspec disarm_timer = { { 0, 0 }, { 0, 0 } };
-       int r;
-
-       usbi_dbg(" ");
-       r = timerfd_settime(ctx->timerfd, 0, &disarm_timer, NULL);
-       if (r < 0)
-               return LIBUSB_ERROR_OTHER;
-       else
-               return 0;
-}
-
-/* iterates through the flying transfers, and rearms the timerfd based on the
+/* iterates through the flying transfers, and rearms the timer based on the
  * next upcoming timeout.
  * must be called with flying_list locked.
  * returns 0 on success or a LIBUSB_ERROR code on failure.
  */
-static int arm_timerfd_for_next_timeout(struct libusb_context *ctx)
+#ifdef HAVE_OS_TIMER
+static int arm_timer_for_next_timeout(struct libusb_context *ctx)
 {
        struct usbi_transfer *itransfer;
 
+       if (!usbi_using_timer(ctx))
+               return 0;
+
        for_each_transfer(ctx, itransfer) {
                struct timespec *cur_ts = &itransfer->timeout;
 
                /* if we've reached transfers of infinite timeout, then we have no
                 * arming to do */
                if (!TIMESPEC_IS_SET(cur_ts))
-                       goto disarm;
+                       break;
 
                /* act on first transfer that has not already been handled */
                if (!(itransfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))) {
-                       int r;
-                       const struct itimerspec it = { {0, 0},
-                               { cur_ts->tv_sec, cur_ts->tv_nsec } };
                        usbi_dbg("next timeout originally %ums", USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout);
-                       r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL);
-                       if (r < 0)
-                               return LIBUSB_ERROR_OTHER;
-                       return 0;
+                       return usbi_arm_timer(&ctx->timer, cur_ts);
                }
        }
 
-disarm:
-       return disarm_timerfd(ctx);
+       usbi_dbg("no timeouts, disarming timer");
+       return usbi_disarm_timer(&ctx->timer);
 }
 #else
-static int arm_timerfd_for_next_timeout(struct libusb_context *ctx)
+static inline int arm_timer_for_next_timeout(struct libusb_context *ctx)
 {
        UNUSED(ctx);
        return 0;
@@ -1421,19 +1396,13 @@ static int add_to_flying_list(struct usbi_transfer *itransfer)
        /* otherwise we need to be inserted at the end */
        list_add_tail(&itransfer->list, &ctx->flying_transfers);
 out:
-#ifdef HAVE_TIMERFD
-       if (first && usbi_using_timerfd(ctx) && TIMESPEC_IS_SET(timeout)) {
+#ifdef HAVE_OS_TIMER
+       if (first && usbi_using_timer(ctx) && TIMESPEC_IS_SET(timeout)) {
                /* if this transfer has the lowest timeout of all active transfers,
-                * rearm the timerfd with this transfer's timeout */
-               const struct itimerspec it = { {0, 0},
-                       { timeout->tv_sec, timeout->tv_nsec } };
-               usbi_dbg("arm timerfd for timeout in %ums (first in line)",
+                * rearm the timer with this transfer's timeout */
+               usbi_dbg("arm timer for timeout in %ums (first in line)",
                        USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout);
-               r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL);
-               if (r < 0) {
-                       usbi_warn(ctx, "failed to arm first timerfd, errno=%d", errno);
-                       r = LIBUSB_ERROR_OTHER;
-               }
+               r = usbi_arm_timer(&ctx->timer, timeout);
        }
 #else
        UNUSED(first);
@@ -1452,15 +1421,15 @@ out:
 static int remove_from_flying_list(struct usbi_transfer *itransfer)
 {
        struct libusb_context *ctx = ITRANSFER_CTX(itransfer);
-       int rearm_timerfd;
+       int rearm_timer;
        int r = 0;
 
        usbi_mutex_lock(&ctx->flying_transfers_lock);
-       rearm_timerfd = (TIMESPEC_IS_SET(&itransfer->timeout) &&
+       rearm_timer = (TIMESPEC_IS_SET(&itransfer->timeout) &&
                list_first_entry(&ctx->flying_transfers, struct usbi_transfer, list) == itransfer);
        list_del(&itransfer->list);
-       if (usbi_using_timerfd(ctx) && rearm_timerfd)
-               r = arm_timerfd_for_next_timeout(ctx);
+       if (rearm_timer)
+               r = arm_timer_for_next_timeout(ctx);
        usbi_mutex_unlock(&ctx->flying_transfers_lock);
 
        return r;
@@ -1660,7 +1629,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
 
        r = remove_from_flying_list(itransfer);
        if (r < 0)
-               usbi_err(ITRANSFER_CTX(itransfer), "failed to set timer for next timeout, errno=%d", errno);
+               usbi_err(ITRANSFER_CTX(itransfer), "failed to set timer for next timeout");
 
        usbi_mutex_lock(&itransfer->lock);
        itransfer->state_flags &= ~USBI_TRANSFER_IN_FLIGHT;
@@ -1731,7 +1700,7 @@ void usbi_signal_transfer_completion(struct usbi_transfer *itransfer)
                pending_events = usbi_pending_events(ctx);
                list_add_tail(&itransfer->completed_list, &ctx->completed_transfers);
                if (!pending_events)
-                       usbi_signal_event(ctx);
+                       usbi_signal_event(&ctx->event);
                usbi_mutex_unlock(&ctx->event_data_lock);
        }
 }
@@ -1918,7 +1887,7 @@ void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx)
        pending_events = usbi_pending_events(ctx);
        ctx->event_flags |= USBI_EVENT_USER_INTERRUPT;
        if (!pending_events)
-               usbi_signal_event(ctx);
+               usbi_signal_event(&ctx->event);
 
        usbi_mutex_unlock(&ctx->event_data_lock);
 }
@@ -2068,8 +2037,76 @@ static int handle_timeouts(struct libusb_context *ctx)
        return r;
 }
 
-#ifdef HAVE_TIMERFD
-static int handle_timerfd_trigger(struct libusb_context *ctx)
+static int handle_event_trigger(struct libusb_context *ctx)
+{
+       struct list_head hotplug_msgs;
+       int r = 0;
+
+       usbi_dbg("event triggered");
+
+       list_init(&hotplug_msgs);
+
+       /* take the the event data lock while processing events */
+       usbi_mutex_lock(&ctx->event_data_lock);
+
+       /* check if someone modified the event sources */
+       if (ctx->event_flags & USBI_EVENT_EVENT_SOURCES_MODIFIED)
+               usbi_dbg("someone updated the event sources");
+
+       if (ctx->event_flags & USBI_EVENT_USER_INTERRUPT) {
+               usbi_dbg("someone purposefully interrupted");
+               ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT;
+       }
+
+       /* check if someone is closing a device */
+       if (ctx->device_close)
+               usbi_dbg("someone is closing a device");
+
+       /* check for any pending hotplug messages */
+       if (!list_empty(&ctx->hotplug_msgs)) {
+               usbi_dbg("hotplug message received");
+               list_cut(&hotplug_msgs, &ctx->hotplug_msgs);
+       }
+
+       /* complete any pending transfers */
+       while (r == 0 && !list_empty(&ctx->completed_transfers)) {
+               struct usbi_transfer *itransfer =
+                       list_first_entry(&ctx->completed_transfers, struct usbi_transfer, completed_list);
+
+               list_del(&itransfer->completed_list);
+               usbi_mutex_unlock(&ctx->event_data_lock);
+               r = usbi_backend.handle_transfer_completion(itransfer);
+               if (r)
+                       usbi_err(ctx, "backend handle_transfer_completion failed with error %d", r);
+               usbi_mutex_lock(&ctx->event_data_lock);
+       }
+
+       /* if no further pending events, clear the event */
+       if (!usbi_pending_events(ctx))
+               usbi_clear_event(&ctx->event);
+
+       usbi_mutex_unlock(&ctx->event_data_lock);
+
+       /* process the hotplug messages, if any */
+       while (!list_empty(&hotplug_msgs)) {
+               struct libusb_hotplug_message *message =
+                       list_first_entry(&hotplug_msgs, struct libusb_hotplug_message, list);
+
+               usbi_hotplug_match(ctx, message->device, message->event);
+
+               /* the device left, dereference the device */
+               if (message->event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
+                       libusb_unref_device(message->device);
+
+               list_del(&message->list);
+               free(message);
+       }
+
+       return r;
+}
+
+#ifdef HAVE_OS_TIMER
+static int handle_timer_trigger(struct libusb_context *ctx)
 {
        int r;
 
@@ -2081,7 +2118,7 @@ static int handle_timerfd_trigger(struct libusb_context *ctx)
                goto out;
 
        /* arm for next timeout */
-       r = arm_timerfd_for_next_timeout(ctx);
+       r = arm_timer_for_next_timeout(ctx);
 
 out:
        usbi_mutex_unlock(&ctx->flying_transfers_lock);
@@ -2093,81 +2130,38 @@ out:
  * doing the same thing. */
 static int handle_events(struct libusb_context *ctx, struct timeval *tv)
 {
-       int r;
-       struct usbi_pollfd *ipollfd;
-       usbi_nfds_t nfds = 0;
-       usbi_nfds_t internal_nfds;
-       struct pollfd *fds = NULL;
-       int timeout_ms;
+       struct usbi_reported_events reported_events;
+       int r, timeout_ms;
 
        /* prevent attempts to recursively handle events (e.g. calling into
         * libusb_handle_events() from within a hotplug or transfer callback) */
-       usbi_mutex_lock(&ctx->event_data_lock);
-       r = 0;
        if (usbi_handling_events(ctx))
-               r = LIBUSB_ERROR_BUSY;
-       else
-               usbi_start_event_handling(ctx);
-       usbi_mutex_unlock(&ctx->event_data_lock);
-
-       if (r)
-               return r;
-
-       /* there are certain fds that libusb uses internally, currently:
-        *
-        *   1) event pipe
-        *   2) timerfd
-        *
-        * the backend will never need to attempt to handle events on these fds, so
-        * we determine how many fds are in use internally for this context and when
-        * handle_events() is called in the backend, the pollfd list and count will
-        * be adjusted to skip over these internal fds */
-       if (usbi_using_timerfd(ctx))
-               internal_nfds = 2;
-       else
-               internal_nfds = 1;
+               return LIBUSB_ERROR_BUSY;
 
-       /* only reallocate the poll fds when the list of poll fds has been modified
-        * since the last poll, otherwise reuse them to save the additional overhead */
+       /* only reallocate the event source data when the list of event sources has
+        * been modified since the last handle_events(), otherwise reuse them to
+        * save the additional overhead */
        usbi_mutex_lock(&ctx->event_data_lock);
-       /* clean up removed poll fds */
-       cleanup_removed_pollfds(ctx);
-       if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED) {
-               int i = 0;
-
-               usbi_dbg("poll fds modified, reallocating");
+       if (ctx->event_flags & USBI_EVENT_EVENT_SOURCES_MODIFIED) {
+               usbi_dbg("event sources modified, reallocating event data");
 
-               free(ctx->pollfds);
-               ctx->pollfds = NULL;
+               /* free anything removed since we last ran */
+               cleanup_removed_event_sources(ctx);
 
-               /* sanity check - it is invalid for a context to have fewer than the
-                * required internal fds (memory corruption?) */
-               assert(ctx->pollfds_cnt >= internal_nfds);
-
-               ctx->pollfds = calloc(ctx->pollfds_cnt, sizeof(*ctx->pollfds));
-               if (!ctx->pollfds) {
+               r = usbi_alloc_event_data(ctx);
+               if (r) {
                        usbi_mutex_unlock(&ctx->event_data_lock);
-                       r = LIBUSB_ERROR_NO_MEM;
-                       goto done;
-               }
-
-               for_each_pollfd(ctx, ipollfd) {
-                       struct libusb_pollfd *pollfd = &ipollfd->pollfd;
-                       ctx->pollfds[i].fd = pollfd->fd;
-                       ctx->pollfds[i].events = pollfd->events;
-                       i++;
+                       return r;
                }
 
                /* reset the flag now that we have the updated list */
-               ctx->event_flags &= ~USBI_EVENT_POLLFDS_MODIFIED;
+               ctx->event_flags &= ~USBI_EVENT_EVENT_SOURCES_MODIFIED;
 
-               /* if no further pending events, clear the event pipe so that we do
-                * not immediately return from poll */
+               /* if no further pending events, clear the event so that we do
+                * not immediately return from the wait function */
                if (!usbi_pending_events(ctx))
-                       usbi_clear_event(ctx);
+                       usbi_clear_event(&ctx->event);
        }
-       fds = ctx->pollfds;
-       nfds = ctx->pollfds_cnt;
        usbi_mutex_unlock(&ctx->event_data_lock);
 
        timeout_ms = (int)(tv->tv_sec * 1000) + (tv->tv_usec / 1000);
@@ -2176,141 +2170,38 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
        if (tv->tv_usec % 1000)
                timeout_ms++;
 
-       usbi_dbg("poll() %d fds with timeout in %dms", (int)nfds, timeout_ms);
-       r = usbi_poll(fds, nfds, timeout_ms);
-       usbi_dbg("poll() returned %d", r);
-       if (r == 0) {
-               r = handle_timeouts(ctx);
-               goto done;
-       } else if (r == -1 && errno == EINTR) {
-               r = LIBUSB_ERROR_INTERRUPTED;
-               goto done;
-       } else if (r < 0) {
-               usbi_err(ctx, "poll failed, errno=%d", errno);
-               r = LIBUSB_ERROR_IO;
+       usbi_start_event_handling(ctx);
+
+       r = usbi_wait_for_events(ctx, &reported_events, timeout_ms);
+       if (r != LIBUSB_SUCCESS) {
+               if (r == LIBUSB_ERROR_TIMEOUT)
+                       r = handle_timeouts(ctx);
                goto done;
        }
 
-       /* fds[0] is always the event pipe */
-       if (fds[0].revents) {
-               struct list_head hotplug_msgs;
-               struct usbi_transfer *itransfer;
-               int hotplug_cb_deregistered = 0;
-               int ret = 0;
-
-               list_init(&hotplug_msgs);
-
-               usbi_dbg("caught a fish on the event pipe");
-
-               /* take the the event data lock while processing events */
-               usbi_mutex_lock(&ctx->event_data_lock);
-
-               /* check if someone added a new poll fd */
-               if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED)
-                       usbi_dbg("someone updated the poll fds");
-
-               if (ctx->event_flags & USBI_EVENT_USER_INTERRUPT) {
-                       usbi_dbg("someone purposely interrupted");
-                       ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT;
-               }
-
-               if (ctx->event_flags & USBI_EVENT_HOTPLUG_CB_DEREGISTERED) {
-                       usbi_dbg("someone unregistered a hotplug cb");
-                       ctx->event_flags &= ~USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
-                       hotplug_cb_deregistered = 1;
-               }
-
-               /* check if someone is closing a device */
-               if (ctx->device_close)
-                       usbi_dbg("someone is closing a device");
-
-               /* check for any pending hotplug messages */
-               if (!list_empty(&ctx->hotplug_msgs)) {
-                       usbi_dbg("hotplug message received");
-                       list_cut(&hotplug_msgs, &ctx->hotplug_msgs);
-               }
-
-               /* complete any pending transfers */
-               while (ret == 0 && !list_empty(&ctx->completed_transfers)) {
-                       itransfer = list_first_entry(&ctx->completed_transfers, struct usbi_transfer, completed_list);
-                       list_del(&itransfer->completed_list);
-                       usbi_mutex_unlock(&ctx->event_data_lock);
-                       ret = usbi_backend.handle_transfer_completion(itransfer);
-                       if (ret)
-                               usbi_err(ctx, "backend handle_transfer_completion failed with error %d", ret);
-                       usbi_mutex_lock(&ctx->event_data_lock);
-               }
-
-               /* if no further pending events, clear the event pipe */
-               if (!usbi_pending_events(ctx))
-                       usbi_clear_event(ctx);
-
-               usbi_mutex_unlock(&ctx->event_data_lock);
-
-               if (hotplug_cb_deregistered)
-                       usbi_hotplug_deregister(ctx, 0);
-
-               /* process the hotplug messages, if any */
-               while (!list_empty(&hotplug_msgs)) {
-                       struct libusb_hotplug_message *message =
-                               list_first_entry(&hotplug_msgs, struct libusb_hotplug_message, list);
-
-                       usbi_hotplug_match(ctx, message->device, message->event);
-
-                       /* the device left, dereference the device */
-                       if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message->event)
-                               libusb_unref_device(message->device);
-
-                       list_del(&message->list);
-                       free(message);
-               }
-
-               if (ret) {
+       if (reported_events.event_triggered) {
+               r = handle_event_trigger(ctx);
+               if (r) {
                        /* return error code */
-                       r = ret;
                        goto done;
                }
-
-               if (0 == --r)
-                       goto done;
        }
 
-#ifdef HAVE_TIMERFD
-       /* on timerfd configurations, fds[1] is the timerfd */
-       if (usbi_using_timerfd(ctx) && fds[1].revents) {
-               /* timerfd indicates that a timeout has expired */
-               int ret;
-               usbi_dbg("timerfd triggered");
-
-               ret = handle_timerfd_trigger(ctx);
-               if (ret < 0) {
+#ifdef HAVE_OS_TIMER
+       if (reported_events.timer_triggered) {
+               r = handle_timer_trigger(ctx);
+               if (r) {
                        /* return error code */
-                       r = ret;
                        goto done;
                }
-
-               if (0 == --r)
-                       goto done;
        }
 #endif
 
-       for_each_removed_pollfd(ctx, ipollfd) {
-               usbi_nfds_t n;
-
-               for (n = internal_nfds ; n < nfds ; n++) {
-                       if (ipollfd->pollfd.fd == fds[n].fd) {
-                               /* pollfd was removed between the creation of the fd
-                                * array and here. remove any triggered revent as
-                                * it is no longer relevant */
-                               usbi_dbg("pollfd %d was removed. ignoring raised events",
-                                        fds[n].fd);
-                               fds[n].revents = 0;
-                               break;
-                       }
-               }
-       }
+       if (!reported_events.num_ready)
+               goto done;
 
-       r = usbi_backend.handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r);
+       r = usbi_backend.handle_events(ctx, reported_events.event_data,
+               reported_events.event_data_count, reported_events.num_ready);
        if (r)
                usbi_err(ctx, "backend handle_events failed with error %d", r);
 
@@ -2555,13 +2446,8 @@ int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx,
  */
 int API_EXPORTED libusb_pollfds_handle_timeouts(libusb_context *ctx)
 {
-#ifdef HAVE_TIMERFD
        ctx = usbi_get_context(ctx);
-       return usbi_using_timerfd(ctx);
-#else
-       UNUSED(ctx);
-       return 0;
-#endif
+       return usbi_using_timer(ctx);
 }
 
 /** \ingroup libusb_poll
@@ -2601,7 +2487,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
        int r;
 
        ctx = usbi_get_context(ctx);
-       if (usbi_using_timerfd(ctx))
+       if (usbi_using_timer(ctx))
                return 0;
 
        usbi_mutex_lock(&ctx->flying_transfers_lock);
@@ -2673,80 +2559,92 @@ void API_EXPORTED libusb_set_pollfd_notifiers(libusb_context *ctx,
        libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
        void *user_data)
 {
+#if !defined(_WIN32) && !defined(__CYGWIN__)
        ctx = usbi_get_context(ctx);
        ctx->fd_added_cb = added_cb;
        ctx->fd_removed_cb = removed_cb;
        ctx->fd_cb_user_data = user_data;
+#else
+       usbi_err(ctx, "external polling of libusb's internal event sources " \
+               "is not yet supported on Windows");
+       UNUSED(added_cb);
+       UNUSED(removed_cb);
+       UNUSED(user_data);
+#endif
 }
 
 /*
  * Interrupt the iteration of the event handling thread, so that it picks
- * up the fd change. Callers of this function must hold the event_data_lock.
+ * up the event source change. Callers of this function must hold the event_data_lock.
  */
-static void usbi_fd_notification(struct libusb_context *ctx)
+static void usbi_event_source_notification(struct libusb_context *ctx)
 {
        int pending_events;
 
        /* Record that there is a new poll fd.
         * Only signal an event if there are no prior pending events. */
        pending_events = usbi_pending_events(ctx);
-       ctx->event_flags |= USBI_EVENT_POLLFDS_MODIFIED;
+       ctx->event_flags |= USBI_EVENT_EVENT_SOURCES_MODIFIED;
        if (!pending_events)
-               usbi_signal_event(ctx);
+               usbi_signal_event(&ctx->event);
 }
 
-/* Add a file descriptor to the list of file descriptors to be monitored.
- * events should be specified as a bitmask of events passed to poll(), e.g.
+/* Add an event source to the list of event sources to be monitored.
+ * poll_events should be specified as a bitmask of events passed to poll(), e.g.
  * POLLIN and/or POLLOUT. */
-int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events)
+int usbi_add_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle, short poll_events)
 {
-       struct usbi_pollfd *ipollfd = malloc(sizeof(*ipollfd));
-       if (!ipollfd)
+       struct usbi_event_source *ievent_source = malloc(sizeof(*ievent_source));
+
+       if (!ievent_source)
                return LIBUSB_ERROR_NO_MEM;
 
-       usbi_dbg("add fd %d events %d", fd, events);
-       ipollfd->pollfd.fd = fd;
-       ipollfd->pollfd.events = events;
+       usbi_dbg("add " USBI_OS_HANDLE_FORMAT_STRING " events %d", os_handle, poll_events);
+       ievent_source->data.os_handle = os_handle;
+       ievent_source->data.poll_events = poll_events;
        usbi_mutex_lock(&ctx->event_data_lock);
-       list_add_tail(&ipollfd->list, &ctx->ipollfds);
-       ctx->pollfds_cnt++;
-       usbi_fd_notification(ctx);
+       list_add_tail(&ievent_source->list, &ctx->event_sources);
+       usbi_event_source_notification(ctx);
        usbi_mutex_unlock(&ctx->event_data_lock);
 
+#if !defined(_WIN32) && !defined(__CYGWIN__)
        if (ctx->fd_added_cb)
-               ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
+               ctx->fd_added_cb(os_handle, poll_events, ctx->fd_cb_user_data);
+#endif
+
        return 0;
 }
 
-/* Remove a file descriptor from the list of file descriptors to be polled. */
-void usbi_remove_pollfd(struct libusb_context *ctx, int fd)
+/* Remove an event source from the list of event sources to be monitored. */
+void usbi_remove_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle)
 {
-       struct usbi_pollfd *ipollfd;
+       struct usbi_event_source *ievent_source;
        int found = 0;
 
-       usbi_dbg("remove fd %d", fd);
+       usbi_dbg("remove " USBI_OS_HANDLE_FORMAT_STRING, os_handle);
        usbi_mutex_lock(&ctx->event_data_lock);
-       for_each_pollfd(ctx, ipollfd) {
-               if (ipollfd->pollfd.fd == fd) {
+       for_each_event_source(ctx, ievent_source) {
+               if (ievent_source->data.os_handle == os_handle) {
                        found = 1;
                        break;
                }
        }
 
        if (!found) {
-               usbi_dbg("couldn't find fd %d to remove", fd);
+               usbi_dbg("couldn't find " USBI_OS_HANDLE_FORMAT_STRING " to remove", os_handle);
                usbi_mutex_unlock(&ctx->event_data_lock);
                return;
        }
 
-       list_del(&ipollfd->list);
-       list_add_tail(&ipollfd->list, &ctx->removed_ipollfds);
-       ctx->pollfds_cnt--;
-       usbi_fd_notification(ctx);
+       list_del(&ievent_source->list);
+       list_add_tail(&ievent_source->list, &ctx->removed_event_sources);
+       usbi_event_source_notification(ctx);
        usbi_mutex_unlock(&ctx->event_data_lock);
 
+#if !defined(_WIN32) && !defined(__CYGWIN__)
        if (ctx->fd_removed_cb)
-               ctx->fd_removed_cb(fd, ctx->fd_cb_user_data);
+               ctx->fd_removed_cb(os_handle, ctx->fd_cb_user_data);
+#endif
 }
 
 /** \ingroup libusb_poll
@@ -2768,29 +2666,36 @@ DEFAULT_VISIBILITY
 const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds(
        libusb_context *ctx)
 {
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(__CYGWIN__)
        struct libusb_pollfd **ret = NULL;
-       struct usbi_pollfd *ipollfd;
-       size_t i = 0;
+       struct usbi_event_source *ievent_source;
+       size_t i;
+
+       static_assert(sizeof(struct usbi_event_source_data) == sizeof(struct libusb_pollfd),
+                     "mismatch between usbi_event_source_data and libusb_pollfd sizes");
 
        ctx = usbi_get_context(ctx);
 
        usbi_mutex_lock(&ctx->event_data_lock);
 
-       ret = calloc(ctx->pollfds_cnt + 1, sizeof(struct libusb_pollfd *));
+       i = 0;
+       for_each_event_source(ctx, ievent_source)
+               i++;
+
+       ret = calloc(i + 1, sizeof(struct libusb_pollfd *));
        if (!ret)
                goto out;
 
-       for_each_pollfd(ctx, ipollfd)
-               ret[i++] = (struct libusb_pollfd *)ipollfd;
-       ret[ctx->pollfds_cnt] = NULL;
+       i = 0;
+       for_each_event_source(ctx, ievent_source)
+               ret[i++] = (struct libusb_pollfd *)ievent_source;
 
 out:
        usbi_mutex_unlock(&ctx->event_data_lock);
        return (const struct libusb_pollfd **)ret;
 #else
-       usbi_err(ctx, "external polling of libusb's internal descriptors "\
-               "is not yet supported on Windows platforms");
+       usbi_err(ctx, "external polling of libusb's internal event sources " \
+               "is not yet supported on Windows");
        return NULL;
 #endif
 }
@@ -2808,7 +2713,11 @@ out:
  */
 void API_EXPORTED libusb_free_pollfds(const struct libusb_pollfd **pollfds)
 {
+#if !defined(_WIN32) && !defined(__CYGWIN__)
        free((void *)pollfds);
+#else
+       UNUSED(pollfds);
+#endif
 }
 
 /* Backends may call this from handle_events to report disconnection of a
index 1677fdacc4848c6d21e4aeb3541e1aaf44697010..afeb27a7089e594c5f72b1b548ce468db90d1312 100644 (file)
 #define PTR_ALIGN(v) \
        (((v) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1))
 
-/* Internal abstraction for poll */
-#if defined(POLL_POSIX)
-#include "os/poll_posix.h"
-#elif defined(POLL_WINDOWS)
-#include "os/poll_windows.h"
+/* Internal abstraction for event handling */
+#if defined(EVENTS_POSIX)
+#include "os/events_posix.h"
+#elif defined(EVENTS_WINDOWS)
+#include "os/events_windows.h"
 #endif
 
 /* Internal abstraction for thread synchronization */
@@ -305,8 +305,14 @@ struct libusb_context {
        libusb_log_cb log_handler;
 #endif
 
-       /* internal event pipe, used for signalling occurrence of an internal event. */
-       int event_pipe[2];
+       /* used for signalling occurrence of an internal event. */
+       usbi_event_t event;
+
+#ifdef HAVE_OS_TIMER
+       /* used for timeout handling, if supported by OS.
+        * this timer is maintained to trigger on the next pending timeout */
+       usbi_timer_t timer;
+#endif
 
        struct list_head usb_devs;
        usbi_mutex_t usb_devs_lock;
@@ -330,10 +336,12 @@ struct libusb_context {
         * take this lock first */
        usbi_mutex_t flying_transfers_lock;
 
+#if !defined(_WIN32) && !defined(__CYGWIN__)
        /* user callbacks for pollfd changes */
        libusb_pollfd_added_cb fd_added_cb;
        libusb_pollfd_removed_cb fd_removed_cb;
        void *fd_cb_user_data;
+#endif
 
        /* ensures that only one thread is handling events at any one time */
        usbi_mutex_t events_lock;
@@ -361,14 +369,17 @@ struct libusb_context {
         * in order to safely close a device. Protected by event_data_lock. */
        unsigned int device_close;
 
-       /* list and count of poll fds and an array of poll fd structures that is
-        * (re)allocated as necessary prior to polling. Protected by event_data_lock. */
-       struct list_head ipollfds;
-        /* list of pollfds that have been removed. keeps track of pollfd changes
-         * between the poll call and */
-        struct list_head removed_ipollfds;
-       struct pollfd *pollfds;
-       usbi_nfds_t pollfds_cnt;
+       /* A list of currently active event sources. Protected by event_data_lock. */
+       struct list_head event_sources;
+
+       /* A list of event sources that have been removed since the last time
+        * event sources were waited on. Protected by event_data_lock. */
+       struct list_head removed_event_sources;
+
+       /* A pointer and count to platform-specific data used for monitoring event
+        * sources. Only accessed during event handling. */
+       void *event_data;
+       unsigned int event_data_cnt;
 
        /* A list of pending hotplug messages. Protected by event_data_lock. */
        struct list_head hotplug_msgs;
@@ -376,12 +387,6 @@ struct libusb_context {
        /* A list of pending completed transfers. Protected by event_data_lock. */
        struct list_head completed_transfers;
 
-#ifdef HAVE_TIMERFD
-       /* used for timeout handling, if supported by OS.
-        * this timerfd is maintained to trigger on the next pending timeout */
-       int timerfd;
-#endif
-
        struct list_head list;
 };
 
@@ -393,8 +398,8 @@ static inline struct libusb_context *usbi_get_context(struct libusb_context *ctx
 }
 
 enum usbi_event_flags {
-       /* The list of pollfds has been modified */
-       USBI_EVENT_POLLFDS_MODIFIED = 1U << 0,
+       /* The list of event sources has been modified */
+       USBI_EVENT_EVENT_SOURCES_MODIFIED = 1U << 0,
 
        /* The user has interrupted the event handler */
        USBI_EVENT_USER_INTERRUPT = 1U << 1,
@@ -428,16 +433,6 @@ static inline int usbi_pending_events(struct libusb_context *ctx)
               !list_empty(&ctx->completed_transfers);
 }
 
-static inline int usbi_using_timerfd(struct libusb_context *ctx)
-{
-#ifdef HAVE_TIMERFD
-       return ctx->timerfd >= 0;
-#else
-       UNUSED(ctx);
-       return 0;
-#endif
-}
-
 struct libusb_device {
        /* lock protects refcnt, everything else is finalized at initialization
         * time */
@@ -651,18 +646,55 @@ void usbi_signal_transfer_completion(struct usbi_transfer *itransfer);
 void usbi_connect_device(struct libusb_device *dev);
 void usbi_disconnect_device(struct libusb_device *dev);
 
-int usbi_signal_event(struct libusb_context *ctx);
-int usbi_clear_event(struct libusb_context *ctx);
+struct usbi_event_source {
+       struct usbi_event_source_data {
+               usbi_os_handle_t os_handle;
+               short poll_events;
+       } data;
+       struct list_head list;
+};
 
-struct usbi_pollfd {
-       /* must come first */
-       struct libusb_pollfd pollfd;
+int usbi_add_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle,
+       short poll_events);
+void usbi_remove_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle);
 
-       struct list_head list;
+/* OS event abstraction */
+
+int usbi_create_event(usbi_event_t *event);
+void usbi_destroy_event(usbi_event_t *event);
+void usbi_signal_event(usbi_event_t *event);
+void usbi_clear_event(usbi_event_t *event);
+
+#ifdef HAVE_OS_TIMER
+int usbi_create_timer(usbi_timer_t *timer);
+void usbi_destroy_timer(usbi_timer_t *timer);
+int usbi_arm_timer(usbi_timer_t *timer, const struct timespec *timeout);
+int usbi_disarm_timer(usbi_timer_t *timer);
+#endif
+
+static inline int usbi_using_timer(struct libusb_context *ctx)
+{
+#ifdef HAVE_OS_TIMER
+       return usbi_timer_valid(&ctx->timer);
+#else
+       UNUSED(ctx);
+       return 0;
+#endif
+}
+
+struct usbi_reported_events {
+       unsigned int event_triggered:1;
+#ifdef HAVE_OS_TIMER
+       unsigned int timer_triggered:1;
+#endif
+       void *event_data;
+       unsigned int event_data_count;
+       unsigned int num_ready;
 };
 
-int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events);
-void usbi_remove_pollfd(struct libusb_context *ctx, int fd);
+int usbi_alloc_event_data(struct libusb_context *ctx);
+int usbi_wait_for_events(struct libusb_context *ctx,
+       struct usbi_reported_events *reported_events, int timeout_ms);
 
 /* accessor functions for structure private data */
 
@@ -819,7 +851,7 @@ struct usbi_os_backend {
         * and other operations so that those operations can happen (hopefully)
         * without hiccup. This is also a good place to inform libusb that it
         * should monitor certain file descriptors related to this device -
-        * see the usbi_add_pollfd() function.
+        * see the usbi_add_event_source() function.
         *
         * Your backend should also initialize the device structure
         * (dev_handle->dev), which is NULL at the beginning of the call.
@@ -848,7 +880,7 @@ struct usbi_os_backend {
         * and other operations so that those operations can happen (hopefully)
         * without hiccup. This is also a good place to inform libusb that it
         * should monitor certain file descriptors related to this device -
-        * see the usbi_add_pollfd() function.
+        * see the usbi_add_event_source() function.
         *
         * This function should not generate any bus I/O and should not block.
         *
@@ -869,9 +901,9 @@ struct usbi_os_backend {
 
        /* Close a device such that the handle cannot be used again. Your backend
         * should destroy any resources that were allocated in the open path.
-        * This may also be a good place to call usbi_remove_pollfd() to inform
-        * libusb of any file descriptors associated with this device that should
-        * no longer be monitored.
+        * This may also be a good place to call usbi_remove_event_source() to
+        * inform libusb of any event sources associated with this device that
+        * should no longer be monitored.
         *
         * This function is called when the user closes a device handle.
         */
@@ -1166,21 +1198,22 @@ struct usbi_os_backend {
         */
        void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
 
-       /* Handle any pending events on file descriptors. Optional.
+       /* Handle any pending events on event sources. Optional.
         *
-        * Provide this function when file descriptors directly indicate device
-        * or transfer activity. If your backend does not have such file descriptors,
+        * Provide this function when event sources directly indicate device
+        * or transfer activity. If your backend does not have such event sources,
         * implement the handle_transfer_completion function below.
         *
         * This involves monitoring any active transfers and processing their
         * completion or cancellation.
         *
-        * The function is passed an array of pollfd structures (size nfds)
-        * as a result of the poll() system call. The num_ready parameter
-        * indicates the number of file descriptors that have reported events
-        * (i.e. the poll() return value). This should be enough information
-        * for you to determine which actions need to be taken on the currently
-        * active transfers.
+        * The function is passed a pointer that represents platform-specific
+        * data for monitoring event sources (size count). This data is to be
+        * (re)allocated as necessary when event sources are modified.
+        * The num_ready parameter indicates the number of event sources that
+        * have reported events. This should be enough information for you to
+        * determine which actions need to be taken on the currently active
+        * transfers.
         *
         * For any cancelled transfers, call usbi_handle_transfer_cancellation().
         * For completed transfers, call usbi_handle_transfer_completion().
@@ -1199,13 +1232,13 @@ struct usbi_os_backend {
         * Return 0 on success, or a LIBUSB_ERROR code on failure.
         */
        int (*handle_events)(struct libusb_context *ctx,
-               struct pollfd *fds, usbi_nfds_t nfds, int num_ready);
+               void *event_data, unsigned int count, unsigned int num_ready);
 
        /* Handle transfer completion. Optional.
         *
-        * Provide this function when there are no file descriptors available
-        * that directly indicate device or transfer activity. If your backend does
-        * have such file descriptors, implement the handle_events function above.
+        * Provide this function when there are no event sources available that
+        * directly indicate device or transfer activity. If your backend does
+        * have such event sources, implement the handle_events function above.
         *
         * Your backend must tell the library when a transfer has completed by
         * calling usbi_signal_transfer_completion(). You should store any private
@@ -1274,14 +1307,14 @@ extern usbi_mutex_static_t active_contexts_lock;
 #define for_each_transfer_safe(ctx, t, n) \
        for_each_safe_helper(t, n, &(ctx)->flying_transfers, struct usbi_transfer)
 
-#define for_each_pollfd(ctx, p) \
-       for_each_helper(p, &(ctx)->ipollfds, struct usbi_pollfd)
+#define for_each_event_source(ctx, e) \
+       for_each_helper(e, &(ctx)->event_sources, struct usbi_event_source)
 
-#define for_each_removed_pollfd(ctx, p) \
-       for_each_helper(p, &(ctx)->removed_ipollfds, struct usbi_pollfd)
+#define for_each_removed_event_source(ctx, e) \
+       for_each_helper(e, &(ctx)->removed_event_sources, struct usbi_event_source)
 
-#define for_each_removed_pollfd_safe(ctx, p, n) \
-       for_each_safe_helper(p, n, &(ctx)->removed_ipollfds, struct usbi_pollfd)
+#define for_each_removed_event_source_safe(ctx, e, n) \
+       for_each_safe_helper(e, n, &(ctx)->removed_event_sources, struct usbi_event_source)
 
 #ifdef __cplusplus
 }
diff --git a/libusb/os/events_posix.c b/libusb/os/events_posix.c
new file mode 100644 (file)
index 0000000..01064af
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * libusb event abstraction on POSIX platforms
+ *
+ * Copyright Â© 2020 Chris Dickens <christopher.a.dickens@gmail.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libusbi.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_TIMERFD
+#include <sys/timerfd.h>
+#endif
+#include <unistd.h>
+
+#ifdef HAVE_NFDS_T
+typedef nfds_t usbi_nfds_t;
+#else
+typedef unsigned int usbi_nfds_t;
+#endif
+
+int usbi_create_event(usbi_event_t *event)
+{
+#if defined(HAVE_PIPE2)
+       int ret = pipe2(event->pipefd, O_CLOEXEC);
+#else
+       int ret = pipe(event->pipefd);
+#endif
+
+       if (ret != 0) {
+               usbi_err(NULL, "failed to create pipe, errno=%d", errno);
+               return LIBUSB_ERROR_OTHER;
+       }
+
+#if !defined(HAVE_PIPE2) && defined(FD_CLOEXEC)
+       ret = fcntl(event->pipefd[0], F_GETFD);
+       if (ret == -1) {
+               usbi_err(NULL, "failed to get pipe fd flags, errno=%d", errno);
+               goto err_close_pipe;
+       }
+       ret = fcntl(event->pipefd[0], F_SETFD, ret | FD_CLOEXEC);
+       if (ret == -1) {
+               usbi_err(NULL, "failed to set pipe fd flags, errno=%d", errno);
+               goto err_close_pipe;
+       }
+
+       ret = fcntl(event->pipefd[1], F_GETFD);
+       if (ret == -1) {
+               usbi_err(NULL, "failed to get pipe fd flags, errno=%d", errno);
+               goto err_close_pipe;
+       }
+       ret = fcntl(event->pipefd[1], F_SETFD, ret | FD_CLOEXEC);
+       if (ret == -1) {
+               usbi_err(NULL, "failed to set pipe fd flags, errno=%d", errno);
+               goto err_close_pipe;
+       }
+#endif
+
+       ret = fcntl(event->pipefd[1], F_GETFL);
+       if (ret == -1) {
+               usbi_err(NULL, "failed to get pipe fd status flags, errno=%d", errno);
+               goto err_close_pipe;
+       }
+       ret = fcntl(event->pipefd[1], F_SETFL, ret | O_NONBLOCK);
+       if (ret == -1) {
+               usbi_err(NULL, "failed to set pipe fd status flags, errno=%d", errno);
+               goto err_close_pipe;
+       }
+
+       return 0;
+
+err_close_pipe:
+       close(event->pipefd[1]);
+       close(event->pipefd[0]);
+       return LIBUSB_ERROR_OTHER;
+}
+
+void usbi_destroy_event(usbi_event_t *event)
+{
+       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);
+}
+
+void usbi_signal_event(usbi_event_t *event)
+{
+       unsigned char dummy = 1;
+       ssize_t r;
+
+       r = write(event->pipefd[1], &dummy, sizeof(dummy));
+       if (r != sizeof(dummy))
+               usbi_warn(NULL, "pipe write failed");
+}
+
+void usbi_clear_event(usbi_event_t *event)
+{
+       unsigned char dummy;
+       ssize_t r;
+
+       r = read(event->pipefd[0], &dummy, sizeof(dummy));
+       if (r != sizeof(dummy))
+               usbi_warn(NULL, "pipe read failed");
+}
+
+#ifdef HAVE_TIMERFD
+int usbi_create_timer(usbi_timer_t *timer)
+{
+       timer->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
+       if (timer->timerfd == -1) {
+               usbi_warn(NULL, "failed to create timerfd, errno=%d", errno);
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       return 0;
+}
+
+void usbi_destroy_timer(usbi_timer_t *timer)
+{
+       if (close(timer->timerfd) == -1)
+               usbi_warn(NULL, "failed to close timerfd, errno=%d", errno);
+}
+
+int usbi_arm_timer(usbi_timer_t *timer, const struct timespec *timeout)
+{
+       const struct itimerspec it = { { 0, 0 }, { timeout->tv_sec, timeout->tv_nsec } };
+
+       if (timerfd_settime(timer->timerfd, TFD_TIMER_ABSTIME, &it, NULL) == -1) {
+               usbi_warn(NULL, "failed to arm timerfd, errno=%d", errno);
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       return 0;
+}
+
+int usbi_disarm_timer(usbi_timer_t *timer)
+{
+       const struct itimerspec it = { { 0, 0 }, { 0, 0 } };
+
+       if (timerfd_settime(timer->timerfd, 0, &it, NULL) == -1) {
+               usbi_warn(NULL, "failed to disarm timerfd, errno=%d", errno);
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       return 0;
+}
+#endif
+
+int usbi_alloc_event_data(struct libusb_context *ctx)
+{
+       struct usbi_event_source *ievent_source;
+       struct pollfd *fds;
+       size_t i = 0;
+
+       if (ctx->event_data) {
+               free(ctx->event_data);
+               ctx->event_data = NULL;
+       }
+
+       ctx->event_data_cnt = 0;
+       for_each_event_source(ctx, ievent_source)
+               ctx->event_data_cnt++;
+
+       fds = calloc(ctx->event_data_cnt, sizeof(*fds));
+       if (!fds)
+               return LIBUSB_ERROR_NO_MEM;
+
+       for_each_event_source(ctx, ievent_source) {
+               fds[i].fd = ievent_source->data.os_handle;
+               fds[i].events = ievent_source->data.poll_events;
+               i++;
+       }
+
+       ctx->event_data = fds;
+       return 0;
+}
+
+int usbi_wait_for_events(struct libusb_context *ctx,
+       struct usbi_reported_events *reported_events, int timeout_ms)
+{
+       struct pollfd *fds = ctx->event_data;
+       usbi_nfds_t nfds = (usbi_nfds_t)ctx->event_data_cnt;
+       int internal_fds, num_ready;
+
+       usbi_dbg("poll() %u fds with timeout in %dms", (unsigned int)nfds, timeout_ms);
+       num_ready = poll(fds, nfds, timeout_ms);
+       usbi_dbg("poll() returned %d", num_ready);
+       if (num_ready == 0) {
+               if (usbi_using_timer(ctx))
+                       goto done;
+               return LIBUSB_ERROR_TIMEOUT;
+       } else if (num_ready == -1) {
+               if (errno == EINTR)
+                       return LIBUSB_ERROR_INTERRUPTED;
+               usbi_err(ctx, "poll() failed, errno=%d", errno);
+               return LIBUSB_ERROR_IO;
+       }
+
+       /* fds[0] is always the internal signalling event */
+       if (fds[0].revents) {
+               reported_events->event_triggered = 1;
+               num_ready--;
+       } else {
+               reported_events->event_triggered = 0;
+       }
+
+#ifdef HAVE_OS_TIMER
+       /* on timer configurations, fds[1] is the timer */
+       if (usbi_using_timer(ctx) && fds[1].revents) {
+               reported_events->timer_triggered = 1;
+               num_ready--;
+       } else {
+               reported_events->timer_triggered = 0;
+       }
+#endif
+
+       assert(num_ready > 0);
+       if (!num_ready)
+               goto done;
+
+       /* the backend will never need to attempt to handle events on the
+        * library's internal file descriptors, so we determine how many are
+        * in use internally for this context and skip these when passing any
+        * remaining pollfds to the backend. */
+       internal_fds = usbi_using_timer(ctx) ? 2 : 1;
+       fds += internal_fds;
+       nfds -= internal_fds;
+
+       usbi_mutex_lock(&ctx->event_data_lock);
+       if (ctx->event_flags & USBI_EVENT_EVENT_SOURCES_MODIFIED) {
+               struct usbi_event_source *ievent_source;
+
+               for_each_removed_event_source(ctx, ievent_source) {
+                       usbi_nfds_t n;
+
+                       for (n = 0; n < nfds; n++) {
+                               if (ievent_source->data.os_handle != fds[n].fd)
+                                       continue;
+                               if (!fds[n].revents)
+                                       continue;
+                               /* pollfd was removed between the creation of the fds array and
+                                * here. remove triggered revent as it is no longer relevant. */
+                               usbi_dbg("fd %d was removed, ignoring raised events", fds[n].fd);
+                               fds[n].revents = 0;
+                               num_ready--;
+                               break;
+                       }
+               }
+       }
+       usbi_mutex_unlock(&ctx->event_data_lock);
+
+       if (num_ready) {
+               assert(num_ready > 0);
+               reported_events->event_data = fds;
+               reported_events->event_data_count = (unsigned int)nfds;
+       }
+
+done:
+       reported_events->num_ready = num_ready;
+       return LIBUSB_SUCCESS;
+}
diff --git a/libusb/os/events_posix.h b/libusb/os/events_posix.h
new file mode 100644 (file)
index 0000000..401de04
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * libusb event abstraction on POSIX platforms
+ *
+ * Copyright Â© 2020 Chris Dickens <christopher.a.dickens@gmail.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBUSB_EVENTS_POSIX_H
+#define LIBUSB_EVENTS_POSIX_H
+
+#include <poll.h>
+
+typedef int usbi_os_handle_t;
+#define USBI_OS_HANDLE_FORMAT_STRING   "fd %d"
+
+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 } }
+
+#ifdef HAVE_TIMERFD
+#define HAVE_OS_TIMER 1
+typedef struct usbi_timer {
+       int timerfd;
+} usbi_timer_t;
+#define USBI_TIMER_OS_HANDLE(t)        ((t)->timerfd)
+#define USBI_TIMER_POLL_EVENTS POLLIN
+
+static inline int usbi_timer_valid(usbi_timer_t *timer)
+{
+       return timer->timerfd >= 0;
+}
+#endif
+
+#endif
diff --git a/libusb/os/events_windows.c b/libusb/os/events_windows.c
new file mode 100644 (file)
index 0000000..9f120bb
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * libusb event abstraction on Microsoft Windows
+ *
+ * Copyright Â© 2020 Chris Dickens <christopher.a.dickens@gmail.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "libusbi.h"
+#include "windows_common.h"
+
+int usbi_create_event(usbi_event_t *event)
+{
+       event->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+       if (event->hEvent == NULL) {
+               usbi_err(NULL, "CreateEvent failed: %s", windows_error_str(0));
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       return 0;
+}
+
+void usbi_destroy_event(usbi_event_t *event)
+{
+       if (!CloseHandle(event->hEvent))
+               usbi_warn(NULL, "CloseHandle failed: %s", windows_error_str(0));
+}
+
+void usbi_signal_event(usbi_event_t *event)
+{
+       if (!SetEvent(event->hEvent))
+               usbi_warn(NULL, "SetEvent failed: %s", windows_error_str(0));
+}
+
+void usbi_clear_event(usbi_event_t *event)
+{
+       if (!ResetEvent(event->hEvent))
+               usbi_warn(NULL, "ResetEvent failed: %s", windows_error_str(0));
+}
+
+#ifdef HAVE_OS_TIMER
+int usbi_create_timer(usbi_timer_t *timer)
+{
+       timer->hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
+       if (timer->hTimer == NULL) {
+               usbi_warn(NULL, "CreateWaitableTimer failed: %s", windows_error_str(0));
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       return 0;
+}
+
+void usbi_destroy_timer(usbi_timer_t *timer)
+{
+       if (!CloseHandle(timer->hTimer))
+               usbi_warn(NULL, "CloseHandle failed: %s", windows_error_str(0));
+}
+
+int usbi_arm_timer(usbi_timer_t *timer, const struct timespec *timeout)
+{
+       struct timespec systime, remaining;
+       FILETIME filetime;
+       LARGE_INTEGER dueTime;
+       int r;
+
+       /* Transfer timeouts are based on the monotonic clock and the waitable
+        * timers on the system clock. This requires a conversion between the
+        * two, so we calculate the remaining time relative to the monotonic
+        * clock and calculate an absolute system time for the timer expiration.
+        * Note that if the timeout has already passed, the remaining time will
+        * be negative and thus an absolute system time in the past will be set.
+        * This works just as intended because the timer becomes signalled
+        * immediately. */
+       r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &systime);
+       if (r < 0) {
+               usbi_err(NULL, "failed to read monotonic clock");
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       TIMESPEC_SUB(timeout, &systime, &remaining);
+
+       GetSystemTimeAsFileTime(&filetime);
+       dueTime.LowPart = filetime.dwLowDateTime;
+       dueTime.HighPart = filetime.dwHighDateTime;
+       dueTime.QuadPart += (remaining.tv_sec * 10000000LL) + (remaining.tv_nsec / 100LL);
+
+       if (!SetWaitableTimer(timer->hTimer, &dueTime, 0, NULL, NULL, FALSE)) {
+               usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0));
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       return 0;
+}
+
+int usbi_disarm_timer(usbi_timer_t *timer)
+{
+       LARGE_INTEGER dueTime;
+
+       /* A manual-reset waitable timer will stay in the signalled state until
+        * another call to SetWaitableTimer() is made. It is possible that the
+        * timer has already expired by the time we come in to disarm it, so to
+        * be entirely sure the timer is disarmed and not in the signalled state,
+        * we will set it with an impossibly large expiration and immediately
+        * cancel. */
+       dueTime.QuadPart = LLONG_MAX;
+       if (!SetWaitableTimer(timer->hTimer, &dueTime, 0, NULL, NULL, FALSE)) {
+               usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0));
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       if (!CancelWaitableTimer(timer->hTimer)) {
+               usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0));
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       return 0;
+}
+#endif
+
+int usbi_alloc_event_data(struct libusb_context *ctx)
+{
+       struct usbi_event_source *ievent_source;
+       HANDLE *handles;
+       size_t i = 0;
+
+       /* Event sources are only added during usbi_io_init(). We should not
+        * be running this function again if the event data has already been
+        * allocated. */
+       if (ctx->event_data) {
+               usbi_warn(ctx, "program assertion failed - event data already allocated");
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       ctx->event_data_cnt = 0;
+       for_each_event_source(ctx, ievent_source)
+               ctx->event_data_cnt++;
+
+       /* We only expect up to two HANDLEs to wait on, one for the internal
+        * signalling event and the other for the timer. */
+       if (ctx->event_data_cnt != 1 && ctx->event_data_cnt != 2) {
+               usbi_err(ctx, "program assertion failed - expected exactly 1 or 2 HANDLEs");
+               return LIBUSB_ERROR_OTHER;
+       }
+
+       handles = calloc(ctx->event_data_cnt, sizeof(HANDLE));
+       if (!handles)
+               return LIBUSB_ERROR_NO_MEM;
+
+       for_each_event_source(ctx, ievent_source) {
+               handles[i] = ievent_source->data.os_handle;
+               i++;
+       }
+
+       ctx->event_data = handles;
+       return 0;
+}
+
+int usbi_wait_for_events(struct libusb_context *ctx,
+       struct usbi_reported_events *reported_events, int timeout_ms)
+{
+       HANDLE *handles = ctx->event_data;
+       DWORD num_handles = (DWORD)ctx->event_data_cnt;
+       DWORD result;
+
+       usbi_dbg("WaitForMultipleObjects() for %lu HANDLEs with timeout in %dms", ULONG_CAST(num_handles), timeout_ms);
+       result = WaitForMultipleObjects(num_handles, handles, FALSE, (DWORD)timeout_ms);
+       usbi_dbg("WaitForMultipleObjects() returned %lu", ULONG_CAST(result));
+       if (result == WAIT_TIMEOUT) {
+               if (usbi_using_timer(ctx))
+                       goto done;
+               return LIBUSB_ERROR_TIMEOUT;
+       } else if (result == WAIT_FAILED) {
+               usbi_err(ctx, "WaitForMultipleObjects() failed: %s", windows_error_str(0));
+               return LIBUSB_ERROR_IO;
+       }
+
+       result -= WAIT_OBJECT_0;
+
+       /* handles[0] is always the internal signalling event */
+       if (result == 0)
+               reported_events->event_triggered = 1;
+       else
+               reported_events->event_triggered = 0;
+
+#ifdef HAVE_OS_TIMER
+       /* on timer configurations, handles[1] is the timer */
+       if (usbi_using_timer(ctx)) {
+               /* The WaitForMultipleObjects() function reports the index of
+                * the first object that became signalled. If the internal
+                * signalling event was reported, we need to also check and
+                * report whether the timer is in the signalled state. */
+               if (result == 1 || WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0)
+                       reported_events->timer_triggered = 1;
+               else
+                       reported_events->timer_triggered = 0;
+       } else {
+               reported_events->timer_triggered = 0;
+       }
+#endif
+
+done:
+       /* no events are ever reported to the backend */
+       reported_events->num_ready = 0;
+       return LIBUSB_SUCCESS;
+}
diff --git a/libusb/os/events_windows.h b/libusb/os/events_windows.h
new file mode 100644 (file)
index 0000000..0c5e0b0
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * libusb event abstraction on Microsoft Windows
+ *
+ * Copyright Â© 2020 Chris Dickens <christopher.a.dickens@gmail.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBUSB_EVENTS_WINDOWS_H
+#define LIBUSB_EVENTS_WINDOWS_H
+
+typedef HANDLE usbi_os_handle_t;
+#define USBI_OS_HANDLE_FORMAT_STRING   "HANDLE %p"
+
+typedef struct usbi_event {
+       HANDLE hEvent;
+} usbi_event_t;
+#define USBI_EVENT_OS_HANDLE(e)        ((e)->hEvent)
+#define USBI_EVENT_POLL_EVENTS 0
+#define USBI_INVALID_EVENT     { INVALID_HANDLE_VALUE }
+
+#define HAVE_OS_TIMER 1
+typedef struct usbi_timer {
+       HANDLE hTimer;
+} usbi_timer_t;
+#define USBI_TIMER_OS_HANDLE(t)        ((t)->hTimer)
+#define USBI_TIMER_POLL_EVENTS 0
+
+static inline int usbi_timer_valid(usbi_timer_t *timer)
+{
+       return timer->hTimer != NULL;
+}
+
+#endif
index 9917df266e8779832b8d259ede17dd9846592d30..77c83c5f8db7407250939d7211b980e0195ed628 100644 (file)
@@ -48,7 +48,7 @@
 #endif
 
 static int linux_netlink_socket = -1;
-static int netlink_control_pipe[2] = { -1, -1 };
+static usbi_event_t netlink_control_event = USBI_INVALID_EVENT;
 static pthread_t libusb_linux_event_thread;
 
 static void *linux_netlink_event_thread_main(void *arg);
@@ -125,25 +125,23 @@ int linux_netlink_start_event_monitor(void)
                goto err_close_socket;
        }
 
-       ret = usbi_pipe(netlink_control_pipe);
+       ret = usbi_create_event(&netlink_control_event);
        if (ret) {
-               usbi_err(NULL, "failed to create netlink control pipe");
+               usbi_err(NULL, "failed to create netlink control event");
                goto err_close_socket;
        }
 
        ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
        if (ret != 0) {
                usbi_err(NULL, "failed to create netlink event thread (%d)", ret);
-               goto err_close_pipe;
+               goto err_destroy_event;
        }
 
        return LIBUSB_SUCCESS;
 
-err_close_pipe:
-       close(netlink_control_pipe[0]);
-       close(netlink_control_pipe[1]);
-       netlink_control_pipe[0] = -1;
-       netlink_control_pipe[1] = -1;
+err_destroy_event:
+       usbi_destroy_event(&netlink_control_event);
+       netlink_control_event = (usbi_event_t)USBI_INVALID_EVENT;
 err_close_socket:
        close(linux_netlink_socket);
        linux_netlink_socket = -1;
@@ -153,28 +151,23 @@ err:
 
 int linux_netlink_stop_event_monitor(void)
 {
-       char dummy = 1;
-       ssize_t r;
+       int ret;
 
        assert(linux_netlink_socket != -1);
 
-       /* Write some dummy data to the control pipe and
-        * wait for the thread to exit */
-       r = write(netlink_control_pipe[1], &dummy, sizeof(dummy));
-       if (r <= 0)
-               usbi_warn(NULL, "netlink control pipe signal failed");
+       /* Signal the control event and wait for the thread to exit */
+       usbi_signal_event(&netlink_control_event);
+
+       ret = pthread_join(libusb_linux_event_thread, NULL);
+       if (ret)
+               usbi_warn(NULL, "failed to join netlink event thread (%d)", ret);
 
-       pthread_join(libusb_linux_event_thread, NULL);
+       usbi_destroy_event(&netlink_control_event);
+       netlink_control_event = (usbi_event_t)USBI_INVALID_EVENT;
 
        close(linux_netlink_socket);
        linux_netlink_socket = -1;
 
-       /* close and reset control pipe */
-       close(netlink_control_pipe[0]);
-       close(netlink_control_pipe[1]);
-       netlink_control_pipe[0] = -1;
-       netlink_control_pipe[1] = -1;
-
        return LIBUSB_SUCCESS;
 }
 
@@ -353,15 +346,13 @@ static int linux_netlink_read_message(void)
 
 static void *linux_netlink_event_thread_main(void *arg)
 {
-       char dummy;
-       int r;
-       ssize_t nb;
        struct pollfd fds[] = {
-               { .fd = netlink_control_pipe[0],
-                 .events = POLLIN },
+               { .fd = USBI_EVENT_OS_HANDLE(&netlink_control_event),
+                 .events = USBI_EVENT_POLL_EVENTS },
                { .fd = linux_netlink_socket,
                  .events = POLLIN },
        };
+       int r;
 
        UNUSED(arg);
 
@@ -373,19 +364,20 @@ static void *linux_netlink_event_thread_main(void *arg)
 
        usbi_dbg("netlink event thread entering");
 
-       while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) {
-               if (r < 0) {
-                       /* temporary failure */
-                       continue;
+       while (1) {
+               r = poll(fds, 2, -1);
+               if (r == -1) {
+                       /* check for temporary failure */
+                       if (errno == EINTR)
+                               continue;
+                       usbi_err(NULL, "poll() failed, errno=%d", errno);
+                       break;
                }
-               if (fds[0].revents & POLLIN) {
-                       /* activity on control pipe, read the byte and exit */
-                       nb = read(netlink_control_pipe[0], &dummy, sizeof(dummy));
-                       if (nb <= 0)
-                               usbi_warn(NULL, "netlink control pipe read failed");
+               if (fds[0].revents) {
+                       /* activity on control event, exit */
                        break;
                }
-               if (fds[1].revents & POLLIN) {
+               if (fds[1].revents) {
                        usbi_mutex_static_lock(&linux_hotplug_lock);
                        linux_netlink_read_message();
                        usbi_mutex_static_unlock(&linux_hotplug_lock);
index e8fb19852ef9609e4401b56db08d95d23bb23858..beb2f05c0a29a60709cb0ce6b71bfe771e5e37c9 100644 (file)
@@ -34,7 +34,7 @@
 /* udev context */
 static struct udev *udev_ctx = NULL;
 static int udev_monitor_fd = -1;
-static int udev_control_pipe[2] = {-1, -1};
+static usbi_event_t udev_control_event = USBI_INVALID_EVENT;
 static struct udev_monitor *udev_monitor = NULL;
 static pthread_t linux_event_thread;
 
@@ -100,23 +100,23 @@ int linux_udev_start_event_monitor(void)
                }
        }
 
-       r = usbi_pipe(udev_control_pipe);
+       r = usbi_create_event(&udev_control_event);
        if (r) {
-               usbi_err(NULL, "could not create udev control pipe");
+               usbi_err(NULL, "failed to create udev control event");
                goto err_free_monitor;
        }
 
        r = pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL);
        if (r) {
-               usbi_err(NULL, "creating hotplug event thread (%d)", r);
-               goto err_close_pipe;
+               usbi_err(NULL, "failed to create hotplug event thread (%d)", r);
+               goto err_destroy_event;
        }
 
        return LIBUSB_SUCCESS;
 
-err_close_pipe:
-       close(udev_control_pipe[0]);
-       close(udev_control_pipe[1]);
+err_destroy_event:
+       usbi_destroy_event(&udev_control_event);
+       udev_control_event = (usbi_event_t)USBI_INVALID_EVENT;
 err_free_monitor:
        udev_monitor_unref(udev_monitor);
        udev_monitor = NULL;
@@ -130,20 +130,21 @@ err:
 
 int linux_udev_stop_event_monitor(void)
 {
-       char dummy = 1;
-       ssize_t r;
+       int r;
 
        assert(udev_ctx != NULL);
        assert(udev_monitor != NULL);
        assert(udev_monitor_fd != -1);
 
-       /* Write some dummy data to the control pipe and
-        * wait for the thread to exit */
-       r = write(udev_control_pipe[1], &dummy, sizeof(dummy));
-       if (r <= 0) {
-               usbi_warn(NULL, "udev control pipe signal failed");
-       }
-       pthread_join(linux_event_thread, NULL);
+       /* Signal the control event and wait for the thread to exit */
+       usbi_signal_event(&udev_control_event);
+
+       r = pthread_join(linux_event_thread, NULL);
+       if (r)
+               usbi_warn(NULL, "failed to join hotplug event thread (%d)", r);
+
+       usbi_destroy_event(&udev_control_event);
+       udev_control_event = (usbi_event_t)USBI_INVALID_EVENT;
 
        /* Release the udev monitor */
        udev_monitor_unref(udev_monitor);
@@ -154,27 +155,19 @@ int linux_udev_stop_event_monitor(void)
        udev_unref(udev_ctx);
        udev_ctx = NULL;
 
-       /* close and reset control pipe */
-       close(udev_control_pipe[0]);
-       close(udev_control_pipe[1]);
-       udev_control_pipe[0] = -1;
-       udev_control_pipe[1] = -1;
-
        return LIBUSB_SUCCESS;
 }
 
 static void *linux_udev_event_thread_main(void *arg)
 {
-       char dummy;
-       int r;
-       ssize_t nb;
-       struct udev_device *udev_dev;
        struct pollfd fds[] = {
-               {.fd = udev_control_pipe[0],
-                .events = POLLIN},
-               {.fd = udev_monitor_fd,
-                .events = POLLIN},
+               { .fd = USBI_EVENT_OS_HANDLE(&udev_control_event),
+                 .events = USBI_EVENT_POLL_EVENTS },
+               { .fd = udev_monitor_fd,
+                 .events = POLLIN },
        };
+       struct udev_device *udev_dev;
+       int r;
 
        UNUSED(arg);
 
@@ -186,20 +179,20 @@ static void *linux_udev_event_thread_main(void *arg)
 
        usbi_dbg("udev event thread entering");
 
-       while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) {
-               if (r < 0) {
-                       /* temporary failure */
-                       continue;
+       while (1) {
+               r = poll(fds, 2, -1);
+               if (r == -1) {
+                       /* check for temporary failure */
+                       if (errno == EINTR)
+                               continue;
+                       usbi_err(NULL, "poll() failed, errno=%d", errno);
+                       break;
                }
-               if (fds[0].revents & POLLIN) {
-                       /* activity on control pipe, read the byte and exit */
-                       nb = read(udev_control_pipe[0], &dummy, sizeof(dummy));
-                       if (nb <= 0) {
-                               usbi_warn(NULL, "udev control pipe read failed");
-                       }
+               if (fds[0].revents) {
+                       /* activity on control event, exit */
                        break;
                }
-               if (fds[1].revents & POLLIN) {
+               if (fds[1].revents) {
                        usbi_mutex_static_lock(&linux_hotplug_lock);
                        udev_dev = udev_monitor_receive_device(udev_monitor);
                        if (udev_dev)
index 1e727ef610b692829e4304132eca7df9c4811dc5..c2980d03e09b287a5e75cdff06846523f65891f7 100644 (file)
@@ -36,6 +36,7 @@
 #include <sys/mman.h>
 #include <sys/utsname.h>
 #include <sys/vfs.h>
+#include <unistd.h>
 
 /* sysfs vs usbfs:
  * opening a usbfs node causes the device to be resumed, so we attempt to
@@ -1266,7 +1267,7 @@ static int initialize_handle(struct libusb_device_handle *handle, int fd)
                hpriv->caps = USBFS_CAP_BULK_CONTINUATION;
        }
 
-       return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
+       return usbi_add_event_source(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
 }
 
 static int op_wrap_sys_device(struct libusb_context *ctx,
@@ -1352,7 +1353,7 @@ static void op_close(struct libusb_device_handle *dev_handle)
 
        /* fd may have already been removed by POLLERR condition in op_handle_events() */
        if (!hpriv->fd_removed)
-               usbi_remove_pollfd(HANDLE_CTX(dev_handle), hpriv->fd);
+               usbi_remove_event_source(HANDLE_CTX(dev_handle), hpriv->fd);
        if (!hpriv->fd_keep)
                close(hpriv->fd);
 }
@@ -2614,13 +2615,14 @@ static int reap_for_handle(struct libusb_device_handle *handle)
 }
 
 static int op_handle_events(struct libusb_context *ctx,
-       struct pollfd *fds, usbi_nfds_t nfds, int num_ready)
+       void *event_data, unsigned int count, unsigned int num_ready)
 {
-       usbi_nfds_t n;
+       struct pollfd *fds = event_data;
+       unsigned int n;
        int r;
 
        usbi_mutex_lock(&ctx->open_devs_lock);
-       for (n = 0; n < nfds && num_ready > 0; n++) {
+       for (n = 0; n < count && num_ready > 0; n++) {
                struct pollfd *pollfd = &fds[n];
                struct libusb_device_handle *handle;
                struct linux_device_handle_priv *hpriv = NULL;
@@ -2645,7 +2647,7 @@ static int op_handle_events(struct libusb_context *ctx,
                        /* remove the fd from the pollfd set so that it doesn't continuously
                         * trigger an event, and flag that it has been removed so op_close()
                         * doesn't try to remove it a second time */
-                       usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd);
+                       usbi_remove_event_source(HANDLE_CTX(handle), hpriv->fd);
                        hpriv->fd_removed = 1;
 
                        /* device will still be marked as attached if hotplug monitor thread
diff --git a/libusb/os/poll_posix.c b/libusb/os/poll_posix.c
deleted file mode 100644 (file)
index 93e9bee..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * poll_posix: poll compatibility wrapper for POSIX systems
- * Copyright Â© 2013 RealVNC Ltd.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include "libusbi.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-int usbi_pipe(int pipefd[2])
-{
-#if defined(HAVE_PIPE2)
-       int ret = pipe2(pipefd, O_CLOEXEC);
-#else
-       int ret = pipe(pipefd);
-#endif
-
-       if (ret != 0) {
-               usbi_err(NULL, "failed to create pipe, errno=%d", errno);
-               return ret;
-       }
-
-#if !defined(HAVE_PIPE2) && defined(FD_CLOEXEC)
-       ret = fcntl(pipefd[0], F_GETFD);
-       if (ret == -1) {
-               usbi_err(NULL, "failed to get pipe fd flags, errno=%d", errno);
-               goto err_close_pipe;
-       }
-       ret = fcntl(pipefd[0], F_SETFD, ret | FD_CLOEXEC);
-       if (ret == -1) {
-               usbi_err(NULL, "failed to set pipe fd flags, errno=%d", errno);
-               goto err_close_pipe;
-       }
-
-       ret = fcntl(pipefd[1], F_GETFD);
-       if (ret == -1) {
-               usbi_err(NULL, "failed to get pipe fd flags, errno=%d", errno);
-               goto err_close_pipe;
-       }
-       ret = fcntl(pipefd[1], F_SETFD, ret | FD_CLOEXEC);
-       if (ret == -1) {
-               usbi_err(NULL, "failed to set pipe fd flags, errno=%d", errno);
-               goto err_close_pipe;
-       }
-#endif
-
-       ret = fcntl(pipefd[1], F_GETFL);
-       if (ret == -1) {
-               usbi_err(NULL, "failed to get pipe fd status flags, errno=%d", errno);
-               goto err_close_pipe;
-       }
-       ret = fcntl(pipefd[1], F_SETFL, ret | O_NONBLOCK);
-       if (ret == -1) {
-               usbi_err(NULL, "failed to set pipe fd status flags, errno=%d", errno);
-               goto err_close_pipe;
-       }
-
-       return 0;
-
-err_close_pipe:
-       close(pipefd[0]);
-       close(pipefd[1]);
-       return ret;
-}
diff --git a/libusb/os/poll_posix.h b/libusb/os/poll_posix.h
deleted file mode 100644 (file)
index 48c4904..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef LIBUSB_POLL_POSIX_H
-#define LIBUSB_POLL_POSIX_H
-
-#include <poll.h>
-#include <unistd.h>
-
-#ifdef HAVE_NFDS_T
-typedef nfds_t usbi_nfds_t;
-#else
-typedef unsigned int usbi_nfds_t;
-#endif
-
-#define usbi_write     write
-#define usbi_read      read
-#define usbi_close     close
-#define usbi_poll      poll
-
-int usbi_pipe(int pipefd[2]);
-
-#endif /* LIBUSB_POLL_POSIX_H */
diff --git a/libusb/os/poll_windows.c b/libusb/os/poll_windows.c
deleted file mode 100644 (file)
index c2bc105..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * poll_windows: poll compatibility wrapper for Windows
- * Copyright Â© 2017 Chris Dickens <christopher.a.dickens@gmail.com>
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-/*
- * poll() and pipe() Windows compatibility layer for libusb 1.0
- *
- * The pipe pollable synchronous I/O works using the overlapped event associated
- * with a fake pipe. The read/write functions are only meant to be used in that
- * context.
- */
-
-#include "libusbi.h"
-#include "windows_common.h"
-
-#include <errno.h>
-#include <intrin.h>
-#include <malloc.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-
-// private data
-struct file_descriptor {
-       LONG refcount;
-       OVERLAPPED overlapped;
-};
-
-static usbi_mutex_static_t fd_table_lock = USBI_MUTEX_INITIALIZER;
-
-#define BITS_PER_BYTE                  8
-#define BITMAP_BITS_PER_WORD           (sizeof(unsigned long) * BITS_PER_BYTE)
-#define FD_TABLE_INCR_SIZE             64
-
-static struct file_descriptor **fd_table;
-static unsigned long *fd_table_bitmap;
-static unsigned int fd_table_size;
-static unsigned int fd_count;
-
-#define return_with_errno(err)         \
-       do {                            \
-               errno = (err);          \
-               return -1;              \
-       } while (0)
-
-static struct file_descriptor *alloc_fd(LONG refcount)
-{
-       struct file_descriptor *fd = calloc(1, sizeof(*fd));
-
-       if (fd == NULL)
-               return NULL;
-       fd->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-       if (fd->overlapped.hEvent == NULL) {
-               free(fd);
-               return NULL;
-       }
-       fd->refcount = refcount;
-       return fd;
-}
-
-static struct file_descriptor *get_fd(unsigned int _fd, bool ref)
-{
-       struct file_descriptor *fd = NULL;
-
-       if (_fd < fd_table_size)
-               fd = fd_table[_fd];
-       if (fd != NULL && ref)
-               InterlockedIncrement(&fd->refcount);
-
-       return fd;
-}
-
-static void put_fd(struct file_descriptor *fd)
-{
-       if (InterlockedDecrement(&fd->refcount) == 0L) {
-               CloseHandle(fd->overlapped.hEvent);
-               free(fd);
-       }
-}
-
-static int install_fd(struct file_descriptor *fd)
-{
-       unsigned int n;
-
-       if (fd_count == fd_table_size) {
-               struct file_descriptor **new_table;
-               unsigned long *new_bitmap;
-
-               // Need to expand the fd table and bitmap
-               new_table = realloc(fd_table, (fd_table_size + FD_TABLE_INCR_SIZE) * sizeof(*new_table));
-               if (new_table == NULL)
-                       return -ENOMEM;
-               memset(new_table + fd_table_size, 0, FD_TABLE_INCR_SIZE * sizeof(*new_table));
-               fd_table = new_table;
-
-               new_bitmap = realloc(fd_table_bitmap, (fd_table_size + FD_TABLE_INCR_SIZE) / BITS_PER_BYTE);
-               if (new_bitmap == NULL)
-                       return -ENOMEM;
-               memset(new_bitmap + (fd_table_size / BITMAP_BITS_PER_WORD), 0, FD_TABLE_INCR_SIZE / BITS_PER_BYTE);
-               fd_table_bitmap = new_bitmap;
-
-               fd_table_size += FD_TABLE_INCR_SIZE;
-               assert(fd_table_size < (unsigned int)INT_MAX);
-       }
-
-       for (n = 0; n < fd_table_size; n += BITMAP_BITS_PER_WORD) {
-               unsigned int idx = n / BITMAP_BITS_PER_WORD;
-               ULONG mask, pos = 0U;
-               unsigned char nonzero;
-
-               mask = ~fd_table_bitmap[idx];
-               if (mask == 0U)
-                       continue;
-
-               nonzero = _BitScanForward(&pos, mask);
-               assert(nonzero);
-               fd_table_bitmap[idx] |= 1U << pos;
-               n += pos;
-               break;
-       }
-
-       assert(n < fd_table_size);
-       assert(fd_table[n] == NULL);
-       fd_table[n] = fd;
-       fd_count++;
-
-       return n;
-}
-
-static void remove_fd(unsigned int pos)
-{
-       assert(fd_table[pos] != NULL);
-       fd_table[pos] = NULL;
-       fd_table_bitmap[pos / BITMAP_BITS_PER_WORD] &= ~(1U << (pos % BITMAP_BITS_PER_WORD));
-       fd_count--;
-       if (fd_count == 0) {
-               free(fd_table);
-               free(fd_table_bitmap);
-               fd_table = NULL;
-               fd_table_bitmap = NULL;
-               fd_table_size = 0;
-       }
-}
-
-struct wait_thread_data {
-       HANDLE thread;
-       HANDLE handles[MAXIMUM_WAIT_OBJECTS];
-       DWORD num_handles;
-       DWORD error;
-};
-
-static DWORD WINAPI WaitThread(LPVOID lpParam)
-{
-       struct wait_thread_data *thread_data = lpParam;
-       HANDLE notify_event = thread_data->handles[0];
-       DWORD status;
-
-       status = WaitForMultipleObjects(thread_data->num_handles, thread_data->handles, FALSE, INFINITE);
-       if (status < (WAIT_OBJECT_0 + thread_data->num_handles)) {
-               if (status > WAIT_OBJECT_0) {
-                       // This will wake up all the other waiting threads
-                       SetEvent(notify_event);
-               }
-               thread_data->error = 0;
-       } else {
-               assert(status == WAIT_FAILED);
-               thread_data->error = (status == WAIT_FAILED) ? GetLastError() : ERROR_CAN_NOT_COMPLETE;
-       }
-
-       return 0;
-}
-
-static DWORD poll_wait(const HANDLE *wait_handles, DWORD num_wait_handles, DWORD timeout)
-{
-       struct wait_thread_data *thread_data;
-       HANDLE notify_event;
-       HANDLE *handles;
-       int n, num_threads;
-       DWORD error, status;
-
-       if (num_wait_handles <= MAXIMUM_WAIT_OBJECTS)
-               return WaitForMultipleObjects(num_wait_handles, wait_handles, FALSE, timeout);
-
-       // To wait on more than MAXIMUM_WAIT_OBJECTS, each thread (including the
-       // current thread) will wait on an event and (MAXIMUM_WAIT_OBJECTS - 1)
-       // HANDLEs.  The event is shared amongst all threads so that any thread
-       // that returns from a WaitForMultipleObjects() call will set the event
-       // and wake up all the other threads.
-       notify_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-       if (notify_event == NULL)
-               return WAIT_FAILED;
-
-       num_threads = 1 + (num_wait_handles - MAXIMUM_WAIT_OBJECTS - 1) / (MAXIMUM_WAIT_OBJECTS - 1);
-       thread_data = malloc(num_threads * sizeof(*thread_data));
-       if (thread_data == NULL) {
-               CloseHandle(notify_event);
-               SetLastError(ERROR_OUTOFMEMORY);
-               return WAIT_FAILED;
-       }
-
-       handles = _alloca(MAXIMUM_WAIT_OBJECTS * sizeof(HANDLE));
-       handles[0] = notify_event;
-       memcpy(handles + 1, wait_handles, (MAXIMUM_WAIT_OBJECTS - 1) * sizeof(HANDLE));
-       wait_handles += MAXIMUM_WAIT_OBJECTS - 1;
-       num_wait_handles -= MAXIMUM_WAIT_OBJECTS - 1;
-
-       for (n = 0; n < num_threads; n++) {
-               DWORD copy_size = MIN(num_wait_handles, MAXIMUM_WAIT_OBJECTS - 1);
-
-               thread_data[n].handles[0] = notify_event;
-               memcpy(thread_data[n].handles + 1, wait_handles, copy_size * sizeof(HANDLE));
-               thread_data[n].num_handles = copy_size + 1;
-
-               // Create the thread that will wait on these HANDLEs
-               thread_data[n].thread = CreateThread(NULL, 0, WaitThread, &thread_data[n], 0, NULL);
-               if (thread_data[n].thread == NULL) {
-                       thread_data[n].error = GetLastError();
-                       SetEvent(notify_event);
-                       num_threads = n + 1;
-                       break;
-               }
-
-               wait_handles += copy_size;
-               num_wait_handles -= copy_size;
-       }
-
-       status = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, handles, FALSE, timeout);
-       if (status < (WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS)) {
-               if (status > WAIT_OBJECT_0) {
-                       // Wake up all the waiting threads
-                       SetEvent(notify_event);
-                       status = WAIT_OBJECT_0;
-               }
-               error = 0;
-       } else if (status == WAIT_TIMEOUT) {
-               // Wake up all the waiting threads
-               SetEvent(notify_event);
-               error = 0;
-       } else {
-               assert(status == WAIT_FAILED);
-               error = (status == WAIT_FAILED) ? GetLastError() : ERROR_CAN_NOT_COMPLETE;
-       }
-
-       for (n = 0; n < num_threads; n++) {
-               if (thread_data[n].thread != NULL) {
-                       if (WaitForSingleObject(thread_data[n].thread, INFINITE) != WAIT_OBJECT_0)
-                               usbi_err(NULL, "WaitForSingleObject() failed: %lu", ULONG_CAST(GetLastError()));
-                       CloseHandle(thread_data[n].thread);
-               }
-               if (thread_data[n].error) {
-                       usbi_err(NULL, "wait thread %d had error %lu\n", n, ULONG_CAST(thread_data[n].error));
-                       error = thread_data[n].error;
-                       status = WAIT_FAILED;
-               }
-       }
-
-       free(thread_data);
-
-       CloseHandle(notify_event);
-
-       if (status == WAIT_FAILED)
-               SetLastError(error);
-
-       return status;
-}
-
-/*
- * POSIX poll equivalent, using Windows OVERLAPPED
- * Currently, this function only accepts one of POLLIN or POLLOUT per fd
- * (but you can create multiple fds from the same handle for read and write)
- */
-int usbi_poll(struct pollfd *fds, usbi_nfds_t nfds, int timeout)
-{
-       struct file_descriptor **fds_array;
-       HANDLE *handles_array;
-       struct file_descriptor *fd;
-       usbi_nfds_t n;
-       int nready;
-
-       if (nfds <= MAXIMUM_WAIT_OBJECTS) {
-               fds_array = _alloca(nfds * sizeof(*fds_array));
-               handles_array = _alloca(nfds * sizeof(*handles_array));
-       } else {
-               fds_array = malloc(nfds * sizeof(*fds_array));
-               if (fds_array == NULL)
-                       return_with_errno(ENOMEM);
-               handles_array = malloc(nfds * sizeof(*handles_array));
-               if (handles_array == NULL) {
-                       free(fds_array);
-                       return_with_errno(ENOMEM);
-               }
-       }
-
-       usbi_mutex_static_lock(&fd_table_lock);
-       for (n = 0; n < nfds; n++) {
-               struct pollfd *pfd = &fds[n];
-
-               // Keep it simple - only allow either POLLIN *or* POLLOUT
-               assert((pfd->events == POLLIN) || (pfd->events == POLLOUT));
-               if ((pfd->events != POLLIN) && (pfd->events != POLLOUT)) {
-                       fds_array[n] = NULL;
-                       continue;
-               }
-
-               // All file descriptors must be valid
-               fd = get_fd(pfd->fd, true);
-               assert(fd != NULL);
-               if (fd == NULL) {
-                       fds_array[n] = NULL;
-                       continue;
-               }
-
-               // We hold a reference to fd for the duration of usbi_poll()
-               fds_array[n] = fd;
-               handles_array[n] = fd->overlapped.hEvent;
-       }
-       usbi_mutex_static_unlock(&fd_table_lock);
-
-       nready = 0;
-       while (nready == 0) {
-               DWORD ret;
-
-               // Check all fds for events
-               for (n = 0; n < nfds; n++) {
-                       fd = fds_array[n];
-                       if (fd == NULL) {
-                               fds[n].revents = POLLNVAL;
-                               nready++;
-                       } else if (HasOverlappedIoCompleted(&fd->overlapped)) {
-                               fds[n].revents = fds[n].events;
-                               nready++;
-                       } else {
-                               fds[n].revents = 0;
-                       }
-               }
-
-               if ((nready != 0) || (timeout == 0))
-                       break;
-
-               // Wait for any of the events to trigger
-               ret = poll_wait(handles_array, nfds, (timeout < 0) ? INFINITE : (DWORD)timeout);
-               if (ret == WAIT_TIMEOUT) {
-                       assert(timeout > 0);
-                       timeout = 0;
-               } else if (ret == WAIT_FAILED) {
-                       usbi_err(NULL, "WaitForMultipleObjects failed: %lu", ULONG_CAST(GetLastError()));
-                       errno = EIO;
-                       nready = -1;
-               }
-       }
-
-       for (n = 0; n < nfds; n++) {
-               if (fds_array[n] != NULL)
-                       put_fd(fds_array[n]);
-       }
-
-       if (nfds > MAXIMUM_WAIT_OBJECTS) {
-               free(handles_array);
-               free(fds_array);
-       }
-
-       return nready;
-}
-
-/*
- * close a fake file descriptor
- */
-int usbi_close(int _fd)
-{
-       struct file_descriptor *fd;
-
-       usbi_mutex_static_lock(&fd_table_lock);
-       fd = get_fd(_fd, false);
-       if (fd != NULL)
-               remove_fd(_fd);
-       usbi_mutex_static_unlock(&fd_table_lock);
-
-       if (fd == NULL)
-               return_with_errno(EBADF);
-
-       put_fd(fd);
-
-       return 0;
-}
-
-/*
-* Create a fake pipe.
-* As libusb only uses pipes for signaling, all we need from a pipe is an
-* event. To that extent, we create a single wfd and overlapped as a means
-* to access that event.
-*/
-int usbi_pipe(int filedes[2])
-{
-       struct file_descriptor *fd;
-       int r_fd, w_fd;
-       int error = 0;
-
-       fd = alloc_fd(2);
-       if (fd == NULL)
-               return_with_errno(ENOMEM);
-
-       fd->overlapped.Internal = STATUS_PENDING;
-
-       usbi_mutex_static_lock(&fd_table_lock);
-       r_fd = install_fd(fd);
-       if (r_fd >= 0) {
-               w_fd = install_fd(fd);
-               if (w_fd < 0) {
-                       remove_fd(r_fd);
-                       error = w_fd;
-               }
-       } else {
-               error = r_fd;
-               w_fd = -1; // Keep compiler happy
-       }
-       usbi_mutex_static_unlock(&fd_table_lock);
-
-       if (error) {
-               CloseHandle(fd->overlapped.hEvent);
-               free(fd);
-               return_with_errno(error);
-       }
-
-       filedes[0] = r_fd;
-       filedes[1] = w_fd;
-
-       return 0;
-}
-
-/*
- * synchronous write for fake "pipe" signaling
- */
-ssize_t usbi_write(int _fd, const void *buf, size_t count)
-{
-       struct file_descriptor *fd;
-
-       UNUSED(buf);
-
-       if (count != sizeof(unsigned char)) {
-               usbi_err(NULL, "this function should only used for signaling");
-               return_with_errno(EINVAL);
-       }
-
-       usbi_mutex_static_lock(&fd_table_lock);
-       fd = get_fd(_fd, false);
-       if (fd != NULL) {
-               assert(fd->overlapped.Internal == STATUS_PENDING);
-               fd->overlapped.Internal = STATUS_WAIT_0;
-               SetEvent(fd->overlapped.hEvent);
-       }
-       usbi_mutex_static_unlock(&fd_table_lock);
-
-       if (fd == NULL)
-               return_with_errno(EBADF);
-
-       return sizeof(unsigned char);
-}
-
-/*
- * synchronous read for fake "pipe" signaling
- */
-ssize_t usbi_read(int _fd, void *buf, size_t count)
-{
-       struct file_descriptor *fd;
-
-       UNUSED(buf);
-
-       if (count != sizeof(unsigned char)) {
-               usbi_err(NULL, "this function should only used for signaling");
-               return_with_errno(EINVAL);
-       }
-
-       usbi_mutex_static_lock(&fd_table_lock);
-       fd = get_fd(_fd, false);
-       if (fd != NULL) {
-               assert(fd->overlapped.Internal == STATUS_WAIT_0);
-               fd->overlapped.Internal = STATUS_PENDING;
-               ResetEvent(fd->overlapped.hEvent);
-       }
-       usbi_mutex_static_unlock(&fd_table_lock);
-
-       if (fd == NULL)
-               return_with_errno(EBADF);
-
-       return sizeof(unsigned char);
-}
diff --git a/libusb/os/poll_windows.h b/libusb/os/poll_windows.h
deleted file mode 100644 (file)
index 14a5b27..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Windows compat: POSIX compatibility wrapper
- * Copyright Â© 2012-2013 RealVNC Ltd.
- * Copyright Â© 2009-2010 Pete Batard <pete@akeo.ie>
- * Copyright Â© 2016-2018 Chris Dickens <christopher.a.dickens@gmail.com>
- * With contributions from Michael Plante, Orin Eman et al.
- * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifndef LIBUSB_POLL_WINDOWS_H
-#define LIBUSB_POLL_WINDOWS_H
-
-#define POLLIN         0x0001  /* There is data to read */
-#define POLLPRI                0x0002  /* There is urgent data to read */
-#define POLLOUT                0x0004  /* Writing now will not block */
-#define POLLERR                0x0008  /* Error condition */
-#define POLLHUP                0x0010  /* Hung up */
-#define POLLNVAL       0x0020  /* Invalid request: fd not open */
-
-typedef unsigned int usbi_nfds_t;
-
-struct pollfd {
-       int fd;         /* file descriptor */
-       short events;   /* requested events */
-       short revents;  /* returned events */
-};
-
-int usbi_pipe(int pipefd[2]);
-int usbi_poll(struct pollfd *fds, usbi_nfds_t nfds, int timeout);
-ssize_t usbi_write(int fd, const void *buf, size_t count);
-ssize_t usbi_read(int fd, void *buf, size_t count);
-int usbi_close(int fd);
-
-#endif
index 04dda4adb10544bb5eb57dcffe499ec5d63b5bca..fa6721e6347a3f38a386f34bcdb566d05d7c8937 100644 (file)
@@ -467,7 +467,7 @@ static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc,
 /*
  * Open a device and associate the HANDLE with the context's I/O completion port
  */
-HANDLE windows_open(struct libusb_device *dev, const char *path, DWORD access)
+static HANDLE windows_open(struct libusb_device *dev, const char *path, DWORD access)
 {
        struct libusb_context *ctx = DEVICE_CTX(dev);
        struct windows_context_priv *priv = usbi_get_context_priv(ctx);
index e7b7f080065e60187df78c5634258dcb2612be92..bf72b266efbbb8b0ab5f9ae9e1a7f77a00fefa90 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 11531
+#define LIBUSB_NANO 11532
index 58d1ed7cf2ce3be39f85c6659604fc672817d5a0..2f6eaf0d25ef9856dde7e4b7490638f27aeccc00 100644 (file)
@@ -47,8 +47,8 @@
 /* Define to 1 to enable message logging. */
 #define ENABLE_LOGGING 1
 
-/* Define to 1 if using the Windows poll() implementation. */
-#define POLL_WINDOWS 1
+/* Define to 1 if using the Windows events abstraction. */
+#define EVENTS_WINDOWS 1
 
 /* Define to 1 if using Windows threads. */
 #define THREADS_WINDOWS 1
index b858f77c52a64e36efe500c06650f1280ed26436..56ffd75e9e752b6f124513cba19a6f1aacfdf854 100644 (file)
@@ -70,9 +70,9 @@
   <ItemGroup>
     <ClCompile Include="..\libusb\core.c" />
     <ClCompile Include="..\libusb\descriptor.c" />
+    <ClCompile Include="..\libusb\os\events_windows.c" />
     <ClCompile Include="..\libusb\hotplug.c" />
     <ClCompile Include="..\libusb\io.c" />
-    <ClCompile Include="..\libusb\os\poll_windows.c" />
     <ClCompile Include="..\libusb\strerror.c" />
     <ClCompile Include="..\libusb\sync.c" />
     <ClCompile Include="..\libusb\os\threads_windows.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include=".\config.h" />
+    <ClInclude Include="..\libusb\os\events_windows.h" />
     <ClInclude Include="..\libusb\hotplug.h" />
     <ClInclude Include="..\libusb\libusb.h" />
     <ClInclude Include="..\libusb\libusbi.h" />
-    <ClInclude Include="..\libusb\os\poll_windows.h" />
     <ClInclude Include="..\libusb\os\threads_windows.h" />
     <ClInclude Include="..\libusb\version.h" />
     <ClInclude Include="..\libusb\version_nano.h" />
index 2e6cc93b92e82b8afa018d00b13d871edecc3823..8da28e3552f1bf1e00a56fd0f23b8d4cbcef71df 100644 (file)
@@ -18,6 +18,9 @@
     <ClInclude Include=".\config.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\libusb\os\events_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\libusb\hotplug.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -27,9 +30,6 @@
     <ClInclude Include="..\libusb\libusbi.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\libusb\os\poll_windows.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="..\libusb\os\threads_windows.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClCompile Include="..\libusb\descriptor.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\hotplug.c">
+    <ClCompile Include="..\libusb\os\events_windows.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\io.c">
+    <ClCompile Include="..\libusb\hotplug.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\os\poll_windows.c">
+    <ClCompile Include="..\libusb\io.c">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClCompile Include="..\libusb\strerror.c">
index 4a73ef70a42d7482ee7220b16005b3ba12bc22cf..d2c850d05c4273999cc96c8ca3239215a31e6233 100644 (file)
@@ -71,9 +71,9 @@
   <ItemGroup>
     <ClCompile Include="..\libusb\core.c" />
     <ClCompile Include="..\libusb\descriptor.c" />
+    <ClCompile Include="..\libusb\os\events_windows.c" />
     <ClCompile Include="..\libusb\hotplug.c" />
     <ClCompile Include="..\libusb\io.c" />
-    <ClCompile Include="..\libusb\os\poll_windows.c" />
     <ClCompile Include="..\libusb\strerror.c" />
     <ClCompile Include="..\libusb\sync.c" />
     <ClCompile Include="..\libusb\os\threads_windows.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include=".\config.h" />
+    <ClInclude Include="..\libusb\os\events_windows.h" />
     <ClInclude Include="..\libusb\hotplug.h" />
     <ClInclude Include="..\libusb\libusb.h" />
     <ClInclude Include="..\libusb\libusbi.h" />
-    <ClInclude Include="..\libusb\os\poll_windows.h" />
     <ClInclude Include="..\libusb\os\threads_windows.h" />
     <ClInclude Include="..\libusb\version.h" />
     <ClInclude Include="..\libusb\version_nano.h" />
index 2e6cc93b92e82b8afa018d00b13d871edecc3823..8da28e3552f1bf1e00a56fd0f23b8d4cbcef71df 100644 (file)
@@ -18,6 +18,9 @@
     <ClInclude Include=".\config.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\libusb\os\events_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\libusb\hotplug.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -27,9 +30,6 @@
     <ClInclude Include="..\libusb\libusbi.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\libusb\os\poll_windows.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="..\libusb\os\threads_windows.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClCompile Include="..\libusb\descriptor.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\hotplug.c">
+    <ClCompile Include="..\libusb\os\events_windows.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\io.c">
+    <ClCompile Include="..\libusb\hotplug.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\os\poll_windows.c">
+    <ClCompile Include="..\libusb\io.c">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClCompile Include="..\libusb\strerror.c">
index 20fa6c47f105aaca308473d39bff7b3149645f80..598159d079a71df11caca30bb6ad07ba8eb3ca7d 100644 (file)
@@ -90,9 +90,9 @@
   <ItemGroup>
     <ClCompile Include="..\libusb\core.c" />
     <ClCompile Include="..\libusb\descriptor.c" />
+    <ClCompile Include="..\libusb\os\events_windows.c" />
     <ClCompile Include="..\libusb\hotplug.c" />
     <ClCompile Include="..\libusb\io.c" />
-    <ClCompile Include="..\libusb\os\poll_windows.c" />
     <ClCompile Include="..\libusb\strerror.c" />
     <ClCompile Include="..\libusb\sync.c" />
     <ClCompile Include="..\libusb\os\threads_windows.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include=".\config.h" />
+    <ClInclude Include="..\libusb\os\events_windows.h" />
     <ClInclude Include="..\libusb\hotplug.h" />
     <ClInclude Include="..\libusb\libusb.h" />
     <ClInclude Include="..\libusb\libusbi.h" />
-    <ClInclude Include="..\libusb\os\poll_windows.h" />
     <ClInclude Include="..\libusb\os\threads_windows.h" />
     <ClInclude Include="..\libusb\version.h" />
     <ClInclude Include="..\libusb\version_nano.h" />
index 2e6cc93b92e82b8afa018d00b13d871edecc3823..8da28e3552f1bf1e00a56fd0f23b8d4cbcef71df 100644 (file)
@@ -18,6 +18,9 @@
     <ClInclude Include=".\config.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\libusb\os\events_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\libusb\hotplug.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -27,9 +30,6 @@
     <ClInclude Include="..\libusb\libusbi.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\libusb\os\poll_windows.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="..\libusb\os\threads_windows.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClCompile Include="..\libusb\descriptor.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\hotplug.c">
+    <ClCompile Include="..\libusb\os\events_windows.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\io.c">
+    <ClCompile Include="..\libusb\hotplug.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\os\poll_windows.c">
+    <ClCompile Include="..\libusb\io.c">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClCompile Include="..\libusb\strerror.c">
index 69e42e137d358fbf1cbb60fe5095bc9726cbbf18..dbd8717695865b13e3f5541738e7a3b48623ef31 100644 (file)
@@ -90,9 +90,9 @@
   <ItemGroup>
     <ClCompile Include="..\libusb\core.c" />
     <ClCompile Include="..\libusb\descriptor.c" />
+    <ClCompile Include="..\libusb\os\events_windows.c" />
     <ClCompile Include="..\libusb\hotplug.c" />
     <ClCompile Include="..\libusb\io.c" />
-    <ClCompile Include="..\libusb\os\poll_windows.c" />
     <ClCompile Include="..\libusb\strerror.c" />
     <ClCompile Include="..\libusb\sync.c" />
     <ClCompile Include="..\libusb\os\threads_windows.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include=".\config.h" />
+    <ClInclude Include="..\libusb\os\events_windows.h" />
     <ClInclude Include="..\libusb\hotplug.h" />
     <ClInclude Include="..\libusb\libusb.h" />
     <ClInclude Include="..\libusb\libusbi.h" />
-    <ClInclude Include="..\libusb\os\poll_windows.h" />
     <ClInclude Include="..\libusb\os\threads_windows.h" />
     <ClInclude Include="..\libusb\version.h" />
     <ClInclude Include="..\libusb\version_nano.h" />
index 2e6cc93b92e82b8afa018d00b13d871edecc3823..8da28e3552f1bf1e00a56fd0f23b8d4cbcef71df 100644 (file)
@@ -18,6 +18,9 @@
     <ClInclude Include=".\config.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\libusb\os\events_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\libusb\hotplug.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -27,9 +30,6 @@
     <ClInclude Include="..\libusb\libusbi.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\libusb\os\poll_windows.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="..\libusb\os\threads_windows.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClCompile Include="..\libusb\descriptor.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\hotplug.c">
+    <ClCompile Include="..\libusb\os\events_windows.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\io.c">
+    <ClCompile Include="..\libusb\hotplug.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\os\poll_windows.c">
+    <ClCompile Include="..\libusb\io.c">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClCompile Include="..\libusb\strerror.c">
index 559acf18d44bcf1b269c7ecbb69384b4314c26bf..1b287e59768bcd3c86b5087d3b29b8df3e99b243 100644 (file)
@@ -66,9 +66,9 @@
   <ItemGroup>
     <ClCompile Include="..\libusb\core.c" />
     <ClCompile Include="..\libusb\descriptor.c" />
+    <ClCompile Include="..\libusb\os\events_windows.c" />
     <ClCompile Include="..\libusb\hotplug.c" />
     <ClCompile Include="..\libusb\io.c" />
-    <ClCompile Include="..\libusb\os\poll_windows.c" />
     <ClCompile Include="..\libusb\strerror.c" />
     <ClCompile Include="..\libusb\sync.c" />
     <ClCompile Include="..\libusb\os\threads_windows.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include=".\config.h" />
+    <ClInclude Include="..\libusb\os\events_windows.h" />
     <ClInclude Include="..\libusb\hotplug.h" />
     <ClInclude Include="..\libusb\libusb.h" />
     <ClInclude Include="..\libusb\libusbi.h" />
-    <ClInclude Include="..\libusb\os\poll_windows.h" />
     <ClInclude Include="..\libusb\os\threads_windows.h" />
     <ClInclude Include="..\libusb\version.h" />
     <ClInclude Include="..\libusb\version_nano.h" />
index c35bf87565ac55056b7976743b1885e87c83f7ec..2994ca10bada7f117bf161495f581320f221fa82 100644 (file)
@@ -14,6 +14,9 @@
     <ClInclude Include=".\config.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\libusb\os\events_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\libusb\hotplug.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -23,9 +26,6 @@
     <ClInclude Include="..\libusb\libusbi.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\libusb\os\poll_windows.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="..\libusb\os\threads_windows.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClCompile Include="..\libusb\descriptor.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\hotplug.c">
+    <ClCompile Include="..\libusb\os\events_windows.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\io.c">
+    <ClCompile Include="..\libusb\hotplug.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\os\poll_windows.c">
+    <ClCompile Include="..\libusb\io.c">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClCompile Include="..\libusb\strerror.c">
index ba076662226609b9769cfe84f23c24fce0dd2a3e..9fa30dab823e29beda6f37d8fa300c43eea30b46 100644 (file)
@@ -67,9 +67,9 @@
   <ItemGroup>
     <ClCompile Include="..\libusb\core.c" />
     <ClCompile Include="..\libusb\descriptor.c" />
+    <ClCompile Include="..\libusb\os\events_windows.c" />
     <ClCompile Include="..\libusb\hotplug.c" />
     <ClCompile Include="..\libusb\io.c" />
-    <ClCompile Include="..\libusb\os\poll_windows.c" />
     <ClCompile Include="..\libusb\strerror.c" />
     <ClCompile Include="..\libusb\sync.c" />
     <ClCompile Include="..\libusb\os\threads_windows.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include=".\config.h" />
+    <ClInclude Include="..\libusb\os\events_windows.h" />
     <ClInclude Include="..\libusb\hotplug.h" />
     <ClInclude Include="..\libusb\libusb.h" />
     <ClInclude Include="..\libusb\libusbi.h" />
-    <ClInclude Include="..\libusb\os\poll_windows.h" />
     <ClInclude Include="..\libusb\os\threads_windows.h" />
     <ClInclude Include="..\libusb\version.h" />
     <ClInclude Include="..\libusb\version_nano.h" />
index c35bf87565ac55056b7976743b1885e87c83f7ec..2994ca10bada7f117bf161495f581320f221fa82 100644 (file)
@@ -14,6 +14,9 @@
     <ClInclude Include=".\config.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\libusb\os\events_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\libusb\hotplug.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -23,9 +26,6 @@
     <ClInclude Include="..\libusb\libusbi.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\libusb\os\poll_windows.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="..\libusb\os\threads_windows.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClCompile Include="..\libusb\descriptor.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\hotplug.c">
+    <ClCompile Include="..\libusb\os\events_windows.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\io.c">
+    <ClCompile Include="..\libusb\hotplug.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\os\poll_windows.c">
+    <ClCompile Include="..\libusb\io.c">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClCompile Include="..\libusb\strerror.c">
index 08816d26df0b78e8100f5e1570c76a4f8abaad1f..62076e0ab9b1a935090091d1671c48f7d232bf72 100644 (file)
@@ -86,9 +86,9 @@
   <ItemGroup>
     <ClCompile Include="..\libusb\core.c" />
     <ClCompile Include="..\libusb\descriptor.c" />
+    <ClCompile Include="..\libusb\os\events_windows.c" />
     <ClCompile Include="..\libusb\hotplug.c" />
     <ClCompile Include="..\libusb\io.c" />
-    <ClCompile Include="..\libusb\os\poll_windows.c" />
     <ClCompile Include="..\libusb\strerror.c" />
     <ClCompile Include="..\libusb\sync.c" />
     <ClCompile Include="..\libusb\os\threads_windows.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include=".\config.h" />
+    <ClInclude Include="..\libusb\os\events_windows.h" />
     <ClInclude Include="..\libusb\hotplug.h" />
     <ClInclude Include="..\libusb\libusb.h" />
     <ClInclude Include="..\libusb\libusbi.h" />
-    <ClInclude Include="..\libusb\os\poll_windows.h" />
     <ClInclude Include="..\libusb\os\threads_windows.h" />
     <ClInclude Include="..\libusb\version.h" />
     <ClInclude Include="..\libusb\version_nano.h" />
index c35bf87565ac55056b7976743b1885e87c83f7ec..2994ca10bada7f117bf161495f581320f221fa82 100644 (file)
@@ -14,6 +14,9 @@
     <ClInclude Include=".\config.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\libusb\os\events_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\libusb\hotplug.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -23,9 +26,6 @@
     <ClInclude Include="..\libusb\libusbi.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\libusb\os\poll_windows.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="..\libusb\os\threads_windows.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClCompile Include="..\libusb\descriptor.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\hotplug.c">
+    <ClCompile Include="..\libusb\os\events_windows.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\io.c">
+    <ClCompile Include="..\libusb\hotplug.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\os\poll_windows.c">
+    <ClCompile Include="..\libusb\io.c">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClCompile Include="..\libusb\strerror.c">
index 24ab3e3927a0e4fd5b0c7fcbb9594ff2ca261d03..60ad642c53875a4480733bcfac922a774ab16fb4 100644 (file)
@@ -86,9 +86,9 @@
   <ItemGroup>
     <ClCompile Include="..\libusb\core.c" />
     <ClCompile Include="..\libusb\descriptor.c" />
+    <ClCompile Include="..\libusb\os\events_windows.c" />
     <ClCompile Include="..\libusb\hotplug.c" />
     <ClCompile Include="..\libusb\io.c" />
-    <ClCompile Include="..\libusb\os\poll_windows.c" />
     <ClCompile Include="..\libusb\strerror.c" />
     <ClCompile Include="..\libusb\sync.c" />
     <ClCompile Include="..\libusb\os\threads_windows.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include=".\config.h" />
+    <ClInclude Include="..\libusb\os\events_windows.h" />
     <ClInclude Include="..\libusb\hotplug.h" />
     <ClInclude Include="..\libusb\libusb.h" />
     <ClInclude Include="..\libusb\libusbi.h" />
-    <ClInclude Include="..\libusb\os\poll_windows.h" />
     <ClInclude Include="..\libusb\os\threads_windows.h" />
     <ClInclude Include="..\libusb\version.h" />
     <ClInclude Include="..\libusb\version_nano.h" />
index c35bf87565ac55056b7976743b1885e87c83f7ec..2994ca10bada7f117bf161495f581320f221fa82 100644 (file)
@@ -14,6 +14,9 @@
     <ClInclude Include=".\config.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\libusb\os\events_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\libusb\hotplug.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -23,9 +26,6 @@
     <ClInclude Include="..\libusb\libusbi.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\libusb\os\poll_windows.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="..\libusb\os\threads_windows.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClCompile Include="..\libusb\descriptor.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\hotplug.c">
+    <ClCompile Include="..\libusb\os\events_windows.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\io.c">
+    <ClCompile Include="..\libusb\hotplug.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\libusb\os\poll_windows.c">
+    <ClCompile Include="..\libusb\io.c">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClCompile Include="..\libusb\strerror.c">