Bug 231076 - libusb_cancel_transfer() does NOT cancel a transfer after the USB device is removed
Summary: libusb_cancel_transfer() does NOT cancel a transfer after the USB device is r...
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: usb (show other bugs)
Version: 10.4-STABLE
Hardware: Any Any
: --- Affects Some People
Assignee: Hans Petter Selasky
URL:
Keywords:
: 231322 (view as bug list)
Depends on:
Blocks:
 
Reported: 2018-09-01 15:20 UTC by Ludovic Rousseau
Modified: 2018-09-19 08:10 UTC (History)
2 users (show)

See Also:


Attachments
LibUSB patch (695 bytes, patch)
2018-09-05 15:51 UTC, Hans Petter Selasky
no flags Details | Diff
LibUSB patch WIP (5.74 KB, patch)
2018-09-09 20:22 UTC, Hans Petter Selasky
no flags Details | Diff
LibUSB patch (7.73 KB, patch)
2018-09-12 10:04 UTC, Hans Petter Selasky
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ludovic Rousseau 2018-09-01 15:20:28 UTC
I am the author of the CCID driver: a driver for smart card readers compliant to the USB CCID specification.

My driver uses /usr/lib/libusb.so.3
$ ldd /usr/local/lib/pcsc/drivers/ifd-ccid.bundle/Contents/FreeBSD/libccid.so 
/usr/local/lib/pcsc/drivers/ifd-ccid.bundle/Contents/FreeBSD/libccid.so:
	libusb.so.3 => /usr/lib/libusb.so.3 (0x2821c000)
	libthr.so.3 => /lib/libthr.so.3 (0x2822d000)
	libc.so.7 => /lib/libc.so.7 (0x2807a000)


In my driver I use a transfer on an USB interrupt pipe to wait for card movements events (a card is inserted or removed in the reader) with a timeout of 10 minutes.
I use the asynchronous calls of libusb. The source of my function InterruptRead() is available at https://github.com/LudovicRousseau/CCID/blob/master/src/ccid_usb.c#L1294

When a USB reader is removed I have to cleanup and unload the driver so it cancels any transfer on the interrupt pipe. To do that I use libusb_cancel_transfer() in my function InterruptStop(). see https://github.com/LudovicRousseau/CCID/blob/master/src/ccid_usb.c#L1380

My problem is that libusb_cancel_transfer() returns with LIBUSB_ERROR_NOT_FOUND (because the USB device has been removed and is no more present?) and the current transfer is NOT cancelled. My driver is still blocked in the libusb_handle_events_completed() waiting for the function to return.

I looked at the FreeBSD libusb code. The error code LIBUSB_ERROR_NOT_FOUND is returned just at the beginning of the libusb_cancel_transfer() function at https://github.com/freebsd/freebsd/blob/master/lib/libusb/libusb10.c#L1501

I have no patch to propose.
Maybe libusb_cancel_transfer() should try to wake up libusb_handle_events_completed() even if the USB device is no more present.

The problem is very easy to reproduce on my side.
Comment 1 Hans Petter Selasky freebsd_committer 2018-09-02 18:22:18 UTC
Hi,

I sounds like you have closed the libusb handle before trying to cancel the USB transfers. What libusb_xxx() calls are you making before the libusb_cancel_transfer() fails? Sounds like a race.

--HPS
Comment 2 Hans Petter Selasky freebsd_committer 2018-09-02 18:26:45 UTC
Or that the LibUSB v1.0 transfer was never actually setup and submitted?
Comment 3 Ludovic Rousseau 2018-09-03 16:32:45 UTC
I added logs in my code.
When I start the transfer I have:
00000006 ccid_usb.c:1329:InterruptRead() uxfer->dev_handle: 0x28c0c9c0

When I cancel the transfer I have:
00000004 ccid_usb.c:1399:InterruptStop() uxfer->dev_handle: 0x28c0c9c0

So the problem is not at line 1501 as I initially mentioned. https://github.com/freebsd/freebsd/blob/master/lib/libusb/libusb10.c#L1501

No, the handle has not been closed. libusb_close() is called _after_ the transfer is cancelled.

Yes, the transfer has started. At least I get no error when I start it.

Yes, I get data from the interrupt pipe when a smart card is inserted or removed. So the USB communication does work with the interrupt pipe.

Yes, I can cancel the transfer when the USB device is present. The program does that when Ctrl-C is used to stop it.

The problem happens when the USB device is no more connected.

I added a call to libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_DEBUG); in my code but I don't see more debug.
I see that libusb uses DPRINTF(). How can I get the generated log messages?
Comment 4 Hans Petter Selasky freebsd_committer 2018-09-03 16:56:26 UTC
>I added a call to libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_DEBUG); in my code but
>I don't see more debug.
>I see that libusb uses DPRINTF(). How can I get the generated log messages?

        LIBUSB_DEBUG_NO=0,
        LIBUSB_DEBUG_FUNCTION=1,
        LIBUSB_DEBUG_TRANSFER=2,

Try using one of the above arguments when calling libusb_set_debug().

--HPS
Comment 5 Ludovic Rousseau 2018-09-04 16:42:28 UTC
I get log message when using libusb_set_debug(ctx, LIBUSB_DEBUG_FUNCTION);

After I remove the device I get:
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
04338703 hotplug_libusb.c:626:HPRemoveHotPluggable() Removing USB device[0]: 0:2:0
00000009 readerfactory.c:610:RFRemoveReader() UnrefReader() count was: 1
00000003 eventhandler.c:175:EHDestroyEventHandler() Stomping thread.
00000005 ifdhandler.c:381:IFDHGetCapabilities() tag: 0xFB1, usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000003 ifdhandler.c:381:IFDHGetCapabilities() tag: 0xFB2, usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000004 eventhandler.c:200:EHDestroyEventHandler() Request stopping of polling thread
00000004 ifdhandler.c:346:IFDHStopPolling() usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000003 ccid_usb.c:1399:InterruptStop() uxfer->dev_handle: 0x28c0c9c0
LIBUSB_FUNCTION: libusb_cancel_transfer enter
LIBUSB_FUNCTION: libusb_cancel_transfer leave
00000010 ccid_usb.c:1403:InterruptStop() libusb_cancel_transfer failed: LIBUSB_ERROR_NOT_FOUND

I guess I now have to instrument libusb to get more logs.
How can I rebuild libusb?
Comment 6 Ludovic Rousseau 2018-09-04 17:05:22 UTC
I added more logs in libusb, rebuilt and installed.

The problem is that I get in the "not started" case:
https://github.com/freebsd/freebsd/blob/master/lib/libusb/libusb10.c#L1546

I logged all the fields used in the if/else cases:
LIBUSB_FUNCTION: libusb_cancel_transfer enter
LIBUSB_FUNCTION: state: 1
LIBUSB_FUNCTION: entry.tqe_prev: 0x0
LIBUSB_FUNCTION: sxfer: 0x29007060
LIBUSB_FUNCTION: pxfer0: 0x28c2f348
LIBUSB_FUNCTION: pxfer1: 0x28c2f384
LIBUSB_FUNCTION: libusb20_tr_get_priv_sc1(pxfer0): 0x0
LIBUSB_FUNCTION: libusb20_tr_get_priv_sc1(pxfer1): 0x0
LIBUSB_FUNCTION: libusb_cancel_transfer leave

I don't know yet why libusb20_tr_get_priv_sc1() returns NULL.

What else should I do?
Comment 7 Hans Petter Selasky freebsd_committer 2018-09-04 19:24:03 UTC
The private pointer is set when you submit a transfer. It basically means that the transfer was never submitted. See:

libusb20_tr_set_priv_sc1(pxfer0, sxfer);

Do you have a printout for error codes in the completion function?

--HPS
Comment 8 Hans Petter Selasky freebsd_committer 2018-09-04 19:25:07 UTC
Try to collect logs using LIBUSB_DEBUG_TRANSFER aswell.
Comment 9 Ludovic Rousseau 2018-09-05 10:08:29 UTC
When the USB device is removed libusb10_handle_events_sub() will call libusb10_cancel_all_transfer() at https://github.com/freebsd/freebsd/blob/master/lib/libusb/libusb10_io.c#L170

libusb10_cancel_all_transfer() will then call libusb20_tr_close() at https://github.com/freebsd/freebsd/blob/master/lib/libusb/libusb10.c#L1570

libusb20_tr_close() will then reset the variable fields at https://github.com/freebsd/freebsd/blob/master/lib/libusb/libusb20.c#L142

So when libusb_cancel_transfer() is called by my code the fields priv_sc0 and priv_sc1 are already reset to 0 and libusb_cancel_transfer() returns LIBUSB_ERROR_NOT_FOUND in https://github.com/freebsd/freebsd/blob/master/lib/libusb/libusb10.c#L1547

I can test any patch you propose to fix the issue.
Comment 10 Ludovic Rousseau 2018-09-05 10:15:04 UTC
I have no problem with libusb_cancel_transfer() failing with the error LIBUSB_ERROR_NOT_FOUND. I can handle that.

My problem is that libusb_handle_events_completed() (in another thread) does NOT return.
On device removal it looks like the USB transfers are cancelled at the libusb internal level but not for libusb_handle_events_completed().
Comment 11 Hans Petter Selasky freebsd_committer 2018-09-05 15:33:25 UTC
> My problem is that libusb_handle_events_completed() (in another thread) does NOT return.

I see.

Are you aware about libusb_handle_events_timeout_completed()?

From what I can see "libusb_close()" will write a byte on the control pipe which should wakeup libusb_handle_events_completed(). Are you waiting for this wakeup before calling libusb_close() or after?

--HPS
Comment 12 Hans Petter Selasky freebsd_committer 2018-09-05 15:36:58 UTC
There also exist: libusb_handle_events_completed(), with the specific purpose to set the completed=1, when you want to force the wait loop to exit. This should be done before calling libusb_close().

Refer to the LibUSB manual pages on the internet for how to use.
Comment 13 Hans Petter Selasky freebsd_committer 2018-09-05 15:51:41 UTC
Created attachment 196888 [details]
LibUSB patch

Does this patch help?
Comment 14 Hans Petter Selasky freebsd_committer 2018-09-05 16:31:24 UTC
My analysis is the following that FreeBSD lacks a libusb transfer completion event when a USB device is detached. This state can be detected using libusb_check_connected(), which returns non-zero when the USB device has been detached.

The problem can be worked around by signalling the worker thread from the close function, which then makes poll()/libusb_handle_events_completed() return and then you simply do:

#ifdef __FreeBSD__
 if (libusb_check_connected(udevh)) {
	libusb_free_transfer(transfer);
	return IFD_COMMUNICATION_ERROR;
 }
#endif
Comment 15 Hans Petter Selasky freebsd_committer 2018-09-05 16:41:24 UTC
Signalling the worker thread results in libusb_handle_events_completed() returning non-zero:

Something like this:

err = libusb_handle_events_completed();

#ifdef __FreeBSD__
if (err != 0) {
    if (libusb_check_connected(udevh)) {
        libusb_cancel_transfer(transfer);
        libusb_free_transfer(transfer);
	return IFD_COMMUNICATION_ERROR;
    }
}
#endif
Comment 16 Ludovic Rousseau 2018-09-08 16:08:17 UTC
(In reply to Hans Petter Selasky from comment #13)
No. The patch does not help.

I added a log so see if the line "process_all = 1;" is executed and the line is executed only once at near the beginning.

$ sudo LIBCCID_ifdLogLevel=0x000F ./pcscd --foreground --debug --apdu --color
00000000 debuglog.c:289:DebugLogSetLevel() debug level=debug
00000022 debuglog.c:310:DebugLogSetCategory() Debug options: APDU
00000006 pcscdaemon.c:352:main() Force colored logs
00000134 configfile.l:361:DBGetReaderList() Parsing conf file: /usr/local/etc/reader.conf.d
00000024 pcscdaemon.c:662:main() pcsc-lite 1.8.23 daemon ready.
00001928 hotplug_libusb.c:440:HPEstablishUSBNotifications() Driver ifd-ccid.bundle does not support IFD_GENERATE_HOTPLUG. Using active polling instead.
00000013 hotplug_libusb.c:449:HPEstablishUSBNotifications() Polling forced every 1 second(s)
03079650 hotplug_libusb.c:536:HPAddHotPluggable() Adding USB device: 0:2:0
00000026 readerfactory.c:1075:RFInitializeReader() Attempting startup of Inside Secure AT90SCR200 00 00 using /usr/local/lib/pcsc/drivers/ifd-ccid.bundle/Contents/FreeBSD/libccid.so
00000089 readerfactory.c:950:RFBindFunctions() Loading IFD Handler 3.0
00000028 ifdhandler.c:1961:init_driver() Driver version: 1.4.29
00000787 ifdhandler.c:1978:init_driver() LogLevel: 0x0003
00000009 ifdhandler.c:1989:init_driver() DriverOptions: 0x0000
00000262 ifdhandler.c:2002:init_driver() LogLevel from LIBCCID_ifdLogLevel: 0x000F
00000007 ifdhandler.c:110:CreateChannelByNameOrChannel() Lun: 0, device: usb:2406/6407:libusb-1.0:0:2:0
00000011 ccid_usb.c:237:OpenUSBByName() Reader index: 0, Device: usb:2406/6407:libusb-1.0:0:2:0
00000021 ccid_usb.c:282:OpenUSBByName() interface_number: 0
00000005 ccid_usb.c:284:OpenUSBByName() usb bus/device: 0/2
00000005 ccid_usb.c:302:OpenUSBByName() Using: /usr/local/lib/pcsc/drivers//ifd-ccid.bundle/Contents/Info.plist
00000599 ccid_usb.c:320:OpenUSBByName() ifdManufacturerString: Ludovic Rousseau (ludovic.rousseau@free.fr)
00000007 ccid_usb.c:321:OpenUSBByName() ifdProductString: Generic CCID driver
00000007 ccid_usb.c:322:OpenUSBByName() Copyright: This driver is protected by terms of the GNU Lesser General Public License version 2.1, or (at your option) any later version.
00000214 ccid_usb.c:407:OpenUSBByName() Try device: 0/2
00000008 ccid_usb.c:417:OpenUSBByName() vid/pid : 2406/6407
00000004 ccid_usb.c:484:OpenUSBByName() Checking device: 0/2
00000005 ccid_usb.c:555:OpenUSBByName() Trying to open USB bus/device: 0/2
00000059 ccid_usb.c:661:OpenUSBByName() Found Vendor/Product: 2406/6407 (Inside Secure AT90SCR200)
00000006 ccid_usb.c:663:OpenUSBByName() Using USB bus/device: 0/2
00000005 ccid_usb.c:723:OpenUSBByName() bNumDataRatesSupported is 0
00001913 ccid_usb.c:1307:InterruptRead() before (0)
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: process_all

*** HERE ^^ ***

LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
00026282 ccid_usb.c:1353:InterruptRead() after (0) (0)
00000006 NotifySlotChange: 50 02 
00000006 -> 000000 65 00 00 00 00 00 00 00 00 00 
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
00002524 <- 000000 81 00 00 00 00 00 00 02 00 00 
00000010 -> 000000 65 00 00 00 00 00 01 00 00 00 
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
00000496 <- 000000 81 00 00 00 00 00 01 02 00 00 
00000010 ifdhandler.c:381:IFDHGetCapabilities() tag: 0xFB3, usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000006 readerfactory.c:396:RFAddReader() Using the reader polling thread
00000006 ifdhandler.c:1821:IFDHICCPresence() usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000009 -> 000000 65 00 00 00 00 00 02 00 00 00 
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
00000477 <- 000000 81 00 00 00 00 00 02 02 00 00 
00000005 ifdhandler.c:1942:IFDHICCPresence() Card absent
00000046 ifdhandler.c:381:IFDHGetCapabilities() tag: 0xFAE, usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000008 ifdhandler.c:476:IFDHGetCapabilities() Reader supports 1 slot(s)
00000013 ifdhandler.c:1821:IFDHICCPresence() usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000013 -> 000000 65 00 00 00 00 00 03 00 00 00 
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
00000423 <- 000000 81 00 00 00 00 00 03 02 00 00 
00000005 ifdhandler.c:1942:IFDHICCPresence() Card absent
00000005 ifdhandler.c:1821:IFDHICCPresence() usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000008 -> 000000 65 00 00 00 00 00 04 00 00 00 
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit
00000489 <- 000000 81 00 00 00 00 00 04 02 00 00 
00000005 ifdhandler.c:1942:IFDHICCPresence() Card absent
00000005 ifdhandler.c:310:IFDHPolling() usb:2406/6407:libusb-1.0:0:2:0 (lun: 0) 600000 ms
00000005 ccid_usb.c:1307:InterruptRead() before (0)
LIBUSB_FUNCTION: libusb_submit_transfer enter
LIBUSB_FUNCTION: libusb_submit_transfer leave 0
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed enter
LIBUSB_FUNCTION: libusb10_handle_events_sub enter


LIBUSB_FUNCTION: libusb10_handle_events_sub enter
04249190 hotplug_libusb.c:626:HPRemoveHotPluggable() Removing USB device[0]: 0:2:0
00000009 readerfactory.c:610:RFRemoveReader() UnrefReader() count was: 1
00000004 eventhandler.c:175:EHDestroyEventHandler() Stomping thread.
00000004 ifdhandler.c:381:IFDHGetCapabilities() tag: 0xFB1, usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000004 ifdhandler.c:381:IFDHGetCapabilities() tag: 0xFB2, usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000004 eventhandler.c:200:EHDestroyEventHandler() Request stopping of polling thread
00000003 ifdhandler.c:346:IFDHStopPolling() usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
LIBUSB_FUNCTION: libusb_cancel_transfer enter
LIBUSB_FUNCTION: state: 1
LIBUSB_FUNCTION: entry.tqe_prev: 0x0
LIBUSB_FUNCTION: sxfer: 0x29007060
LIBUSB_FUNCTION: pxfer0: 0x28c2f348
LIBUSB_FUNCTION: pxfer1: 0x28c2f384
LIBUSB_FUNCTION: libusb20_tr_get_priv_sc1(pxfer0): 0x0
LIBUSB_FUNCTION: libusb20_tr_get_priv_sc1(pxfer1): 0x0
LIBUSB_FUNCTION: f
LIBUSB_FUNCTION: libusb_cancel_transfer leave
00000023 ccid_usb.c:1401:InterruptStop() libusb_cancel_transfer failed: LIBUSB_ERROR_NOT_FOUND
Comment 17 Ludovic Rousseau 2018-09-08 16:38:17 UTC
(In reply to Hans Petter Selasky from comment #8)
Using libusb_set_debug(ctx, LIBUSB_DEBUG_TRANSFER); does not log anything.
The only call site is in libusb10_do_transfer_cb() https://github.com/freebsd/freebsd/blob/master/lib/libusb/libusb10_io.c#L500

In libusb10_do_transfer_cb() the context is fetched using:
ctx = GET_CONTEXT(NULL);
Note the use of "NULL".

so ctx->debug is always 0 and nothing is ever logged.

The logging using LIBUSB_DEBUG_TRANSFER is bogus :-)

I added a printf() in libusb10_do_transfer_cb() to get some log.
This function is NOT called after I removed the USB device.
Comment 18 Ludovic Rousseau 2018-09-08 16:43:31 UTC
(In reply to Hans Petter Selasky from comment #15)

Where exactly should I add this code?
In my code or in libusb?

My code works fine using the "official" libusb on GNU/Linux and macOS.
FreeBSD libusb should have the same behaviour if it claims to be compliant. No?
Comment 19 Hans Petter Selasky freebsd_committer 2018-09-08 17:42:16 UTC
> My code works fine using the "official" libusb on GNU/Linux and macOS.
FreeBSD libusb should have the same behaviour if it claims to be compliant. No?

I understand your frustration, but it is not always easy to be compliant. Some behaviours will be OS specific.

I'll try to come up with a second libusb patch to address this issue.

Can you try adding a call to libusb_check_connected(udevh) in your code to see what the value is?

--HPS
Comment 20 Ludovic Rousseau 2018-09-09 12:07:23 UTC
(In reply to Ludovic Rousseau from comment #17)
I created a new bug about the non-working LIBUSB_DEBUG_TRANSFER level
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=231264
Comment 21 Hans Petter Selasky freebsd_committer 2018-09-09 20:22:12 UTC
Created attachment 196991 [details]
LibUSB patch WIP

Second try.

I suspect libusb10_cancel_all_transfer() is called from the waiting loop and that will break the cancel logic because the priv_sc1 pointer is cleared.

I didn't have time yet to writeup a test program to verify the patch.
Comment 22 Ludovic Rousseau 2018-09-12 09:10:15 UTC
Your patch works for me.

Now I have:
LIBUSB_FUNCTION: libusb10_handle_events_sub enter
03008747 hotplug_libusb.c:626:HPRemoveHotPluggable() Removing USB device[0]: 0:2:0
00000009 readerfactory.c:610:RFRemoveReader() UnrefReader() count was: 1
00000003 eventhandler.c:175:EHDestroyEventHandler() Stomping thread.
00000005 ifdhandler.c:381:IFDHGetCapabilities() tag: 0xFB1, usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000003 ifdhandler.c:381:IFDHGetCapabilities() tag: 0xFB2, usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
00000003 eventhandler.c:200:EHDestroyEventHandler() Request stopping of polling thread
00000004 ifdhandler.c:346:IFDHStopPolling() usb:2406/6407:libusb-1.0:0:2:0 (lun: 0)
LIBUSB_FUNCTION: libusb_cancel_transfer enter
LIBUSB_FUNCTION: libusb_cancel_transfer leave
LIBUSB_FUNCTION: libusb_handle_events_timeout_completed exit

The libusb_cancel_transfer() function does return with no error. Great.

libusb_handle_events_completed() now returns. Great.

I now have another problem. I opened a new bug for that bug #231322.

Thanks
Comment 23 Hans Petter Selasky freebsd_committer 2018-09-12 10:04:25 UTC
Created attachment 197050 [details]
LibUSB patch

Added code to handle cancel of pending transfers and block new ones after device detach is detected.

Can you please test?
Comment 24 Ludovic Rousseau 2018-09-12 12:10:10 UTC
This new patch works for me.

It also fixes bug #231322.
Comment 25 Hans Petter Selasky freebsd_committer 2018-09-12 13:16:50 UTC
Good. I'll try to push this patch upstream then.

Thank you for testing and being patient :-)

--HPS
Comment 26 Hans Petter Selasky freebsd_committer 2018-09-12 13:32:00 UTC
*** Bug 231322 has been marked as a duplicate of this bug. ***
Comment 27 commit-hook freebsd_committer 2018-09-12 15:06:57 UTC
A commit references this bug:

Author: hselasky
Date: Wed Sep 12 15:06:31 UTC 2018
New revision: 338616
URL: https://svnweb.freebsd.org/changeset/base/338616

Log:
  Fix issues about cancelling USB transfers in LibUSB when the USB device has
  been detached. When a USB device has been detached the kernel file handle
  stops responding to commands. USB applications which continue to run after
  the USB device has been detached, depend on LibUSB generated events to tear
  down its pending USB transfers. Add code to handle the needed cleanup when
  processing the USB transfer(s) fails and prevent new USB transfer(s) from
  being submitted.

  Found by:		Ludovic Rousseau <ludovic.rousseau+freebsd@gmail.com>
  PR:			231076
  MFC after:		1 week
  Approved by:		re (gjb)
  Sponsored by:		Mellanox Technologies

Changes:
  head/lib/libusb/libusb10.c
  head/lib/libusb/libusb10.h
  head/lib/libusb/libusb10_io.c
Comment 28 Hans Petter Selasky freebsd_committer 2018-09-12 15:07:54 UTC
Will be MFC'ed to 10-stable in a week.
Comment 29 commit-hook freebsd_committer 2018-09-19 07:57:19 UTC
A commit references this bug:

Author: hselasky
Date: Wed Sep 19 07:56:20 UTC 2018
New revision: 338788
URL: https://svnweb.freebsd.org/changeset/base/338788

Log:
  MFC r338616:
  Fix issues about cancelling USB transfers in LibUSB when the USB device has
  been detached. When a USB device has been detached the kernel file handle
  stops responding to commands. USB applications which continue to run after
  the USB device has been detached, depend on LibUSB generated events to tear
  down its pending USB transfers. Add code to handle the needed cleanup when
  processing the USB transfer(s) fails and prevent new USB transfer(s) from
  being submitted.

  Found by:		Ludovic Rousseau <ludovic.rousseau+freebsd@gmail.com>
  PR:			231076
  Sponsored by:		Mellanox Technologies

Changes:
_U  stable/11/
  stable/11/lib/libusb/libusb10.c
  stable/11/lib/libusb/libusb10.h
  stable/11/lib/libusb/libusb10_io.c
Comment 30 commit-hook freebsd_committer 2018-09-19 07:58:24 UTC
A commit references this bug:

Author: hselasky
Date: Wed Sep 19 07:57:31 UTC 2018
New revision: 338789
URL: https://svnweb.freebsd.org/changeset/base/338789

Log:
  MFC r338616:
  Fix issues about cancelling USB transfers in LibUSB when the USB device has
  been detached. When a USB device has been detached the kernel file handle
  stops responding to commands. USB applications which continue to run after
  the USB device has been detached, depend on LibUSB generated events to tear
  down its pending USB transfers. Add code to handle the needed cleanup when
  processing the USB transfer(s) fails and prevent new USB transfer(s) from
  being submitted.

  Found by:		Ludovic Rousseau <ludovic.rousseau+freebsd@gmail.com>
  PR:			231076
  Sponsored by:		Mellanox Technologies

Changes:
_U  stable/10/
  stable/10/lib/libusb/libusb10.c
  stable/10/lib/libusb/libusb10.h
  stable/10/lib/libusb/libusb10_io.c
Comment 31 commit-hook freebsd_committer 2018-09-19 08:10:35 UTC
A commit references this bug:

Author: hselasky
Date: Wed Sep 19 08:10:00 UTC 2018
New revision: 338790
URL: https://svnweb.freebsd.org/changeset/base/338790

Log:
  MFC r338616:
  Fix issues about cancelling USB transfers in LibUSB when the USB device has
  been detached. When a USB device has been detached the kernel file handle
  stops responding to commands. USB applications which continue to run after
  the USB device has been detached, depend on LibUSB generated events to tear
  down its pending USB transfers. Add code to handle the needed cleanup when
  processing the USB transfer(s) fails and prevent new USB transfer(s) from
  being submitted.

  Found by:		Ludovic Rousseau <ludovic.rousseau+freebsd@gmail.com>
  PR:			231076
  Sponsored by:		Mellanox Technologies

Changes:
_U  stable/9/lib/
_U  stable/9/lib/libusb/
  stable/9/lib/libusb/libusb10.c
  stable/9/lib/libusb/libusb10.h
  stable/9/lib/libusb/libusb10_io.c