/*
* Interrupt the iteration of the event handling thread, so that it picks
- * up the new fd.
+ * up the fd change.
*/
void usbi_fd_notification(struct libusb_context *ctx)
{
* 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;
+ ctx->pollfds_modified = 1;
if (!pending_events)
usbi_signal_event(ctx);
usbi_mutex_unlock(&ctx->event_data_lock);
usbi_mutex_unlock(&ctx->open_devs_lock);
*handle = _handle;
- if (usbi_backend->caps & USBI_CAP_HAS_POLLABLE_DEVICE_FD) {
- /* At this point, we want to interrupt any existing event handlers so
- * that they realise the addition of the new device's poll fd. One
- * example when this is desirable is if the user is running a separate
- * dedicated libusb events handling thread, which is running with a long
- * or infinite timeout. We want to interrupt that iteration of the loop,
- * so that it picks up the new fd, and then continues. */
- usbi_fd_notification(ctx);
- }
-
return 0;
}
int r;
usbi_mutex_init(&ctx->flying_transfers_lock, NULL);
- usbi_mutex_init(&ctx->pollfds_lock, NULL);
usbi_mutex_init_recursive(&ctx->events_lock, NULL);
- usbi_mutex_init(&ctx->event_data_lock, NULL);
usbi_mutex_init(&ctx->event_waiters_lock, NULL);
usbi_cond_init(&ctx->event_waiters_cond, NULL);
+ usbi_mutex_init_recursive(&ctx->event_data_lock, NULL);
list_init(&ctx->flying_transfers);
list_init(&ctx->ipollfds);
list_init(&ctx->hotplug_msgs);
usbi_close(ctx->event_pipe[1]);
err:
usbi_mutex_destroy(&ctx->flying_transfers_lock);
- usbi_mutex_destroy(&ctx->pollfds_lock);
usbi_mutex_destroy(&ctx->events_lock);
- usbi_mutex_destroy(&ctx->event_data_lock);
usbi_mutex_destroy(&ctx->event_waiters_lock);
usbi_cond_destroy(&ctx->event_waiters_cond);
+ usbi_mutex_destroy(&ctx->event_data_lock);
return r;
}
}
#endif
usbi_mutex_destroy(&ctx->flying_transfers_lock);
- usbi_mutex_destroy(&ctx->pollfds_lock);
usbi_mutex_destroy(&ctx->events_lock);
- usbi_mutex_destroy(&ctx->event_data_lock);
usbi_mutex_destroy(&ctx->event_waiters_lock);
usbi_cond_destroy(&ctx->event_waiters_cond);
+ usbi_mutex_destroy(&ctx->event_data_lock);
if (ctx->pollfds)
free(ctx->pollfds);
}
struct usbi_transfer *itransfer =
LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
int r;
- int updated_fds;
usbi_mutex_lock(&ctx->flying_transfers_lock);
usbi_mutex_lock(&itransfer->lock);
libusb_ref_device(transfer->dev_handle->dev);
}
out:
- updated_fds = (itransfer->flags & USBI_TRANSFER_UPDATED_FDS);
usbi_mutex_unlock(&itransfer->lock);
usbi_mutex_unlock(&ctx->flying_transfers_lock);
- if (updated_fds)
- usbi_fd_notification(ctx);
return r;
}
/* 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 */
- usbi_mutex_lock(&ctx->pollfds_lock);
+ usbi_mutex_lock(&ctx->event_data_lock);
if (ctx->pollfds_modified) {
usbi_dbg("poll fds modified, reallocating");
ctx->pollfds = calloc(ctx->pollfds_cnt, sizeof(*ctx->pollfds));
if (!ctx->pollfds) {
- usbi_mutex_unlock(&ctx->pollfds_lock);
+ usbi_mutex_unlock(&ctx->event_data_lock);
return LIBUSB_ERROR_NO_MEM;
}
/* reset the flag now that we have the updated list */
ctx->pollfds_modified = 0;
+
+ /* if no further pending events, clear the event pipe so that we do
+ * not immediately return from poll */
+ if (!usbi_pending_events(ctx))
+ usbi_clear_event(ctx);
}
fds = ctx->pollfds;
nfds = ctx->pollfds_cnt;
- usbi_mutex_unlock(&ctx->pollfds_lock);
+ usbi_mutex_unlock(&ctx->event_data_lock);
timeout_ms = (int)(tv->tv_sec * 1000) + (tv->tv_usec / 1000);
usbi_mutex_lock(&ctx->event_data_lock);
/* check if someone added a new poll fd */
- if (ctx->fd_notify) {
+ if (ctx->pollfds_modified)
usbi_dbg("someone updated the poll fds");
- ctx->fd_notify = 0;
- }
/* check if someone is closing a device */
if (ctx->device_close)
usbi_dbg("add fd %d events %d", fd, events);
ipollfd->pollfd.fd = fd;
ipollfd->pollfd.events = events;
- usbi_mutex_lock(&ctx->pollfds_lock);
+ usbi_mutex_lock(&ctx->event_data_lock);
list_add_tail(&ipollfd->list, &ctx->ipollfds);
ctx->pollfds_cnt++;
- ctx->pollfds_modified = 1;
- usbi_mutex_unlock(&ctx->pollfds_lock);
+ usbi_fd_notification(ctx);
+ usbi_mutex_unlock(&ctx->event_data_lock);
if (ctx->fd_added_cb)
ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
int found = 0;
usbi_dbg("remove fd %d", fd);
- usbi_mutex_lock(&ctx->pollfds_lock);
+ usbi_mutex_lock(&ctx->event_data_lock);
list_for_each_entry(ipollfd, &ctx->ipollfds, list, struct usbi_pollfd)
if (ipollfd->pollfd.fd == fd) {
found = 1;
if (!found) {
usbi_dbg("couldn't find fd %d to remove", fd);
- usbi_mutex_unlock(&ctx->pollfds_lock);
+ usbi_mutex_unlock(&ctx->event_data_lock);
return;
}
list_del(&ipollfd->list);
ctx->pollfds_cnt--;
- ctx->pollfds_modified = 1;
- usbi_mutex_unlock(&ctx->pollfds_lock);
+ usbi_fd_notification(ctx);
+ usbi_mutex_unlock(&ctx->event_data_lock);
free(ipollfd);
if (ctx->fd_removed_cb)
ctx->fd_removed_cb(fd, ctx->fd_cb_user_data);
size_t i = 0;
USBI_GET_CONTEXT(ctx);
- usbi_mutex_lock(&ctx->pollfds_lock);
+ usbi_mutex_lock(&ctx->event_data_lock);
ret = calloc(ctx->pollfds_cnt + 1, sizeof(struct libusb_pollfd *));
if (!ret)
ret[ctx->pollfds_cnt] = NULL;
out:
- usbi_mutex_unlock(&ctx->pollfds_lock);
+ usbi_mutex_unlock(&ctx->event_data_lock);
return (const struct libusb_pollfd **) ret;
#else
usbi_err(ctx, "external polling of libusb's internal descriptors "\
/* Backend specific capabilities */
#define USBI_CAP_HAS_HID_ACCESS 0x00010000
#define USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER 0x00020000
-#define USBI_CAP_HAS_POLLABLE_DEVICE_FD 0x00040000
/* Maximum number of bytes in a log line */
#define USBI_MAX_LOG_LEN 1024
struct list_head flying_transfers;
usbi_mutex_t flying_transfers_lock;
- /* list and count of poll fds and an array of poll fd structures that is
- * (re)allocated as necessary prior to polling, and a flag to indicate
- * when the list of poll fds has changed since the last poll. */
- struct list_head ipollfds;
- struct pollfd *pollfds;
- POLL_NFDS_TYPE pollfds_cnt;
- unsigned int pollfds_modified;
- usbi_mutex_t pollfds_lock;
-
/* user callbacks for pollfd changes */
libusb_pollfd_added_cb fd_added_cb;
libusb_pollfd_removed_cb fd_removed_cb;
/* used to see if there is an active thread doing event handling */
int event_handler_active;
+ /* used to wait for event completion in threads other than the one that is
+ * event handling */
+ usbi_mutex_t event_waiters_lock;
+ usbi_cond_t event_waiters_cond;
+
/* A lock to protect internal context event data. */
usbi_mutex_t event_data_lock;
* in order to safely close a device. Protected by event_data_lock. */
unsigned int device_close;
- /* A flag that is set when we want to interrupt event handling, in order to
- * pick up a new fd for polling. Protected by event_data_lock. */
- unsigned int fd_notify;
+ /* list and count of poll fds and an array of poll fd structures that is
+ * (re)allocated as necessary prior to polling, and a flag to indicate
+ * when the list of poll fds has changed since the last poll.
+ * Protected by event_data_lock. */
+ struct list_head ipollfds;
+ struct pollfd *pollfds;
+ POLL_NFDS_TYPE pollfds_cnt;
+ unsigned int pollfds_modified;
/* A list of pending hotplug messages. Protected by event_data_lock. */
struct list_head hotplug_msgs;
- /* used to wait for event completion in threads other than the one that is
- * event handling */
- usbi_mutex_t event_waiters_lock;
- usbi_cond_t event_waiters_cond;
-
#ifdef USBI_TIMERFD_AVAILABLE
/* used for timeout handling, if supported by OS.
* this timerfd is maintained to trigger on the next pending timeout */
/* 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))
+ ((ctx)->device_close || (ctx)->pollfds_modified || !list_empty(&(ctx)->hotplug_msgs))
#ifdef USBI_TIMERFD_AVAILABLE
#define usbi_using_timerfd(ctx) ((ctx)->timerfd >= 0)
/* Operation on the transfer failed because the device disappeared */
USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3,
-
- /* Set by backend submit_transfer() if the fds in use have been updated */
- USBI_TRANSFER_UPDATED_FDS = 1 << 4,
};
#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \
const struct usbi_os_backend darwin_backend = {
.name = "Darwin",
- .caps = USBI_CAP_HAS_POLLABLE_DEVICE_FD,
+ .caps = 0,
.init = darwin_init,
.exit = darwin_exit,
.get_device_list = NULL, /* not needed */
const struct usbi_os_backend linux_usbfs_backend = {
.name = "Linux usbfs",
- .caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER|USBI_CAP_HAS_POLLABLE_DEVICE_FD,
+ .caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER,
.init = op_init,
.exit = op_exit,
.get_device_list = NULL,
const struct usbi_os_backend netbsd_backend = {
"Synchronous NetBSD backend",
- USBI_CAP_HAS_POLLABLE_DEVICE_FD,
+ 0,
NULL, /* init() */
NULL, /* exit() */
netbsd_get_device_list,
const struct usbi_os_backend openbsd_backend = {
"Synchronous OpenBSD backend",
- USBI_CAP_HAS_POLLABLE_DEVICE_FD,
+ 0,
NULL, /* init() */
NULL, /* exit() */
obsd_get_device_list,
return libusbErr;
}
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT);
- itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
return LIBUSB_SUCCESS;
}
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
(short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
- itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
return LIBUSB_SUCCESS;
}
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
(short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
- itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
return LIBUSB_SUCCESS;
}
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
- itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
return LIBUSB_SUCCESS;
}