aboutsummaryrefslogtreecommitdiff
path: root/src/libmtp.h.in
diff options
context:
space:
mode:
authorPhilip Langdale <philipl@overt.org>2016-04-09 14:22:25 -0700
committerPhilip Langdale <philipl@overt.org>2016-04-14 07:39:13 -0700
commit0a576519a2e7157611266a74e61b9aedf4068b69 (patch)
tree0ebaa09f41827d2d25d21d16a6e6c5e509938756 /src/libmtp.h.in
parent0950ff1323dea619dd742449153adb0467387ffc (diff)
downloadlibmtp-0a576519a2e7157611266a74e61b9aedf4068b69.tar.gz
[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.
Diffstat (limited to 'src/libmtp.h.in')
-rw-r--r--src/libmtp.h.in5
1 files changed, 5 insertions, 0 deletions
diff --git a/src/libmtp.h.in b/src/libmtp.h.in
index 7a9001e..ac37b3e 100644
--- a/src/libmtp.h.in
+++ b/src/libmtp.h.in
@@ -50,6 +50,8 @@ typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
+#else
+#include <sys/time.h>
#endif
#include <stdio.h>
@@ -1048,7 +1050,10 @@ int LIBMTP_TruncateObject(LIBMTP_mtpdevice_t *, uint32_t const, uint64_t);
* @defgroup files The events API.
* @{
*/
+typedef void(* LIBMTP_event_cb_fn) (int, LIBMTP_event_t, uint32_t, void *);
int LIBMTP_Read_Event(LIBMTP_mtpdevice_t *, LIBMTP_event_t *, uint32_t *);
+int LIBMTP_Read_Event_Async(LIBMTP_mtpdevice_t *, LIBMTP_event_cb_fn, void *);
+int LIBMTP_Handle_Events_Timeout_Completed(struct timeval *, int *);
/** @} */