Blob Blame History Raw
From 852efb5a3e82de43cf6288e9904cb254ff636aa0 Mon Sep 17 00:00:00 2001
From: Chris Dickens <christopher.a.dickens@gmail.com>
Date: Sat, 20 Jul 2013 13:01:41 -0700
Subject: [PATCH 2/2] hotplug: Remove use of pthread_cancel from linux_udev

Using pthread_cancel() presents the opportunity for deadlock, so
use a control pipe to cause the event thread to gracefully exit.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 libusb/os/linux_udev.c | 63 ++++++++++++++++++++++++++++++++++++++------------
 libusb/version_nano.h  |  2 +-
 2 files changed, 49 insertions(+), 16 deletions(-)

diff --git a/libusb/os/linux_udev.c b/libusb/os/linux_udev.c
index 5a2aadf..70f632d 100644
--- a/libusb/os/linux_udev.c
+++ b/libusb/os/linux_udev.c
@@ -46,6 +46,7 @@
 /* udev context */
 static struct udev *udev_ctx = NULL;
 static int udev_monitor_fd = -1;
+static int udev_control_pipe[2] = {-1, -1};
 static struct udev_monitor *udev_monitor = NULL;
 static pthread_t linux_event_thread;
 
@@ -95,14 +96,23 @@ int linux_udev_start_event_monitor(void)
 		goto err_free_monitor;
 	}
 
+	r = usbi_pipe(udev_control_pipe);
+	if (r) {
+		usbi_err(NULL, "could not create udev control pipe");
+		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_free_monitor;
+		goto err_close_pipe;
 	}
 
 	return LIBUSB_SUCCESS;
 
+err_close_pipe:
+	close(udev_control_pipe[0]);
+	close(udev_control_pipe[1]);
 err_free_monitor:
 	udev_monitor_unref(udev_monitor);
 	udev_monitor = NULL;
@@ -115,14 +125,19 @@ err_free_ctx:
 
 int linux_udev_stop_event_monitor(void)
 {
+	char dummy = 1;
+	int r;
+
 	assert(udev_ctx != NULL);
 	assert(udev_monitor != NULL);
 	assert(udev_monitor_fd != -1);
 
-	/* Cancel the event thread. This is the only way to guarantee the
-	   thread exits since closing the monitor fd won't necessarily cause
-	   poll to return. */
-	pthread_cancel(linux_event_thread);
+	/* Write some dummy data to the control pipe and
+	 * wait for the thread to exit */
+	r = usbi_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);
 
 	/* Release the udev monitor */
@@ -134,27 +149,45 @@ 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;
 	struct udev_device* udev_dev;
-	struct pollfd fds = {.fd = udev_monitor_fd,
-			     .events = POLLIN};
+	struct pollfd fds[] = {
+		{.fd = udev_control_pipe[0],
+		 .events = POLLIN},
+		{.fd = udev_monitor_fd,
+		 .events = POLLIN},
+	};
 
 	usbi_dbg("udev event thread entering.");
 
-	while (1 == poll(&fds, 1, -1)) {
-		if (NULL == udev_monitor || POLLIN != fds.revents) {
+	while (poll(fds, 2, -1) >= 0) {
+		if (fds[0].revents & POLLIN) {
+			/* activity on control pipe, read the byte and exit */
+			r = usbi_read(udev_control_pipe[0], &dummy, sizeof(dummy));
+			if (r <= 0) {
+				usbi_warn(NULL, "udev control pipe read failed");
+			}
 			break;
 		}
-
-		usbi_mutex_static_lock(&linux_hotplug_lock);
-		udev_dev = udev_monitor_receive_device(udev_monitor);
-		if (udev_dev)
-			udev_hotplug_event(udev_dev);
-		usbi_mutex_static_unlock(&linux_hotplug_lock);
+		if (fds[1].revents & POLLIN) {
+			usbi_mutex_static_lock(&linux_hotplug_lock);
+			udev_dev = udev_monitor_receive_device(udev_monitor);
+			if (udev_dev)
+				udev_hotplug_event(udev_dev);
+			usbi_mutex_static_unlock(&linux_hotplug_lock);
+		}
 	}
 
 	usbi_dbg("udev event thread exiting");
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 34e26ff..39ad7e3 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10777
+#define LIBUSB_NANO 10778
-- 
1.8.3.1