Hi,

I've attached two patches which improve the logging in non-console applications and three patches which add Android support to libusbx.

The first patch adds a configure option "--enable-system-log". This also enable output of libusbx log messages to the debugger output in Windows.

The second patch makes the "--enable-system-log" option make use of syslog on platforms which support it. I've only tested this on 64-bit desktop Ubuntu 12.04 at the moment. I'm not sure if non-Linux platforms, e.g.

While looking at this logging I discovered that the Android logging code doesn't even compile. This appears to be because there aren't any build files for Android in the libusbx source tree. The third patch adds build files for Android.

The forth patch updates the logging code and a couple of other files so that libusbx almost builds for Android.

The fifth and final patch modifies the hotplug netlink code so that it doesn't use pthread_cancel. This is because Android doesn't have pthread_cancel, so alternative ways of stopping the hotplug thread are needed.

I've not done much testing with libusbx on Android other than using listdevs. I'll try to find time to:
* Add building for Android of more of the samples.
* Add building for Android of the tests.
* Do a bit more testing.
* Add some documentation about how to build libusbx for Android.
* Check that the Android.mk is suitable for easily including in other Android projects. This is really a case of making sure that all the paths are correctly set in relation to the location of the make file.

But that might not be for a while so I thought it better to share the patches earlier rather than later.

Regards,

Toby
>From 956628e5f97cdd989966a15de2c20e5cf50c6657 Mon Sep 17 00:00:00 2001
From: Toby Gray <toby.g...@realvnc.com>
Date: Tue, 9 Jul 2013 16:05:39 +0100
Subject: [PATCH 1/5] Windows: Add compile time option to log messages to the
 debugger.

This change makes it considerably easier to debug issues in UI applications
which don't necessarily have a console connected to stderr.

Outputting to the debugger shouldn't occur in normal situations so
this change has to be explicitly enabled by a build-time config flag.
---
 configure.ac  |    8 ++++++++
 libusb/core.c |   10 ++++++++++
 msvc/config.h |    3 +++
 3 files changed, 21 insertions(+)

diff --git a/configure.ac b/configure.ac
index 6d6b35d..ef69370 100644
--- a/configure.ac
+++ b/configure.ac
@@ -192,6 +192,14 @@ if test "x$debug_log_enabled" != "xno"; then
 	AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Start with debug message logging enabled])
 fi
 
+AC_ARG_ENABLE([system-log], [AS_HELP_STRING([--enable-system-log],
+	[output logging messages to system wide log])],
+	[system_log_enabled=$enableval],
+	[system_log_enabled='no'])
+if test "x$system_log_enabled" != "xno"; then
+	AC_DEFINE([USE_SYSTEM_LOGGING_FACILITY], 1, [Enable output to system log])
+fi
+
 # Examples build
 AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
 	[build example applications (default n)])],
diff --git a/libusb/core.c b/libusb/core.c
index e29e8df..ec905d3 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -2028,6 +2028,16 @@ int usbi_gettimeofday(struct timeval *tp, void *tzp)
 
 static void usbi_log_str(struct libusb_context *ctx, const char * str)
 {
+#ifdef USE_SYSTEM_LOGGING_FACILITY
+#if defined(OS_WINDOWS)
+	OutputDebugStringA(str);
+#elif defined(OS_WINCE)
+	/* Windows CE only supports the unicode version of OutputDebugString. */
+	WCHAR wbuf[USBI_MAX_LOG_LEN];
+	MultiByteToWideChar(CP_ACP, 0, str, -1, wbuf, sizeof(wbuf));
+	OutputDebugStringW(wbuf);
+#endif
+#endif /* USE_SYSTEM_LOGGING_FACILITY */
 	UNUSED(ctx);
 	fputs(str, stderr);
 }
diff --git a/msvc/config.h b/msvc/config.h
index bb542c5..4b418db 100644
--- a/msvc/config.h
+++ b/msvc/config.h
@@ -25,6 +25,9 @@
 /* Uncomment to start with debug message logging enabled */
 // #define ENABLE_DEBUG_LOGGING 1
 
+/* Uncomment to enabling logging to system log */
+// #define USE_SYSTEM_LOGGING_FACILITY
+
 /* type of second poll() argument */
 #define POLL_NFDS_TYPE unsigned int
 
-- 
1.7.9.5

>From 706d8f31be885495e5ee9d9aba83b91ebd954a4c Mon Sep 17 00:00:00 2001
From: Toby Gray <toby.g...@realvnc.com>
Date: Tue, 9 Jul 2013 16:30:55 +0100
Subject: [PATCH 2/5] Core: Adding support for syslog if --enable-system-log
 is passed to configure.

This change allows log messages to go to syslog if enabled at
compilation time by using --enable-system-log.

The syslog.h header and syslog() function are used to provide the
logging.
---
 configure.ac  |    7 +++++++
 libusb/core.c |   22 ++++++++++++++++++----
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index ef69370..b7ed542 100644
--- a/configure.ac
+++ b/configure.ac
@@ -200,6 +200,13 @@ if test "x$system_log_enabled" != "xno"; then
 	AC_DEFINE([USE_SYSTEM_LOGGING_FACILITY], 1, [Enable output to system log])
 fi
 
+# Check if syslog is available in standard C library
+AC_CHECK_HEADERS(syslog.h)
+AC_CHECK_FUNC([syslog], [have_syslog=yes], [have_syslog=no])
+if test "x$have_syslog" != "xno"; then
+	AC_DEFINE([HAVE_SYSLOG_FUNC], 1, [syslog() function available])
+fi
+
 # Examples build
 AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
 	[build example applications (default n)])],
diff --git a/libusb/core.c b/libusb/core.c
index ec905d3..5df459a 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -33,6 +33,9 @@
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
 
 #ifdef __ANDROID__
 #include <android/log.h>
@@ -2026,7 +2029,8 @@ int usbi_gettimeofday(struct timeval *tp, void *tzp)
 }
 #endif
 
-static void usbi_log_str(struct libusb_context *ctx, const char * str)
+static void usbi_log_str(struct libusb_context *ctx,
+	enum libusb_log_level level, const char * str)
 {
 #ifdef USE_SYSTEM_LOGGING_FACILITY
 #if defined(OS_WINDOWS)
@@ -2036,6 +2040,16 @@ static void usbi_log_str(struct libusb_context *ctx, const char * str)
 	WCHAR wbuf[USBI_MAX_LOG_LEN];
 	MultiByteToWideChar(CP_ACP, 0, str, -1, wbuf, sizeof(wbuf));
 	OutputDebugStringW(wbuf);
+#elif defined(HAVE_SYSLOG_FUNC)
+	int syslog_level = LOG_INFO;
+	switch (level) {
+	case LIBUSB_LOG_LEVEL_INFO: syslog_level = LOG_INFO; break;
+	case LIBUSB_LOG_LEVEL_WARNING: syslog_level = LOG_WARNING; break;
+	case LIBUSB_LOG_LEVEL_ERROR: syslog_level = LOG_ERR; break;
+	case LIBUSB_LOG_LEVEL_DEBUG: syslog_level = LOG_DEBUG; break;
+	case LIBUSB_LOG_LEVEL_NONE: break;
+	}
+	syslog(syslog_level, "%s", str);
 #endif
 #endif /* USE_SYSTEM_LOGGING_FACILITY */
 	UNUSED(ctx);
@@ -2094,8 +2108,8 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
 	usbi_gettimeofday(&now, NULL);
 	if ((global_debug) && (!has_debug_header_been_displayed)) {
 		has_debug_header_been_displayed = 1;
-		usbi_log_str(ctx, "[timestamp] [threadID] facility level [function call] <message>\n");
-		usbi_log_str(ctx, "--------------------------------------------------------------------------------\n");
+		usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "[timestamp] [threadID] facility level [function call] <message>\n");
+		usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------\n");
 	}
 	if (now.tv_usec < timestamp_origin.tv_usec) {
 		now.tv_sec--;
@@ -2153,7 +2167,7 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
 	}
 	strcpy(buf + header_len + text_len, USBI_LOG_LINE_END);
 
-	usbi_log_str(ctx, buf);
+	usbi_log_str(ctx, level, buf);
 #endif
 }
 
-- 
1.7.9.5

>From 257c66a8b8f5e3804513dc32c62229af1da3207a Mon Sep 17 00:00:00 2001
From: Toby Gray <toby.g...@realvnc.com>
Date: Tue, 9 Jul 2013 16:43:53 +0100
Subject: [PATCH 3/5] Android: Adding Android build files.

---
 android/config.h       |   56 ++++++++++++++++++++++++++++++++++++++++++
 android/jni/Android.mk |   63 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)
 create mode 100644 android/config.h
 create mode 100644 android/jni/Android.mk

diff --git a/android/config.h b/android/config.h
new file mode 100644
index 0000000..7943384
--- /dev/null
+++ b/android/config.h
@@ -0,0 +1,56 @@
+/*
+ * Android build config for libusbx
+ * Copyright © 2012-2013 RealVNC Ltd. <toby.g...@realvnc.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
+ */
+
+/* Start with debug message logging enabled */
+/* #undef ENABLE_DEBUG_LOGGING */
+
+/* Message logging */
+#define ENABLE_LOGGING
+
+/* Linux backend */
+#define OS_LINUX 1
+
+/* Enable output to system log */
+#define USE_SYSTEM_LOGGING_FACILITY 1
+
+/* type of second poll() argument */
+#define POLL_NFDS_TYPE nfds_t
+
+/* Use POSIX Threads */
+#define THREADS_POSIX 1
+
+/* Default visibility */
+#define DEFAULT_VISIBILITY __attribute__((visibility("default")))
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+#ifndef TIMESPEC_TO_TIMEVAL
+#define TIMESPEC_TO_TIMEVAL(tv, ts)                                     \
+        do {                                                            \
+                (tv)->tv_sec = (ts)->tv_sec;                            \
+                (tv)->tv_usec = (ts)->tv_nsec / 1000;                   \
+        } while (0)
+#endif
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
new file mode 100644
index 0000000..c00c8ac
--- /dev/null
+++ b/android/jni/Android.mk
@@ -0,0 +1,63 @@
+#
+# Android build config for libusbx
+# Copyright © 2012-2013 RealVNC Ltd. <toby.g...@realvnc.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
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+# libusb
+
+include $(CLEAR_VARS)
+
+LIBUSB_ROOT_REL:= ../..
+LIBUSB_ROOT_ABS:= $(LOCAL_PATH)/../..
+
+LOCAL_SRC_FILES := \
+  $(LIBUSB_ROOT_REL)/libusb/core.c \
+  $(LIBUSB_ROOT_REL)/libusb/descriptor.c \
+  $(LIBUSB_ROOT_REL)/libusb/io.c \
+  $(LIBUSB_ROOT_REL)/libusb/sync.c \
+  $(LIBUSB_ROOT_REL)/libusb/os/linux_usbfs.c
+
+LOCAL_C_INCLUDES += \
+  $(LOCAL_PATH)/.. \
+  $(LIBUSB_ROOT_ABS)/libusb \
+  $(LIBUSB_ROOT_ABS)/libusb/os
+
+LOCAL_EXPORT_C_INCLUDES := \
+  $(LIBUSB_ROOT_ABS)/libusb
+
+LOCAL_MODULE := libusb1.0
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+# listdevs
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+  $(LIBUSB_ROOT_REL)/examples/listdevs.c
+
+LOCAL_C_INCLUDES += \
+  $(LIBUSB_ROOT_ABS)
+
+LOCAL_SHARED_LIBRARIES += libusb1.0
+
+LOCAL_MODULE:= listdevs
+
+include $(BUILD_EXECUTABLE)
-- 
1.7.9.5

>From ac8d25a18fb8cb13bb5a466512d4825efee22e7a Mon Sep 17 00:00:00 2001
From: Toby Gray <toby.g...@realvnc.com>
Date: Tue, 9 Jul 2013 17:05:22 +0100
Subject: [PATCH 4/5] Android: Fix the majority of Android OS build issues.

This commit fixes the majority of Android OS build issues so that
it is almost possible to build libusbx for Android OS.
---
 android/config.h          |   22 ++++++++++++++++++++++
 android/jni/Android.mk    |    8 +++++++-
 libusb/core.c             |   34 +++++++++++-----------------------
 libusb/os/linux_netlink.c |   36 +++++++++++++++++++++++++++++++++++-
 libusb/os/threads_posix.c |    4 +++-
 5 files changed, 78 insertions(+), 26 deletions(-)

diff --git a/android/config.h b/android/config.h
index 7943384..30be160 100644
--- a/android/config.h
+++ b/android/config.h
@@ -23,6 +23,15 @@
 /* Message logging */
 #define ENABLE_LOGGING
 
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
 /* Linux backend */
 #define OS_LINUX 1
 
@@ -47,6 +56,19 @@
 /* Define to 1 if you have the <signal.h> header file. */
 #define HAVE_SIGNAL_H 1
 
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Add defines which Android is missing */
 #ifndef TIMESPEC_TO_TIMEVAL
 #define TIMESPEC_TO_TIMEVAL(tv, ts)                                     \
         do {                                                            \
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index c00c8ac..8f9f66c 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -29,9 +29,13 @@ LIBUSB_ROOT_ABS:= $(LOCAL_PATH)/../..
 LOCAL_SRC_FILES := \
   $(LIBUSB_ROOT_REL)/libusb/core.c \
   $(LIBUSB_ROOT_REL)/libusb/descriptor.c \
+  $(LIBUSB_ROOT_REL)/libusb/hotplug.c \
   $(LIBUSB_ROOT_REL)/libusb/io.c \
   $(LIBUSB_ROOT_REL)/libusb/sync.c \
-  $(LIBUSB_ROOT_REL)/libusb/os/linux_usbfs.c
+  $(LIBUSB_ROOT_REL)/libusb/os/linux_usbfs.c \
+  $(LIBUSB_ROOT_REL)/libusb/os/poll_posix.c \
+  $(LIBUSB_ROOT_REL)/libusb/os/threads_posix.c \
+  $(LIBUSB_ROOT_REL)/libusb/os/linux_netlink.c
 
 LOCAL_C_INCLUDES += \
   $(LOCAL_PATH)/.. \
@@ -41,6 +45,8 @@ LOCAL_C_INCLUDES += \
 LOCAL_EXPORT_C_INCLUDES := \
   $(LIBUSB_ROOT_ABS)/libusb
 
+LOCAL_LDLIBS := -llog
+
 LOCAL_MODULE := libusb1.0
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libusb/core.c b/libusb/core.c
index 5df459a..3dc1ef6 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -2040,6 +2040,17 @@ static void usbi_log_str(struct libusb_context *ctx,
 	WCHAR wbuf[USBI_MAX_LOG_LEN];
 	MultiByteToWideChar(CP_ACP, 0, str, -1, wbuf, sizeof(wbuf));
 	OutputDebugStringW(wbuf);
+#elif defined(__ANDROID__)
+	int prio;
+	switch (level) {
+	case LIBUSB_LOG_LEVEL_INFO: prio = ANDROID_LOG_INFO; break;
+	case LIBUSB_LOG_LEVEL_WARNING: prio = ANDROID_LOG_WARN; break;
+	case LIBUSB_LOG_LEVEL_ERROR: prio = ANDROID_LOG_ERROR; break;
+	case LIBUSB_LOG_LEVEL_DEBUG: prio = ANDROID_LOG_DEBUG; break;
+	default: prio = ANDROID_LOG_UNKNOWN; break;
+	}
+
+	__android_log_write(prio, "LibUsb", str);
 #elif defined(HAVE_SYSLOG_FUNC)
 	int syslog_level = LOG_INFO;
 	switch (level) {
@@ -2083,28 +2094,6 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
 		return;
 #endif
 
-#ifdef __ANDROID__
-	int prio;
-	switch (level) {
-	case LOG_LEVEL_INFO:
-		prio = ANDROID_LOG_INFO;
-		break;
-	case LOG_LEVEL_WARNING:
-		prio = ANDROID_LOG_WARN;
-		break;
-	case LOG_LEVEL_ERROR:
-		prio = ANDROID_LOG_ERROR;
-		break;
-	case LOG_LEVEL_DEBUG:
-		prio = ANDROID_LOG_DEBUG;
-		break;
-	default:
-		prio = ANDROID_LOG_UNKNOWN;
-		break;
-	}
-
-	__android_log_vprint(prio, "LibUsb", format, args);
-#else
 	usbi_gettimeofday(&now, NULL);
 	if ((global_debug) && (!has_debug_header_been_displayed)) {
 		has_debug_header_been_displayed = 1;
@@ -2168,7 +2157,6 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
 	strcpy(buf + header_len + text_len, USBI_LOG_LINE_END);
 
 	usbi_log_str(ctx, level, buf);
-#endif
 }
 
 void usbi_log(struct libusb_context *ctx, enum libusb_log_level level,
diff --git a/libusb/os/linux_netlink.c b/libusb/os/linux_netlink.c
index 3a68f69..259f80b 100644
--- a/libusb/os/linux_netlink.c
+++ b/libusb/os/linux_netlink.c
@@ -52,14 +52,48 @@ struct sockaddr_nl snl = { .nl_family=AF_NETLINK, .nl_groups=KERNEL };
 int linux_netlink_start_event_monitor(void)
 {
 	int ret;
+	int sock_type = SOCK_RAW;
+
+#ifdef SOCK_CLOEXEC
+	sock_type |= SOCK_CLOEXEC;
+#endif
+#ifdef SOCK_NONBLOCK
+	sock_type |= SOCK_NONBLOCK;
+#endif
 
 	snl.nl_groups = KERNEL;
 
-	linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
+	linux_netlink_socket = socket(PF_NETLINK, sock_type, NETLINK_KOBJECT_UEVENT);
 	if (-1 == linux_netlink_socket) {
 		return LIBUSB_ERROR_OTHER;
 	}
 
+#ifndef SOCK_CLOEXEC
+	ret = fcntl(linux_netlink_socket, F_GETFD);
+	if (ret == -1) {
+		usbi_dbg("Failed to get netlink fd flags: %d", errno);
+		return LIBUSB_ERROR_OTHER;
+	}
+	ret = fcntl(linux_netlink_socket, F_SETFD, ret | FD_CLOEXEC);
+	if (ret == -1) {
+		usbi_dbg("Failed to set netlink fd flags: %d", errno);
+		return LIBUSB_ERROR_OTHER;
+	}
+#endif
+#ifndef SOCK_NONBLOCK
+	ret = fcntl(linux_netlink_socket, F_GETFL);
+	if (ret == -1) {
+		usbi_dbg("Failed to get netlink fd status flags: %d", errno);
+		return LIBUSB_ERROR_OTHER;
+	}
+	ret = fcntl(linux_netlink_socket, F_SETFL, ret | O_NONBLOCK);
+	if (ret == -1) {
+		usbi_dbg("Failed to set netlink fd status flags: %d", errno);
+		return LIBUSB_ERROR_OTHER;
+	}
+
+#endif
+
 	ret = bind(linux_netlink_socket, (struct sockaddr *) &snl, sizeof(snl));
 	if (0 != ret) {
 		return LIBUSB_ERROR_OTHER;
diff --git a/libusb/os/threads_posix.c b/libusb/os/threads_posix.c
index 9769f58..edf7063 100644
--- a/libusb/os/threads_posix.c
+++ b/libusb/os/threads_posix.c
@@ -63,7 +63,9 @@ finish:
 int usbi_get_tid(void)
 {
 	int ret = -1;
-#if defined(__linux__)
+#if defined(__ANDROID__)
+	ret = gettid();
+#elif defined(__linux__)
 	ret = syscall(SYS_gettid);
 #elif defined(__OpenBSD__)
 	/* The following only works with OpenBSD > 5.1 as it requires
-- 
1.7.9.5

>From 644f8f77e12844157564e0a23f791d7f7decc4a6 Mon Sep 17 00:00:00 2001
From: Toby Gray <toby.g...@realvnc.com>
Date: Tue, 9 Jul 2013 17:51:24 +0100
Subject: [PATCH 5/5] hotplug: Remove use of pthread_cancel from netlink
 hotplug code.

Before this change the netlink hotplug code made use of pthread_cancel
to wake up the hotplug thread. Some platforms, such as Android, do not
support pthread_cancel.

To allow hotplug to work on Android this change makes use of a usbi_pipe
to wake up the hotplug polling thread, in a very similar way to the
event pipes and hotplug pipes are used to wake up event handling.
---
 libusb/os/linux_netlink.c |   49 ++++++++++++++++++++++++++++++++++++---------
 1 file changed, 40 insertions(+), 9 deletions(-)

diff --git a/libusb/os/linux_netlink.c b/libusb/os/linux_netlink.c
index 259f80b..0233072 100644
--- a/libusb/os/linux_netlink.c
+++ b/libusb/os/linux_netlink.c
@@ -43,6 +43,7 @@
 #define KERNEL 1
 
 static int linux_netlink_socket = -1;
+static int linux_netlink_pipe[2] = {-1, -1};
 static pthread_t libusb_linux_event_thread;
 
 static void *linux_netlink_event_thread_main(void *arg);
@@ -70,24 +71,24 @@ int linux_netlink_start_event_monitor(void)
 
 #ifndef SOCK_CLOEXEC
 	ret = fcntl(linux_netlink_socket, F_GETFD);
-	if (ret == -1) {
+	if (-1 == ret) {
 		usbi_dbg("Failed to get netlink fd flags: %d", errno);
 		return LIBUSB_ERROR_OTHER;
 	}
 	ret = fcntl(linux_netlink_socket, F_SETFD, ret | FD_CLOEXEC);
-	if (ret == -1) {
+	if (-1 == ret) {
 		usbi_dbg("Failed to set netlink fd flags: %d", errno);
 		return LIBUSB_ERROR_OTHER;
 	}
 #endif
 #ifndef SOCK_NONBLOCK
 	ret = fcntl(linux_netlink_socket, F_GETFL);
-	if (ret == -1) {
+	if (-1 == ret) {
 		usbi_dbg("Failed to get netlink fd status flags: %d", errno);
 		return LIBUSB_ERROR_OTHER;
 	}
 	ret = fcntl(linux_netlink_socket, F_SETFL, ret | O_NONBLOCK);
-	if (ret == -1) {
+	if (-1 == ret) {
 		usbi_dbg("Failed to set netlink fd status flags: %d", errno);
 		return LIBUSB_ERROR_OTHER;
 	}
@@ -107,12 +108,19 @@ int linux_netlink_start_event_monitor(void)
 		return LIBUSB_ERROR_OTHER;
 	}
 
+	ret = usbi_pipe(linux_netlink_pipe);
+	if (0 != ret) {
+		usbi_dbg("Failed to open netlink status pipe: %d", errno);
+		return LIBUSB_ERROR_OTHER;
+	}
+
 	return LIBUSB_SUCCESS;
 }
 
 int linux_netlink_stop_event_monitor(void)
 {
 	int r;
+	char buf[1] = {0};
 
 	if (-1 == linux_netlink_socket) {
 		/* already closed. nothing to do */
@@ -125,8 +133,18 @@ int linux_netlink_stop_event_monitor(void)
 		return LIBUSB_ERROR_OTHER;
 	}
 
-	pthread_cancel(libusb_linux_event_thread);
+	/* Write a dummy byte down the pipe to wake up the thread */
+	r = usbi_write(linux_netlink_pipe[1], buf, sizeof(buf));
+	if (1 != r) {
+		usbi_dbg("Failed to write to netlink pipe: %d", errno);
+	}
+	/* Wait for it to exit */
+	pthread_join(libusb_linux_event_thread, NULL);
 
+	usbi_close(linux_netlink_pipe[0]);
+	linux_netlink_pipe[0] = -1;
+	usbi_close(linux_netlink_pipe[1]);
+	linux_netlink_pipe[1] = -1;
 	linux_netlink_socket = -1;
 
 	return LIBUSB_SUCCESS;
@@ -257,14 +275,27 @@ static int linux_netlink_read_message(void)
 
 static void *linux_netlink_event_thread_main(void *arg)
 {
-	struct pollfd fds = {.fd = linux_netlink_socket,
-			     .events = POLLIN};
+	struct pollfd fds[] = {
+		{.fd = linux_netlink_pipe[0],
+		 .events = POLLIN},
+		{.fd = linux_netlink_socket,
+		 .events = POLLIN},
+	};
 
 	/* silence compiler warning */
 	(void) arg;
 
-	while (1 == poll(&fds, 1, -1)) {
-		if (POLLIN != fds.revents) {
+	while (1 == poll(fds, sizeof(fds) / sizeof(fds[0]), -1)) {
+		if (POLLIN == fds[0].revents) {
+			/* Woken up due to write on signal pipe, read it and then stop */
+			char buf[1];
+			int ret = usbi_read(fds[0].fd, buf, sizeof(buf));
+			if (1 != ret) {
+				usbi_dbg("Failed to read from status pipe: %d", errno);
+			}
+			usbi_dbg("Woke up netlink thread on status pipe");
+			break;
+		} else if (POLLIN != fds[1].revents) {
 			break;
 		}
 
-- 
1.7.9.5

------------------------------------------------------------------------------
See everything from the browser to the database with AppDynamics
Get end-to-end visibility with application monitoring from AppDynamics
Isolate bottlenecks and diagnose root cause in seconds.
Start your free trial of AppDynamics Pro today!
http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk
_______________________________________________
libusbx-devel mailing list
libusbx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libusbx-devel

Reply via email to