diff options
author | Vitali Lovich <vlovich@aliph.com> | 2011-03-16 19:51:40 -0700 |
---|---|---|
committer | Peter Stuge <peter@stuge.se> | 2011-07-24 22:29:09 +0200 |
commit | c775c2f43037cd235b65410583179195e25f9c4a (patch) | |
tree | 54fb2d1a6ffb1cc21b9516738032a857fc08c7ce /libusb/core.c | |
parent | 74282582cc879f091ad1d847411337bc3fa78a2b (diff) | |
download | libusbx-c775c2f43037cd235b65410583179195e25f9c4a.tar.gz |
Clean up in-flight transfers and device handle when closing a device
Any in-flight transfers should properly invalidate their references
to device handles that are being closed. Additionally, they should be
removed from the transfer-in-flight list. This is done with the events
lock held to protect against another thread processing the same transfer.
The events lock is initialized as a recursive mutex, because the device
close code might itself be called while an event is being handled.
Fixes #82.
[stuge: Trivial rework to reduce indenting]
Diffstat (limited to 'libusb/core.c')
-rw-r--r-- | libusb/core.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/libusb/core.c b/libusb/core.c index c40d9d5..afe9e6e 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -1011,6 +1011,51 @@ out: static void do_close(struct libusb_context *ctx, struct libusb_device_handle *dev_handle) { + struct usbi_transfer *itransfer; + struct usbi_transfer *tmp; + + libusb_lock_events(ctx); + + /* remove any transfers in flight that are for this device */ + usbi_mutex_lock(&ctx->flying_transfers_lock); + + /* safe iteration because transfers may be being deleted */ + list_for_each_entry_safe(itransfer, tmp, &ctx->flying_transfers, list, struct usbi_transfer) { + struct libusb_transfer *transfer = + __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + + if (transfer->dev_handle != dev_handle) + continue; + + if (!(itransfer->flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) { + usbi_err(ctx, "Device handle closed while transfer was still being processed, but the device is still connected as far as we know"); + + if (itransfer->flags & USBI_TRANSFER_CANCELLING) + usbi_warn(ctx, "A cancellation for an in-flight transfer hasn't completed but closing the device handle"); + else + usbi_err(ctx, "A cancellation hasn't even been scheduled on the transfer for which the device is closing"); + } + + /* remove from the list of in-flight transfers and make sure + * we don't accidentally use the device handle in the future + * (or that such accesses will be easily caught and identified as a crash) + */ + usbi_mutex_lock(&itransfer->lock); + list_del(&itransfer->list); + transfer->dev_handle = NULL; + usbi_mutex_unlock(&itransfer->lock); + + /* it is up to the user to free up the actual transfer struct. this is + * just making sure that we don't attempt to process the transfer after + * the device handle is invalid + */ + usbi_dbg("Removed transfer %p from the in-flight list because device handle %p closed", + transfer, dev_handle); + } + usbi_mutex_unlock(&ctx->flying_transfers_lock); + + libusb_unlock_events(ctx); + usbi_mutex_lock(&ctx->open_devs_lock); list_del(&dev_handle->list); usbi_mutex_unlock(&ctx->open_devs_lock); |