[events] Add an asynchronous function to check for events

The existing LIBMTP_Read_Event function blocks while waiting for
an event. This can lead to race conditions where a client attempts
to disconnect from the device in one thread while an event just
happens to arrive in the polling thread, with unpredictable results,
including attempts to disconnect twice.

To make life easier for clients, we can offer an asynchronous form
of event checking, which gives the client the ability to terminate
polling when necessary.

To do this, we can leverage the asynchronous capabilities of
libusb-1. That's only one of three possible backends, but it's the
most commonly and heavily used library.

Starting an asynchronous transfer is pretty straightforward, but
polling can be done in a variety of ways, some of which are very
complicated. For my purposes, one of the simpler forms is sufficient,
and, in fact, the most generalised form doesn't offer me any
advantages.

Accordingly, I put a trivial wrapper around this method so that it
can be used without making the client explicitly pull in libusb-1.
It's a bit weird, but worth the convenience.

So, we now have a Read_Events_Async that takes a callback and
a Handle_Events method that will poll for activity. How have we
solved the original problem?

There are two ways.

1) We can pass a timeout to Handle_Events. This will cause it to
return if no activity happened. We can then assess whether it is
safe to poll some more or give up.

2) libusb has recently added an 'interrupt_event_handler' function

https://github.com/libusb/libusb/commit/a6db382ad11f7662b550338e0570d5a2dfd8ce5a

This function finally offers a way to interrupt polling on demand.

No release of libusb with this in it has happened yet, but hopefully
it will happen soon.

Now, you could ask, with fairness, why this interrupt mechanism
shouldn't work with the existing synchronous Read_Event; and I
agree - it should - but it doesn't.

Due to a bug in libusb, even though the interruption works, the
synchronous wrapper code they have will immediately start the
polling again and never return control to the caller.

So, even when we're in a position to use this interruption
function, we'll still need to be using the async API to take
advantage of it.

I've verified that all this logic works in gvfs.
7 files changed