summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libusb/core.c30
-rw-r--r--libusb/hotplug.c9
-rw-r--r--libusb/io.c21
-rw-r--r--libusb/libusbi.h4
-rw-r--r--libusb/version_nano.h2
5 files changed, 41 insertions, 25 deletions
diff --git a/libusb/core.c b/libusb/core.c
index 626fabc..9894209 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -1200,13 +1200,16 @@ int usbi_clear_event(struct libusb_context *ctx)
*/
void usbi_fd_notification(struct libusb_context *ctx)
{
- /* record that there is a new poll fd */
+ int pending_events;
+
+ /* Record that there is a new poll fd.
+ * Only signal an event if there are no prior pending events. */
usbi_mutex_lock(&ctx->event_data_lock);
+ pending_events = usbi_pending_events(ctx);
ctx->fd_notify = 1;
+ if (!pending_events)
+ usbi_signal_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
-
- /* signal the event pipe to interrupt event handlers */
- usbi_signal_event(ctx);
}
/** \ingroup dev
@@ -1407,6 +1410,7 @@ static void do_close(struct libusb_context *ctx,
void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
{
struct libusb_context *ctx;
+ int pending_events;
if (!dev_handle)
return;
@@ -1420,26 +1424,28 @@ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
* thread from doing event handling) because we will be removing a file
* descriptor from the polling loop. */
- /* record that we are closing a device */
+ /* Record that we are closing a device.
+ * Only signal an event if there are no prior pending events. */
usbi_mutex_lock(&ctx->event_data_lock);
+ pending_events = usbi_pending_events(ctx);
ctx->device_close++;
+ if (!pending_events)
+ usbi_signal_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
- /* signal the event pipe to interrupt event handlers */
- usbi_signal_event(ctx);
-
/* take event handling lock */
libusb_lock_events(ctx);
- /* clear the event pipe */
- usbi_clear_event(ctx);
-
/* Close the device */
do_close(ctx, dev_handle);
- /* we're done with closing this device */
+ /* We're done with closing this device.
+ * Clear the event pipe if there are no further pending events. */
usbi_mutex_lock(&ctx->event_data_lock);
ctx->device_close--;
+ pending_events = usbi_pending_events(ctx);
+ if (!pending_events)
+ usbi_clear_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
/* Release event handling lock and wake up event waiters */
diff --git a/libusb/hotplug.c b/libusb/hotplug.c
index 9171f2c..3ac159f 100644
--- a/libusb/hotplug.c
+++ b/libusb/hotplug.c
@@ -206,6 +206,7 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event)
{
+ int pending_events;;
libusb_hotplug_message *message = calloc(1, sizeof(*message));
if (!message) {
@@ -216,12 +217,14 @@ void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device
message->event = event;
message->device = dev;
- /* Take the event data lock and add this message to the list. */
+ /* Take the event data lock and add this message to the list.
+ * Only signal an event if there are no prior pending events. */
usbi_mutex_lock(&ctx->event_data_lock);
+ pending_events = usbi_pending_events(ctx);
list_add_tail(&message->list, &ctx->hotplug_msgs);
+ if (!pending_events)
+ usbi_signal_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
-
- usbi_signal_event(ctx);
}
int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
diff --git a/libusb/io.c b/libusb/io.c
index 6ae4f8d..a5fda69 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -2029,7 +2029,6 @@ redo_poll:
/* fds[0] is always the event pipe */
if (fds[0].revents) {
- unsigned int ru;
libusb_hotplug_message *message = NULL;
usbi_dbg("caught a fish on the event pipe");
@@ -2037,8 +2036,15 @@ redo_poll:
/* 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->fd_notify) {
+ usbi_dbg("someone updated the poll fds");
+ ctx->fd_notify = 0;
+ }
+
/* check if someone is closing a device */
- ru = ctx->device_close;
+ if (ctx->device_close)
+ usbi_dbg("someone is closing a device");
/* check for any pending hotplug messages */
if (!list_empty(&ctx->hotplug_msgs)) {
@@ -2048,6 +2054,10 @@ redo_poll:
list_del(&message->list);
}
+ /* 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);
/* process the hotplug message, if any */
@@ -2061,13 +2071,6 @@ redo_poll:
free(message);
}
- /* clear the event pipe if this was an fd or hotplug notification */
- if (!ru || message) {
- r = usbi_clear_event(ctx);
- if (r)
- goto handled;
- }
-
if (0 == --r)
goto handled;
}
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index c94c5a2..2d2f71a 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -317,6 +317,10 @@ struct libusb_context {
struct list_head list;
};
+/* Update the following macro if new event sources are added */
+#define usbi_pending_events(ctx) \
+ ((ctx)->device_close || (ctx)->fd_notify || !list_empty(&(ctx)->hotplug_msgs))
+
#ifdef USBI_TIMERFD_AVAILABLE
#define usbi_using_timerfd(ctx) ((ctx)->timerfd >= 0)
#else
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 90d77c5..dad6c22 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10938
+#define LIBUSB_NANO 10939