Without this change the Windows backend needed to call usbi_fd_notification()
from within the backend's submit_transfer. This can cause deadlock when
attempting to lock the event lock if another thread was processing events on
the just-submitted transfer.
The deadlock comes about as the thread calling libusb_submit_transfer acquires
the transfer mutex before trying to acquire the event lock; this is the other
order of lock acquisition from an event thread handling activity on the just
submitted transfer. This could lead to one of two deadlocks:
1) If the transfer completes while usbi_fd_notification() is waiting for
the event lock and the callback attempts to resubmit the transfer.
2) If the transfer timeout is hit while usbi_fd_notification() is waiting
for the event lock then the attempt to cancel the transfer will deadlock.
This patch fixes both of these deadlocks by having libusb_submit_transfer()
only call usbi_fd_notification() after having released the transfer mutex.
LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
int r;
int first;
LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
int r;
int first;
usbi_mutex_lock(&itransfer->lock);
itransfer->transferred = 0;
usbi_mutex_lock(&itransfer->lock);
itransfer->transferred = 0;
+ updated_fds = (itransfer->flags & USBI_TRANSFER_UPDATED_FDS);
usbi_mutex_unlock(&itransfer->lock);
usbi_mutex_unlock(&itransfer->lock);
+ if (updated_fds)
+ usbi_fd_notification(ctx);
/* Operation on the transfer failed because the device disappeared */
USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3,
/* 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) \
};
#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
(short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
(short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
- usbi_fd_notification(ctx);
+ itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
(short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
(short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
- usbi_fd_notification(ctx);
+ itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
- usbi_fd_notification(ctx);
+ itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
#define LIBUSB_MICRO 10
#endif
#ifndef LIBUSB_NANO
#define LIBUSB_MICRO 10
#endif
#ifndef LIBUSB_NANO
-#define LIBUSB_NANO 10488
+#define LIBUSB_NANO 10489
#endif
/* LIBUSB_RC is the release candidate suffix. Should normally be empty. */
#ifndef LIBUSB_RC
#endif
/* LIBUSB_RC is the release candidate suffix. Should normally be empty. */
#ifndef LIBUSB_RC