summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Dickens <christopher.a.dickens@gmail.com>2020-08-12 22:34:03 -0700
committerChris Dickens <christopher.a.dickens@gmail.com>2020-08-12 22:34:03 -0700
commit7b5e31b8cb427cd95a307c607741cc52a39cb951 (patch)
treee0b57deb1d8d527a1dfa705000d8a9a1121e208c
parentb40a26f9012c3b4fb29b589b97c37e9a32a06a5d (diff)
downloadlibusb-7b5e31b8cb427cd95a307c607741cc52a39cb951.tar.gz
core: Optimize check for pending events
Prior to this commit, a check for whether any events are pending involved checking four different variables within the context. Optimize this by using multiple bits within a single unsigned integer to represent all the possible events that could be pending. This reduces the check for whether any events are pending to a single load. Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
-rw-r--r--libusb/core.c15
-rw-r--r--libusb/hotplug.c13
-rw-r--r--libusb/io.c53
-rw-r--r--libusb/libusbi.h24
-rw-r--r--libusb/version_nano.h2
5 files changed, 59 insertions, 48 deletions
diff --git a/libusb/core.c b/libusb/core.c
index 692350a..29d767b 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -1437,8 +1437,8 @@ static void do_close(struct libusb_context *ctx,
void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
{
struct libusb_context *ctx;
+ unsigned int event_flags;
int handling_events;
- int pending_events;
if (!dev_handle)
return;
@@ -1459,9 +1459,10 @@ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
/* 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)
+ event_flags = ctx->event_flags;
+ if (!ctx->device_close++)
+ ctx->event_flags |= USBI_EVENT_DEVICE_CLOSE;
+ if (!event_flags)
usbi_signal_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock);
@@ -1476,9 +1477,9 @@ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
/* 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)
+ if (!--ctx->device_close)
+ ctx->event_flags &= ~USBI_EVENT_DEVICE_CLOSE;
+ if (!ctx->event_flags)
usbi_clear_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock);
diff --git a/libusb/hotplug.c b/libusb/hotplug.c
index 86aeed8..1b654e3 100644
--- a/libusb/hotplug.c
+++ b/libusb/hotplug.c
@@ -206,8 +206,8 @@ 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;
struct libusb_hotplug_message *message = calloc(1, sizeof(*message));
+ unsigned int event_flags;
if (!message) {
usbi_err(ctx, "error allocating hotplug message");
@@ -220,9 +220,10 @@ void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device
/* 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);
+ event_flags = ctx->event_flags;
+ ctx->event_flags |= USBI_EVENT_HOTPLUG_MSG_PENDING;
list_add_tail(&message->list, &ctx->hotplug_msgs);
- if (!pending_events)
+ if (!event_flags)
usbi_signal_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock);
}
@@ -341,12 +342,12 @@ void API_EXPORTED libusb_hotplug_deregister_callback(libusb_context *ctx,
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
if (deregistered) {
- int pending_events;
+ unsigned int event_flags;
usbi_mutex_lock(&ctx->event_data_lock);
- pending_events = usbi_pending_events(ctx);
+ event_flags = ctx->event_flags;
ctx->event_flags |= USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
- if (!pending_events)
+ if (!event_flags)
usbi_signal_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock);
}
diff --git a/libusb/io.c b/libusb/io.c
index 31a586e..3eedf44 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -1694,12 +1694,13 @@ void usbi_signal_transfer_completion(struct usbi_transfer *itransfer)
if (dev_handle) {
struct libusb_context *ctx = HANDLE_CTX(dev_handle);
- int pending_events;
+ unsigned int event_flags;
usbi_mutex_lock(&ctx->event_data_lock);
- pending_events = usbi_pending_events(ctx);
+ event_flags = ctx->event_flags;
+ ctx->event_flags |= USBI_EVENT_TRANSFER_COMPLETED;
list_add_tail(&itransfer->completed_list, &ctx->completed_transfers);
- if (!pending_events)
+ if (!event_flags)
usbi_signal_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock);
}
@@ -1877,16 +1878,16 @@ int API_EXPORTED libusb_event_handler_active(libusb_context *ctx)
*/
void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx)
{
- int pending_events;
+ unsigned int event_flags;
usbi_dbg(" ");
ctx = usbi_get_context(ctx);
usbi_mutex_lock(&ctx->event_data_lock);
- pending_events = usbi_pending_events(ctx);
+ event_flags = ctx->event_flags;
ctx->event_flags |= USBI_EVENT_USER_INTERRUPT;
- if (!pending_events)
+ if (!event_flags)
usbi_signal_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock);
@@ -2059,30 +2060,38 @@ static int handle_event_trigger(struct libusb_context *ctx)
}
/* check if someone is closing a device */
- if (ctx->device_close)
+ if (ctx->event_flags & USBI_EVENT_DEVICE_CLOSE)
usbi_dbg("someone is closing a device");
/* check for any pending hotplug messages */
- if (!list_empty(&ctx->hotplug_msgs)) {
+ if (ctx->event_flags & USBI_EVENT_HOTPLUG_MSG_PENDING) {
usbi_dbg("hotplug message received");
+ ctx->event_flags &= ~USBI_EVENT_HOTPLUG_MSG_PENDING;
+ assert(!list_empty(&ctx->hotplug_msgs));
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);
+ if (ctx->event_flags & USBI_EVENT_TRANSFER_COMPLETED) {
+ assert(!list_empty(&ctx->completed_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);
+ 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 (list_empty(&ctx->completed_transfers))
+ ctx->event_flags &= ~USBI_EVENT_TRANSFER_COMPLETED;
}
/* if no further pending events, clear the event */
- if (!usbi_pending_events(ctx))
+ if (!ctx->event_flags)
usbi_clear_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock);
@@ -2159,7 +2168,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
/* if no further pending events, clear the event so that we do
* not immediately return from the wait function */
- if (!usbi_pending_events(ctx))
+ if (!ctx->event_flags)
usbi_clear_event(&ctx->event);
}
usbi_mutex_unlock(&ctx->event_data_lock);
@@ -2579,13 +2588,13 @@ void API_EXPORTED libusb_set_pollfd_notifiers(libusb_context *ctx,
*/
static void usbi_event_source_notification(struct libusb_context *ctx)
{
- int pending_events;
+ unsigned int event_flags;
/* 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);
+ event_flags = ctx->event_flags;
ctx->event_flags |= USBI_EVENT_EVENT_SOURCES_MODIFIED;
- if (!pending_events)
+ if (!event_flags)
usbi_signal_event(&ctx->event);
}
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index afeb27a..4a3e9d5 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -392,6 +392,9 @@ struct libusb_context {
extern struct libusb_context *usbi_default_context;
+extern struct list_head active_contexts_list;
+extern usbi_mutex_static_t active_contexts_lock;
+
static inline struct libusb_context *usbi_get_context(struct libusb_context *ctx)
{
return ctx ? ctx : usbi_default_context;
@@ -406,6 +409,15 @@ enum usbi_event_flags {
/* A hotplug callback deregistration is pending */
USBI_EVENT_HOTPLUG_CB_DEREGISTERED = 1U << 2,
+
+ /* One or more hotplug messages are pending */
+ USBI_EVENT_HOTPLUG_MSG_PENDING = 1U << 3,
+
+ /* One or more completed transfers are pending */
+ USBI_EVENT_TRANSFER_COMPLETED = 1U << 4,
+
+ /* A device is in the process of being closed */
+ USBI_EVENT_DEVICE_CLOSE = 1U << 5,
};
/* Macros for managing event handling state */
@@ -424,15 +436,6 @@ static inline void usbi_end_event_handling(struct libusb_context *ctx)
usbi_tls_key_set(ctx->event_handling_key, NULL);
}
-/* Update the following function if new event sources are added */
-static inline int usbi_pending_events(struct libusb_context *ctx)
-{
- return ctx->event_flags ||
- ctx->device_close ||
- !list_empty(&ctx->hotplug_msgs) ||
- !list_empty(&ctx->completed_transfers);
-}
-
struct libusb_device {
/* lock protects refcnt, everything else is finalized at initialization
* time */
@@ -1286,9 +1289,6 @@ struct usbi_os_backend {
extern const struct usbi_os_backend usbi_backend;
-extern struct list_head active_contexts_list;
-extern usbi_mutex_static_t active_contexts_lock;
-
#define for_each_context(c) \
for_each_helper(c, &active_contexts_list, struct libusb_context)
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index c972e09..fd49514 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11533
+#define LIBUSB_NANO 11534