summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Meissner <marcus@jet.franken.de>2015-06-14 13:37:09 +0000
committerMarcus Meissner <marcus@jet.franken.de>2015-06-14 13:37:09 +0000
commit46f30c89b189b1ecc32ca0839d895b2ca7f7f7f4 (patch)
treeae9cdbb22278fad24ada1e6fc39a49a2c1d4f797
parent6738adb1956c8a15580f81db664a4e2ac1b45fcf (diff)
downloadlibgphoto2-46f30c89b189b1ecc32ca0839d895b2ca7f7f7f4.tar.gz
changed the cancellation of the async usb transfers so that it does not
hang git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@15459 67ed7778-7388-44ab-90cf-0a291f65f57c
-rw-r--r--libgphoto2_port/libusb1/libusb1.c60
1 files changed, 36 insertions, 24 deletions
diff --git a/libgphoto2_port/libusb1/libusb1.c b/libgphoto2_port/libusb1/libusb1.c
index 8900ffc72..25c973482 100644
--- a/libgphoto2_port/libusb1/libusb1.c
+++ b/libgphoto2_port/libusb1/libusb1.c
@@ -435,19 +435,41 @@ static int
gp_libusb1_close (GPPort *port)
{
int i, haveone;
+
C_PARAMS (port);
if (port->pl->dh == NULL)
return GP_OK;
+ /* Cancel and free the async transfers */
+ for (i = 0; i < sizeof(port->pl->transfers)/sizeof(port->pl->transfers[0]); i++) {
+ GP_LOG_D("canceling transfer %d:%p (status %d)",i, port->pl->transfers[i], port->pl->transfers[i]->status);
+ if (port->pl->transfers[i]) {
+ /* this happens if the transfer is completed for instance, but not reaped. we cannot cancel it. */
+ if (LOG_ON_LIBUSB_E(libusb_cancel_transfer(port->pl->transfers[i])) < 0) {
+ libusb_free_transfer (port->pl->transfers[i]);
+ port->pl->transfers[i] = NULL;
+ }
+ }
+ }
+ /* Do just one loop ... this should be sufficient and avoids endless loops. */
+ haveone = 0;
+ for (i = 0; i < sizeof(port->pl->transfers)/sizeof(port->pl->transfers[0]); i++) {
+ if (port->pl->transfers[i]) {
+ GP_LOG_D("checking: transfer %d:%p status %d",i, port->pl->transfers[i], port->pl->transfers[i]->status);
+ haveone = 1;
+ }
+ }
+ if (haveone)
+ LOG_ON_LIBUSB_E (libusb_handle_events(port->pl->ctx));
+
if (libusb_release_interface (port->pl->dh,
port->settings.usb.interface) < 0) {
int saved_errno = errno;
- gp_port_set_error (port, _("Could not release "
- "interface %d (%s)."),
+ gp_port_set_error (port, _("Could not release interface %d (%s)."),
port->settings.usb.interface,
strerror(saved_errno));
- return (GP_ERROR_IO);
+ return GP_ERROR_IO;
}
#if 0
@@ -470,23 +492,6 @@ gp_libusb1_close (GPPort *port)
gp_port_set_error (port, _("Could not reattach kernel driver of camera device."));
}
-
- /* FIXME: free the transfers */
- for (i = 0; i < sizeof(port->pl->transfers)/sizeof(port->pl->transfers[0]); i++)
- if (port->pl->transfers[i])
- libusb_cancel_transfer(port->pl->transfers[i]);
- haveone = 1;
- while (haveone) {
- haveone = 0;
- for (i = 0; i < sizeof(port->pl->transfers)/sizeof(port->pl->transfers[0]); i++)
- if (port->pl->transfers[i])
- haveone = 1;
- if (haveone)
- if (libusb_handle_events(port->pl->ctx) < 0)
- break;
- }
-
-
libusb_close (port->pl->dh);
free (port->pl->irqs);
@@ -564,10 +569,14 @@ static void LIBUSB_CALL
_cb_irq(struct libusb_transfer *transfer)
{
struct _GPPortPrivateLibrary *pl = transfer->user_data;
+ int i;
- if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
- int i;
+ GP_LOG_D("%p with status %d", transfer, transfer->status);
+ if ( (transfer->status == LIBUSB_TRANSFER_CANCELLED) ||
+ (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) || /* on close */
+ (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) /* on removing camera */
+ ) {
/* Only requeue the global transfers, not temporary ones */
for (i = 0; i < sizeof(pl->transfers)/sizeof(pl->transfers[0]); i++) {
if (pl->transfers[i] == transfer) {
@@ -595,7 +604,9 @@ _cb_irq(struct libusb_transfer *transfer)
pl->nrofirqs++;
}
- libusb_submit_transfer(transfer);
+ GP_LOG_D("requeuing complete transfer %p", transfer);
+ LOG_ON_LIBUSB_E(libusb_submit_transfer(transfer));
+ return;
}
static int
@@ -612,7 +623,8 @@ gp_libusb1_queue_interrupt_urbs (GPPort *port)
buf, 256, _cb_irq, port->pl, 0
);
port->pl->transfers[i]->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
- libusb_submit_transfer (port->pl->transfers[i]);
+ LOG_ON_LIBUSB_E(libusb_submit_transfer (port->pl->transfers[i]));
+
}
return GP_OK;
}