summaryrefslogtreecommitdiff
path: root/libusb/io.c
diff options
context:
space:
mode:
authorChris Dickens <christopher.a.dickens@gmail.com>2014-11-17 23:53:13 -0800
committerChris Dickens <chris.dickens@hp.com>2014-12-19 11:21:24 -0800
commit3b371f1a6ab30bdebdadfcde1b96a9b98fb806ca (patch)
treea670f3735a809e60a62ea422dd0f10eba3ef5959 /libusb/io.c
parentf5795bfa0e5d9e2ccd1e031d02269f041101aca7 (diff)
downloadlibusb-3b371f1a6ab30bdebdadfcde1b96a9b98fb806ca.tar.gz
core: Eliminate hotplug pipe, using list and event pipe instead
To further consolidate libusb internal events, this change removes the hotplug pipe. Hotplug messages are now kept in a list within the context, and the event pipe is signalled when a new hotplug message is added. When handling events, the hotplug messages will be processed from the list instead of from a separate pipe. This change is greatly beneficial for the Windows/WinCE backends which do not allow pipes to be used in the WaitFor* functions. Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
Diffstat (limited to 'libusb/io.c')
-rw-r--r--libusb/io.c91
1 files changed, 33 insertions, 58 deletions
diff --git a/libusb/io.c b/libusb/io.c
index f00af14..6ae4f8d 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -1118,6 +1118,7 @@ int usbi_io_init(struct libusb_context *ctx)
usbi_cond_init(&ctx->event_waiters_cond, NULL);
list_init(&ctx->flying_transfers);
list_init(&ctx->ipollfds);
+ list_init(&ctx->hotplug_msgs);
/* FIXME should use an eventfd on kernels that support it */
r = usbi_pipe(ctx->event_pipe);
@@ -1130,17 +1131,6 @@ int usbi_io_init(struct libusb_context *ctx)
if (r < 0)
goto err_close_pipe;
- /* create hotplug pipe */
- r = usbi_pipe(ctx->hotplug_pipe);
- if (r < 0) {
- r = LIBUSB_ERROR_OTHER;
- goto err_remove_pipe;
- }
-
- r = usbi_add_pollfd(ctx, ctx->hotplug_pipe[0], POLLIN);
- if (r < 0)
- goto err_close_hp_pipe;
-
#ifdef USBI_TIMERFD_AVAILABLE
ctx->timerfd = timerfd_create(usbi_backend->get_timerfd_clockid(),
TFD_NONBLOCK);
@@ -1160,13 +1150,8 @@ int usbi_io_init(struct libusb_context *ctx)
#ifdef USBI_TIMERFD_AVAILABLE
err_close_timerfd:
close(ctx->timerfd);
- usbi_remove_pollfd(ctx, ctx->hotplug_pipe[0]);
-#endif
-err_close_hp_pipe:
- usbi_close(ctx->hotplug_pipe[0]);
- usbi_close(ctx->hotplug_pipe[1]);
-err_remove_pipe:
usbi_remove_pollfd(ctx, ctx->event_pipe[0]);
+#endif
err_close_pipe:
usbi_close(ctx->event_pipe[0]);
usbi_close(ctx->event_pipe[1]);
@@ -1185,9 +1170,6 @@ void usbi_io_exit(struct libusb_context *ctx)
usbi_remove_pollfd(ctx, ctx->event_pipe[0]);
usbi_close(ctx->event_pipe[0]);
usbi_close(ctx->event_pipe[1]);
- usbi_remove_pollfd(ctx, ctx->hotplug_pipe[0]);
- usbi_close(ctx->hotplug_pipe[0]);
- usbi_close(ctx->hotplug_pipe[1]);
#ifdef USBI_TIMERFD_AVAILABLE
if (usbi_using_timerfd(ctx)) {
usbi_remove_pollfd(ctx, ctx->timerfd);
@@ -1978,17 +1960,16 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
/* there are certain fds that libusb uses internally, currently:
*
* 1) event pipe
- * 2) hotplug pipe
- * 3) timerfd
+ * 2) timerfd
*
* the backend will never need to attempt to handle events on these fds, so
* we determine how many fds are in use internally for this context and when
* handle_events() is called in the backend, the pollfd list and count will
* be adjusted to skip over these internal fds */
if (usbi_using_timerfd(ctx))
- internal_nfds = 3;
- else
internal_nfds = 2;
+ else
+ internal_nfds = 1;
/* only reallocate the poll fds when the list of poll fds has been modified
* since the last poll, otherwise reuse them to save the additional overhead */
@@ -2048,58 +2029,52 @@ redo_poll:
/* fds[0] is always the event pipe */
if (fds[0].revents) {
- /* another thread wanted to interrupt event handling, and it succeeded!
- * handle any other events that cropped up at the same time, and
- * simply return */
unsigned int ru;
+ libusb_hotplug_message *message = NULL;
usbi_dbg("caught a fish on the event pipe");
- /* read the dummy data from the event pipe unless someone is closing
- * a device */
+ /* take the the event data lock while processing events */
usbi_mutex_lock(&ctx->event_data_lock);
+
+ /* check if someone is closing a device */
ru = ctx->device_close;
- usbi_mutex_unlock(&ctx->event_data_lock);
- if (!ru) {
- r = usbi_clear_event(ctx);
- if (r)
- goto handled;
+
+ /* check for any pending hotplug messages */
+ if (!list_empty(&ctx->hotplug_msgs)) {
+ usbi_dbg("hotplug message received");
+ special_event = 1;
+ message = list_first_entry(&ctx->hotplug_msgs, libusb_hotplug_message, list);
+ list_del(&message->list);
}
- if (0 == --r)
- goto handled;
- }
+ usbi_mutex_unlock(&ctx->event_data_lock);
- /* fd[1] is always the hotplug pipe */
- if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && fds[1].revents) {
- libusb_hotplug_message message;
- ssize_t ret;
+ /* process the hotplug message, if any */
+ if (message) {
+ usbi_hotplug_match(ctx, message->device, message->event);
- usbi_dbg("caught a fish on the hotplug pipe");
- special_event = 1;
+ /* the device left, dereference the device */
+ if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message->event)
+ libusb_unref_device(message->device);
- /* read the message from the hotplug thread */
- ret = usbi_read(ctx->hotplug_pipe[0], &message, sizeof (message));
- if (ret != sizeof(message)) {
- usbi_err(ctx, "hotplug pipe read error %d != %u",
- ret, sizeof(message));
- r = LIBUSB_ERROR_OTHER;
- goto handled;
+ free(message);
}
- usbi_hotplug_match(ctx, message.device, message.event);
-
- /* the device left. dereference the device */
- if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message.event)
- libusb_unref_device(message.device);
+ /* 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;
- } /* else there shouldn't be anything on this pipe */
+ }
#ifdef USBI_TIMERFD_AVAILABLE
- /* on timerfd configurations, fds[2] is the timerfd */
- if (usbi_using_timerfd(ctx) && fds[2].revents) {
+ /* on timerfd configurations, fds[1] is the timerfd */
+ if (usbi_using_timerfd(ctx) && fds[1].revents) {
/* timerfd indicates that a timeout has expired */
int ret;
usbi_dbg("timerfd triggered");