kylelemons/gousb — pull request #7 by krasin (2013-08-14 07:42:37+00:00)
Title: Fix context close race

It appears that C.libusb_handle_events might be awaiting events, while libusb_exit is called. That would result in "error -99" and eventually corrupted memory and segfault (like here: https://gist.github.com/krasin/6228396)

That was possible, because Context.Close did not wait for libusb_handle_events completion. But if it did, it might be an infinite block, if no usb events happened. This is a known issue with libusb. See http://libusb.sourceforge.net/api-1.0/group__asyncio.html

```
Event handling

In accordance of the aim of being a lightweight library, libusb does not create threads internally. This means that libusb code does not execute at any time other than when your application is calling a libusb function. However, an asynchronous model requires that libusb perform work at various points in time - namely processing the results of previously-submitted transfers and invoking the user-supplied callback function.

This gives rise to the libusb_handle_events() function which your application must call into when libusb has work do to. This gives libusb the opportunity to reap pending transfers, invoke callbacks, etc.

The first issue to discuss here is how your application can figure out when libusb has work to do. In fact, there are two naive options which do not actually require your application to know this:

Periodically call libusb_handle_events() in non-blocking mode at fixed short intervals from your main loop
Repeatedly call libusb_handle_events() in blocking mode from a dedicated thread.

The first option is plainly not very nice, and will cause unnecessary CPU wakeups leading to increased power usage and decreased battery life. The second option is not very nice either, but may be the nicest option available to you if the "proper" approach can not be applied to your application (read on...).

The recommended option is to integrate libusb with your application main event loop. libusb exposes a set of file descriptors which allow you to do this. Your main loop is probably already calling poll() or select() or a variant on a set of file descriptors for other event sources (e.g. keyboard button presses, mouse movements, network sockets, etc). You then add libusb's file descriptors to your poll()/select() calls, and when activity is detected on such descriptors you know it is time to call libusb_handle_events().

There is one final event handling complication. libusb supports asynchronous transfers which time out after a specified time period, and this requires that libusb is called into at or after the timeout so that the timeout can be handled. So, in addition to considering libusb's file descriptors in your main event loop, you must also consider that libusb sometimes needs to be called into at fixed points in time even when there is no file descriptor activity.

For the details on retrieving the set of file descriptors and determining the next timeout, see the polling and timing API documentation.
```

Since libusb_handle_events was so inconvenient for everyone, libusb deprecated it and introduced a new routine: [libusb_handle_events_timeout_completed](http://libusb.sourceforge.net/api-1.0/group__poll.html#ga43e52b912a760b41a0cf8a4a472fbd5b) that allows to specify a timeout to block, if no events coming.

So this patch replaces libusb_handle_events with libusb_handle_events_timeout_completed (timeout = 100 ms) and Context.Close waits for completion libusb_handle_events_timeout_completed. The race condition is eliminated, little yellow minions are happily clapping!