summaryrefslogtreecommitdiff
path: root/core/libusbx/0002-hotplug-Remove-use-of-pthread_cancel-from-linux_udev.patch
blob: 5342fbe7005b33869bc78447f363c0f509cb8f9a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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