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>
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 @@ 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 @@ /* 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 @@ /* 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_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 @@ /* 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 @@ 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 @@ 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 @@ */ 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 @@ } /* 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 @@ /* 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 @@ */ 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 @@ 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 @@ /* 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 @@ 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 @@ 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