vpelletier / python-libusb1

Python ctype-based wrapper around libusb1
GNU Lesser General Public License v2.1
168 stars 65 forks source link

Hang on cleanup #14

Closed AstraLuma closed 8 years ago

AstraLuma commented 8 years ago

While tracking down an issue in another project, I wrote this script and found that it hangs in libusb_unlock_events() (called from libusb_close()).

I'm running Arch Linux current.

The C program I based this script on does not hang, but probably does things slightly different.

vpelletier commented 8 years ago

Thanks for this report.

I suspect instance cleanup happens in the wrong order. Could you confirm this by running: $ ltrace -o stressball.ltrace -l "libusb*" python stressball.py and pasting the output here ?

O/T: I like the idea of using a context manager for claiming & releasing interface.

vpelletier commented 8 years ago

...actually, looking better at the trace I generated from a sample script, it is missing a lot of calls. Looks like you also must pass -x "libusb*": $ ltrace -o stressball.ltrace -x "libusb*" -l "libusb*" python stressball.py

AstraLuma commented 8 years ago
--- SIGCHLD (Child exited) ---
--- SIGCHLD (Child exited) ---
libusb_init@libusb-1.0.so.0(0x7f67cd956808, 19, 1, 1 <unfinished ...>
libusb-1.0.so.0->libusb_has_capability(1, 0x7f67d1128af4, 0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0x7f67d1128af4, 0, 0)                              = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_has_capability(1, 0, 0xe822b0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0, 0xe822b0, 0)                                    = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_has_capability(1, 0x7f67d1128af4, 0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0x7f67d1128af4, 0, 0)                              = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_ref_device(0xfdaf80, 0xfe45d0, 0, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xfdaf80, 0xfe45d0, 0, 0)                                 = 0xfdaf80
<... libusb_ref_device resumed> )                                                           = 0xfdaf80
libusb-1.0.so.0->libusb_has_capability(1, 0, 0xe822b0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0, 0xe822b0, 0)                                    = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_has_capability(1, 0x7f67d1128af4, 0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0x7f67d1128af4, 0, 0)                              = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_ref_device(0xf72200, 0xfd9450, 0, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xf72200, 0xfd9450, 0, 0)                                 = 0xf72200
<... libusb_ref_device resumed> )                                                           = 0xf72200
libusb-1.0.so.0->libusb_has_capability(1, 0, 0xe822b0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0, 0xe822b0, 0)                                    = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_has_capability(1, 0x7f67d1128af4, 0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0x7f67d1128af4, 0, 0)                              = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_has_capability(1, 0, 0xe822b0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0, 0xe822b0, 0)                                    = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_has_capability(1, 0x7f67d1128af4, 0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0x7f67d1128af4, 0, 0)                              = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_ref_device(0x1009ae0, 0xfd7130, 0, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0x1009ae0, 0xfd7130, 0, 0)                                = 0x1009ae0
<... libusb_ref_device resumed> )                                                           = 0x1009ae0
libusb-1.0.so.0->libusb_has_capability(1, 0, 0xe822b0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0, 0xe822b0, 0)                                    = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_has_capability(1, 0x7f67d1128af4, 0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0x7f67d1128af4, 0, 0)                              = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_ref_device(0xef0b00, 0xfd8390, 0, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xef0b00, 0xfd8390, 0, 0)                                 = 0xef0b00
<... libusb_ref_device resumed> )                                                           = 0xef0b00
libusb-1.0.so.0->libusb_has_capability(1, 0, 0xe822b0, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0, 0xe822b0, 0)                                    = 1
<... libusb_has_capability resumed> )                                                       = 1
<... libusb_init resumed> )                                                                 = 0
libusb_get_device_list@libusb-1.0.so.0(0xe82290, 0x7f67cd956890, 0xfc5e18, 0x7f67d028c048 <unfinished ...>
libusb-1.0.so.0->libusb_has_capability(1, 4, 0x7f67cdfbdee0, 0x7f67cdfbd373 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 4, 0x7f67cdfbdee0, 0x7f67cdfbd373)                 = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_ref_device(0xef0bc0, 0xef0bc0, 0xef0c10, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xef0bc0, 0xef0bc0, 0xef0c10, 0)                          = 0xef0bc0
<... libusb_ref_device resumed> )                                                           = 0xef0bc0
libusb-1.0.so.0->libusb_ref_device(0xef0b00, 0xef0b00, 0xef0b50, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xef0b00, 0xef0b00, 0xef0b50, 0)                          = 0xef0b00
<... libusb_ref_device resumed> )                                                           = 0xef0b00
libusb-1.0.so.0->libusb_ref_device(0x1009ae0, 0x1009ae0, 0x1009b30, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0x1009ae0, 0x1009ae0, 0x1009b30, 0)                       = 0x1009ae0
<... libusb_ref_device resumed> )                                                           = 0x1009ae0
libusb-1.0.so.0->libusb_ref_device(0x100c9d0, 0x100c9d0, 0x100ca20, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0x100c9d0, 0x100c9d0, 0x100ca20, 0)                       = 0x100c9d0
<... libusb_ref_device resumed> )                                                           = 0x100c9d0
libusb-1.0.so.0->libusb_ref_device(0xf72200, 0xf72200, 0xf72250, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xf72200, 0xf72200, 0xf72250, 0)                          = 0xf72200
<... libusb_ref_device resumed> )                                                           = 0xf72200
libusb-1.0.so.0->libusb_ref_device(0xfdaf80, 0xfdaf80, 0xfdafd0, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xfdaf80, 0xfdaf80, 0xfdafd0, 0)                          = 0xfdaf80
<... libusb_ref_device resumed> )                                                           = 0xfdaf80
libusb-1.0.so.0->libusb_ref_device(0xef0bc0, 2, 56, 7 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xef0bc0, 2, 56, 7)                                       = 0xef0bc0
<... libusb_ref_device resumed> )                                                           = 0xef0bc0
libusb-1.0.so.0->libusb_ref_device(0xef0b00, 0, 0xef0bc0, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xef0b00, 0, 0xef0bc0, 0)                                 = 0xef0b00
<... libusb_ref_device resumed> )                                                           = 0xef0b00
libusb-1.0.so.0->libusb_ref_device(0x1009ae0, 0, 0xef0b00, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0x1009ae0, 0, 0xef0b00, 0)                                = 0x1009ae0
<... libusb_ref_device resumed> )                                                           = 0x1009ae0
libusb-1.0.so.0->libusb_ref_device(0x100c9d0, 0, 0x1009ae0, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0x100c9d0, 0, 0x1009ae0, 0)                               = 0x100c9d0
<... libusb_ref_device resumed> )                                                           = 0x100c9d0
libusb-1.0.so.0->libusb_ref_device(0xf72200, 0, 0x100c9d0, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xf72200, 0, 0x100c9d0, 0)                                = 0xf72200
<... libusb_ref_device resumed> )                                                           = 0xf72200
libusb-1.0.so.0->libusb_ref_device(0xfdaf80, 0, 0xf72200, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xfdaf80, 0, 0xf72200, 0)                                 = 0xfdaf80
<... libusb_ref_device resumed> )                                                           = 0xfdaf80
libusb-1.0.so.0->libusb_unref_device(0xef0bc0, 0, 0xfdaf80, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xef0bc0, 0, 0xfdaf80, 0)                               = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0xef0b00, 0, 0xef0bc0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xef0b00, 0, 0xef0bc0, 0)                               = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0x1009ae0, 0, 0xef0b00, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0x1009ae0, 0, 0xef0b00, 0)                              = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0x100c9d0, 0, 0x1009ae0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0x100c9d0, 0, 0x1009ae0, 0)                             = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0xf72200, 0, 0x100c9d0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xf72200, 0, 0x100c9d0, 0)                              = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0xfdaf80, 0, 0xf72200, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xfdaf80, 0, 0xf72200, 0)                               = 0
<... libusb_unref_device resumed> )                                                         = 0
<... libusb_get_device_list resumed> )                                                      = 6
libusb_ref_device@libusb-1.0.so.0(0xef0bc0, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d0299b40)   = 0xef0bc0
libusb_get_device_descriptor@libusb-1.0.so.0(0xef0bc0, 0xf1d230, 0xfbc6e8, 0x7f67d0299b40)  = 0
libusb_get_config_descriptor@libusb-1.0.so.0(0xef0bc0, 0, 0x7f67cd956de0, 0x7f67d13b6b76)   = 0
libusb_ref_device@libusb-1.0.so.0(0xef0b00, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d0299b40)   = 0xef0b00
libusb_get_device_descriptor@libusb-1.0.so.0(0xef0b00, 0xf1d3d0, 0xfbc6e8, 0x7f67d0299b40)  = 0
libusb_get_config_descriptor@libusb-1.0.so.0(0xef0b00, 0, 0x7f67cd958120, 0x7f67d13b6b76)   = 0
libusb_ref_device@libusb-1.0.so.0(0x1009ae0, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d0299b40)  = 0x1009ae0
libusb_get_device_descriptor@libusb-1.0.so.0(0x1009ae0, 0x1004700, 0xfbc6e8, 0x7f67d0299b40) = 0
libusb_get_config_descriptor@libusb-1.0.so.0(0x1009ae0, 0, 0x7f67cd9583c8, 0x7f67d13b6b76)  = 0
libusb_ref_device@libusb-1.0.so.0(0x100c9d0, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d0299b40)  = 0x100c9d0
libusb_get_device_descriptor@libusb-1.0.so.0(0x100c9d0, 0xef0ae0, 0xfbc6e8, 0x7f67d0299b40) = 0
libusb_get_config_descriptor@libusb-1.0.so.0(0x100c9d0, 0, 0x7f67cd958670, 0x7f67d13b6b76)  = 0
libusb_ref_device@libusb-1.0.so.0(0xf72200, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d0299b40)   = 0xf72200
libusb_get_device_descriptor@libusb-1.0.so.0(0xf72200, 0xfb1160, 0xfbc6e8, 0x7f67d0299b40)  = 0
libusb_get_config_descriptor@libusb-1.0.so.0(0xf72200, 0, 0x7f67cd958918, 0x7f67d13b6b76)   = 0
libusb_ref_device@libusb-1.0.so.0(0xfdaf80, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d0299b40)   = 0xfdaf80
libusb_get_device_descriptor@libusb-1.0.so.0(0xfdaf80, 0x100d790, 0xfbc6e8, 0x7f67d0299b40) = 0
libusb_get_config_descriptor@libusb-1.0.so.0(0xfdaf80, 0, 0x7f67cd958bc0, 0x7f67d13b6b76)   = 0
libusb_free_device_list@libusb-1.0.so.0(0x1009690, 1, 0xf04b98, 0x7f67d0299b40 <unfinished ...>
libusb-1.0.so.0->libusb_unref_device(0xef0bc0, 1, 0xf04b98, 0x7f67d0299b40 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xef0bc0, 1, 0xf04b98, 0x7f67d0299b40)                  = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0xef0b00, 0, 0xef0bc0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xef0b00, 0, 0xef0bc0, 0)                               = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0x1009ae0, 0, 0xef0b00, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0x1009ae0, 0, 0xef0b00, 0)                              = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0x100c9d0, 0, 0x1009ae0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0x100c9d0, 0, 0x1009ae0, 0)                             = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0xf72200, 0, 0x100c9d0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xf72200, 0, 0x100c9d0, 0)                              = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0xfdaf80, 0, 0xf72200, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xfdaf80, 0, 0xf72200, 0)                               = 0
<... libusb_unref_device resumed> )                                                         = 0
<... libusb_free_device_list resumed> )                                                     = 0x1007f50
libusb_unref_device@libusb-1.0.so.0(0xfdaf80, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d028c048) = 0
libusb_free_config_descriptor@libusb-1.0.so.0(0xfe4590, 0xb94d58a73c9afc00, 0xfc2588, 0x7f67d028c048) = 0xfe45b0
libusb_unref_device@libusb-1.0.so.0(0xf72200, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d028c048) = 0
libusb_free_config_descriptor@libusb-1.0.so.0(0x100d1e0, 0xb94d58a73c9afc00, 0xfc2588, 0x7f67d028c048) = 0x100d200
libusb_unref_device@libusb-1.0.so.0(0x100c9d0, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d028c048) = 0
libusb_free_config_descriptor@libusb-1.0.so.0(0x100d360, 0xb94d58a73c9afc00, 0xfc2588, 0x7f67d028c048) = 0x100d380
libusb_unref_device@libusb-1.0.so.0(0x1009ae0, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d028c048) = 0
libusb_free_config_descriptor@libusb-1.0.so.0(0x1007f30, 0xb94d58a73c9afc00, 0xfc2588, 0x7f67d028c048) = 0x100af50
libusb_unref_device@libusb-1.0.so.0(0xef0b00, 0xb94d58a73c9afc00, 0xfc4d98, 0x7f67d028c048) = 0
libusb_free_config_descriptor@libusb-1.0.so.0(0xe963e0, 0xb94d58a73c9afc00, 0xfc2588, 0x7f67d028c048) = 0xfd6760
libusb_open@libusb-1.0.so.0(0xef0bc0, 0x7f67cd956f78, 0xfc6da8, 0x7f67d028c048 <unfinished ...>
libusb-1.0.so.0->libusb_ref_device(0xef0bc0, 0x7f67d1128af4, 0, 0 <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xef0bc0, 0x7f67d1128af4, 0, 0)                           = 0xef0bc0
<... libusb_ref_device resumed> )                                                           = 0xef0bc0
<... libusb_open resumed> )                                                                 = 0
libusb_set_auto_detach_kernel_driver@libusb-1.0.so.0(0xf044c0, 1, 0xf04b98, 0x7f67d0299b88) = 0
libusb_claim_interface@libusb-1.0.so.0(0xf044c0, 0, 0xf04b98, 0x7f67d0299b88)               = 0
libusb_control_transfer@libusb-1.0.so.0(0xf044c0, 33, 9, 512 <unfinished ...>
libusb-1.0.so.0->libusb_alloc_transfer(0, 33, 9, 512 <unfinished ...>
libusb_alloc_transfer@libusb-1.0.so.0(0, 33, 9, 512)                                        = 0x100b648
<... libusb_alloc_transfer resumed> )                                                       = 0x100b648
libusb-1.0.so.0->libusb_submit_transfer(0x100b648, 0x7f67cd9569a0, 8, 0 <unfinished ...>
libusb_submit_transfer@libusb-1.0.so.0(0x100b648, 0x7f67cd9569a0, 8, 0 <unfinished ...>
libusb-1.0.so.0->libusb_ref_device(0xef0bc0, 0, 0xe82358, 0x7f67d0e5d76a <unfinished ...>
libusb_ref_device@libusb-1.0.so.0(0xef0bc0, 0, 0xe82358, 0x7f67d0e5d76a)                    = 0xef0bc0
<... libusb_ref_device resumed> )                                                           = 0xef0bc0
<... libusb_submit_transfer resumed> )                                                      = 0
<... libusb_submit_transfer resumed> )                                                      = 0
libusb-1.0.so.0->libusb_handle_events_completed(0xe82290, 0x7fffa13df534, 0x100b5f8, 0 <unfinished ...>
libusb_handle_events_completed@libusb-1.0.so.0(0xe82290, 0x7fffa13df534, 0x100b5f8, 0 <unfinished ...>
libusb-1.0.so.0->libusb_handle_events_timeout_completed(0xe82290, 0x7fffa13df4b0, 0x7fffa13df534, 0 <unfinished ...>
libusb_handle_events_timeout_completed@libusb-1.0.so.0(0xe82290, 0x7fffa13df4b0, 0x7fffa13df534, 0 <unfinished ...>
libusb-1.0.so.0->libusb_get_next_timeout(0xe82290, 0x7fffa13df420, 0x7fffa13df460, 0 <unfinished ...>
libusb_get_next_timeout@libusb-1.0.so.0(0xe82290, 0x7fffa13df420, 0x7fffa13df460, 0)        = 0
<... libusb_get_next_timeout resumed> )                                                     = 0
libusb-1.0.so.0->libusb_try_lock_events(0xe82290, 0x7fffa13df420, 0, 0 <unfinished ...>
libusb_try_lock_events@libusb-1.0.so.0(0xe82290, 0x7fffa13df420, 0, 0)                      = 0
<... libusb_try_lock_events resumed> )                                                      = 0
libusb-1.0.so.0->libusb_unref_device(0xef0bc0, 4, 0x7f67cdfbf590, 0x7f67cdfbf9ea <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xef0bc0, 4, 0x7f67cdfbf590, 0x7f67cdfbf9ea)            = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unlock_events(0xe82290, 0, 0xe822e8, -104 <unfinished ...>
libusb_unlock_events@libusb-1.0.so.0(0xe82290, 0, 0xe822e8, -104)                           = 0
<... libusb_unlock_events resumed> )                                                        = 0
<... libusb_handle_events_timeout_completed resumed> )                                      = 0
<... libusb_handle_events_timeout_completed resumed> )                                      = 0
<... libusb_handle_events_completed resumed> )                                              = 0
<... libusb_handle_events_completed resumed> )                                              = 0
libusb-1.0.so.0->libusb_free_transfer(0x100b648, 0, 0xffffffffffff8aa4, 0 <unfinished ...>
libusb_free_transfer@libusb-1.0.so.0(0x100b648, 0, 0xffffffffffff8aa4, 0)                   = 1
<... libusb_free_transfer resumed> )                                                        = 1
<... libusb_control_transfer resumed> )                                                     = 0xfffffff8
libusb_release_interface@libusb-1.0.so.0(0xf044c0, 0, 0xf04b98, 0x7f67d0299b88)             = 0
libusb_exit@libusb-1.0.so.0(0xe82290, 0xb94d58a73c9afc00, 0xfc3dd8, 0x7f67d0615c18 <unfinished ...>
libusb-1.0.so.0->libusb_has_capability(1, 0, 0x7f67ce1c5420, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0, 0x7f67ce1c5420, 0)                              = 1
<... libusb_has_capability resumed> )                                                       = 1
libusb-1.0.so.0->libusb_unref_device(0xef0bc0, 0, 0xe822a0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xef0bc0, 0, 0xe822a0, 0)                               = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0xef0b00, 0, 0xe822a0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xef0b00, 0, 0xe822a0, 0)                               = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0x1009ae0, 0, 0xe822a0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0x1009ae0, 0, 0xe822a0, 0)                              = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_unref_device(0x100c9d0, 0, 0xe822a0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0x100c9d0, 0, 0xe822a0, 0 <unfinished ...>
libusb-1.0.so.0->libusb_unref_device(0xf72200, 0x7f67cdfbd358, 1, 85 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xf72200, 0x7f67cdfbd358, 1, 85)                        = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_has_capability(1, 0, 0xffffffff, 0xf6c710 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0, 0xffffffff, 0xf6c710)                           = 1
<... libusb_has_capability resumed> )                                                       = 1
<... libusb_unref_device resumed> )                                                         = 1
<... libusb_unref_device resumed> )                                                         = 1
libusb-1.0.so.0->libusb_unref_device(0xf72200, 0, 0xe822a0, 0xf6c710 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xf72200, 0, 0xe822a0, 0xf6c710 <unfinished ...>
libusb-1.0.so.0->libusb_unref_device(0xfdaf80, 0x7f67cdfbd358, 1, 85 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xfdaf80, 0x7f67cdfbd358, 1, 85)                        = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_has_capability(1, 0, 0xffffffff, 0 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0, 0xffffffff, 0)                                  = 1
<... libusb_has_capability resumed> )                                                       = 1
<... libusb_unref_device resumed> )                                                         = 1
<... libusb_unref_device resumed> )                                                         = 1
libusb-1.0.so.0->libusb_unref_device(0xfdaf80, 0, 0xe822a0, 0 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0xfdaf80, 0, 0xe822a0, 0 <unfinished ...>
libusb-1.0.so.0->libusb_unref_device(0, 0x7f67cdfbd358, 1, 85 <unfinished ...>
libusb_unref_device@libusb-1.0.so.0(0, 0x7f67cdfbd358, 1, 85)                               = 0
<... libusb_unref_device resumed> )                                                         = 0
libusb-1.0.so.0->libusb_has_capability(1, 0, 0xffffffff, 0xf72290 <unfinished ...>
libusb_has_capability@libusb-1.0.so.0(1, 0, 0xffffffff, 0xf72290)                           = 1
<... libusb_has_capability resumed> )                                                       = 1
<... libusb_unref_device resumed> )                                                         = 1
<... libusb_unref_device resumed> )                                                         = 1
<... libusb_exit resumed> )                                                                 = 0
libusb_close@libusb-1.0.so.0(0xf044c0, 0xb94d58a73c9afc00, 0xfc6258, 0x7f67d0615c18 <no return ...>
--- SIGINT (Interrupt) ---
+++ killed by SIGINT +++
vpelletier commented 8 years ago

Aha, libusb_exit indeed returned before libusb_close got called. So there is something weird about the order in which python 3[.5 specifically ?] garbage-collects on interpreter shutdown.

If you just want to work around this issue to continue debugging the one you were initially chasing, you can wrap your with-block in a try..except block ending like this:

except KeyboardInterrupt:
  handle.close()

(which makes me wonder about making USBDeviceHandle a context manager...) It should be enough to reach the correct execution order.

This said, python-usb1 already give a hint to the interpreter by referencing the USBContext instance from USBDeviceHandle - it should then garbage-collect the handle before the context. Unless there is somehow a reference loop, which I do not see yet.

Another off-topic: I spotted the REQUEST_TYPE_CLASS constant declaration, and indeed there was a mistake in python-libusb1 as it defined these constants as TYPE_CLASS (etc). I see this changed in 2008 in libusb, and I picked the old names.

vpelletier commented 8 years ago

I could reproduce the behaviour in a nutshell:

$ python3
Python 3.5.1+ (default, Mar 30 2016, 22:46:26) 
[GCC 5.3.1 20160323] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class A(object):
...   def __del__(self):
...     print(self.__dict__)
... 
>>> a = A()
>>> b = A()
>>> a.b = b
>>> 
{}
{'b': <__main__.A object at 0x7f3e85a5c6a0>}

(I pressed ^D on that last interpreter line, triggering interpreter exit) The first instance to be destroyed is b (the one with no properties), the second is a: that's the opposite of what references would suggest. A python 3 bug maybe ?

vpelletier commented 8 years ago

So, after bringing this up on #python@freenode, the general advice is that I should not rely on __del__, but instead use a context-manager which would know about all USB instances (spawned from it, directly or indirectly), and which would destroy them in a reliable way on __exit__. I've started working in this direction (USBDevice will become a context manager), and should push that commit (along with a few unrelated) some time this week-end.

vpelletier commented 8 years ago

Could you test with the new with_USBContext branch and tell me if it fixes the issue for you ?

You will need to adapt your code a bit. To make up for it, you do not need any more to:

Do not hesitate to comment on the usability & clarity of resulting API.

AstraLuma commented 8 years ago

Yup, cleans up and exits nicely now.

For the record, I've updated the gist with the changes made.

API Commentary: Seems solid, in the context of mostly mirroring the C API. I think some explicit documentation would be useful, in addition to the examples. Thanks for bringing the constant names in line with libusb. It would also make sense to have a context manager associated with detaching/attaching the kernel driver.

vpelletier commented 8 years ago

Thanks for testing, this change is now released as part of version 1.5.0, uploaded to pypi.

About documentation, although I am not too happy with the current documentation I'm also not sure of the form it should take and what to put in it. I like pydoc, and tried to put informative docstrings to all public API. I am worried by documentation rot if it gets any further away from the actual code (I only updated the examples in README in my last pre-upload amend), and also try to not duplicate libusb's documentation. Any idea is welcome.

AstraLuma commented 8 years ago

Porting over this script was pretty straightforward. I figured a section in the README about how it differs and additional Pythonisms would be good.