Hi,

We've been looking into the performance of the Windows desktop and Windows CE versions of libusbx compared to Linux on the same hardware. The event handling in Windows and Windows CE appears to take considerably longer than for Linux.

This is understandable given the way that the windows backends need to pretend to have fds for the core of libusbx to process.

Rather than trying to optimise how the fake fds are generated and handled, I think the best thing to do is to add improved APIs to improve event handling on platforms which don't have fds and then change the internals to not need fake fds.

Before I rush off an implement something, I wanted to check with the community to see how people feel things should be done.

I see two possible ways of approaching the problem:

1) Add a new type, libusb_event_handle, which either maps to an FD or a HANDLE, as appropriate on each platform. I've attached a first attempt at the API changes in new_event_api.diff. It is a new API but is very similar to the pre-existing poll api.

2) Add the ability to start and stop async event processing threads which are internal to libusb. I've attached a first attempt at the API changes in async_thread_api.diff.

I think the second approach probably matches up better with the future direction of hotplug. The only benefit I can really think of the former approach is that it allows the libusbx user to continue to control the thread context for transfer completion callbacks, as well as when the callbacks can occur.

Any thoughts or alternative suggestions are welcome.

Regards,

Toby
>From 80e453300a5c738e0793a61170346e01b09d942b Mon Sep 17 00:00:00 2001
From: Toby Gray <toby.g...@realvnc.com>
Date: Thu, 11 Apr 2013 15:59:45 +0100
Subject: [PATCH] Initial attempt at async event handling thread

---
 libusb/libusb.h |   74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 74 insertions(+), 0 deletions(-)

diff --git a/libusb/libusb.h b/libusb/libusb.h
index 3613864..b467916 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -1515,6 +1515,80 @@ void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx,
 	libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
 	void *user_data);
 
+/** \ingroup threaded
+ * Callback function, invoked when libusb has started the asynchronous
+ * event handling thread.
+ *
+ * This allows runtimes to be made aware of the thread context which
+ * may be used for callbacks. For example some Java Virtual Machines
+ * require all native threads to register before they can call into
+ * the JVM.
+ *
+ * \param user_data User data pointer specified in
+ * libusb_start_async_event_thread() call
+ * \see libusb_start_async_event_thread()
+ */
+typedef void (LIBUSB_CALL *libusb_thread_started_cb)(void *user_data);
+
+/** \ingroup threaded
+ * Callback function, invoked when libusb is about to stop the asynchronous
+ * event handling thread.
+ *
+ * This allows runtimes to be made aware that the thread context which
+ * was used for callbacks is disappearing.
+ *
+ * \param user_data User data pointer specified in
+ * libusb_start_async_event_thread() call
+ * \see libusb_start_async_event_thread()
+ *
+ */
+typedef void (LIBUSB_CALL *libusb_thread_stopping_cb)(void *user_data);
+
+/** \ingroup threaded
+ * Requests that libusb starts the asynchronous event processing thread.
+ *
+ * This will start a thread 
+ *
+ * It is valid to request that the async event thread is started multiple
+ * times. However a matching number of calls to libusb_stop_async_event_thread
+ * should be made and stopping_cb will only be called once the thread
+ * finally ends.
+ *
+ * If the asynchronous event thread is already running then started_cb
+ * will be called from the event thread context before the next callback
+ * occurs after this function has returned.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param started_cb The callback to call in the event thread context
+ * before calling any other callbacks.
+ * \param stopping_cb The callback called in the event thread context
+ * before the event thread is stopped.
+ * \param user_data User data pointer to pass to callback functions
+ * \return LIBUSB_ERROR code on failure or LIBUSB_SUCCESS.
+ * \see libusb_stop_async_event_thread()
+ * \see libusb_thread_started_cb
+ * \see libusb_thread_stopping_cb
+ */
+int LIBUSB_CALL libusb_start_async_event_thread(libusb_context *ctx,
+    libusb_thread_started_cb started_cb, libusb_thread_stopping_cb stopping_cb,
+    void *user_data);
+
+/** \ingroup threaded
+ * Requests that libusb stops the asynchronous event processing thread.
+ *
+ * This stop an asynchronous event processing thread started by a previous call
+ * to libusb_start_async_event_thread.
+ *
+ * Every call to libusb_start_async_event_thread should have a matching call to 
+ * to function and only after all calls are matched will the asynchronous
+ * event thread be stopped.
+ * 
+ * \param ctx the context to operate on, or NULL for the default context
+ * \return LIBUSB_ERROR code on failure or LIBUSB_SUCCESS.
+ * \see libusb_stop_async_event_thread()
+ */
+int LIBUSB_CALL libusb_stop_async_event_thread(libusb_context *ctx);
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.7.9

>From 1cffe06c1331b5af028bd24aab6ddd67be24ce4a Mon Sep 17 00:00:00 2001
From: Toby Gray <toby.g...@realvnc.com>
Date: Thu, 11 Apr 2013 15:37:59 +0100
Subject: [PATCH] Initial attempt at more cross platform event handling

---
 libusb/libusb.h |   64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/libusb/libusb.h b/libusb/libusb.h
index 3613864..b137f94 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -1515,6 +1515,70 @@ void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx,
 	libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
 	void *user_data);
 
+/** \ingroup events
+ * Platform specific event handle type.
+ */
+#if defined(_WIN32) || defined(_WIN32_WCE)
+typedef HANDLE libusb_event_handle;
+#else
+/* All other platforms, including cygwin, use fds */
+typedef int libusb_event_handle;
+#endif
+
+/** \ingroup events
+ * The direction that a libusb_event_handle should be monitored for
+ * activity.
+ */
+enum libusb_event_direction {
+   /** The event handle doesn't have the concept of a direction. */
+   LIBUSB_EVENT_DIR_NONE = 0x0,
+   /** Monitoring for incoming data, e.g. reading */
+   LIBUSB_EVENT_DIR_IN   = 0x1,
+   /** Monitoring for outgoing data, e.g. write */
+   LIBUSB_EVENT_DIR_OUT  = 0x2,
+   /** Monitoring for incoming or outgoing data, e.g. read or write */
+   LIBUSB_EVENT_DIR_BOTH = (LIBUSB_EVENT_DIR_IN | LIBUSB_EVENT_DIR_OUT)
+};
+
+/** \ingroup events
+ * Event description for polling
+ */
+struct libusb_event {
+	libusb_event_handle handle;
+    enum libusb_event_direction direction;
+};
+
+/** \ingroup events
+ * Callback function, invoked when a new file descriptor should be added
+ * to the set of file descriptors monitored for events.
+ * \param fd the new file descriptor
+ * \param events events to monitor for, see \ref libusb_pollfd for a
+ * description
+ * \param user_data User data pointer specified in
+ * libusb_set_pollfd_notifiers() call
+ * \see libusb_set_pollfd_notifiers()
+ */
+typedef void (LIBUSB_CALL *libusb_event_added_cb)(libusb_event_handle handle,
+    enum libusb_event_direction direction, void *user_data);
+
+/** \ingroup poll
+ * Callback function, invoked when a file descriptor should be removed from
+ * the set of file descriptors being monitored for events. After returning
+ * from this callback, do not use that file descriptor again.
+ * \param fd the file descriptor to stop monitoring
+ * \param user_data User data pointer specified in
+ * libusb_set_pollfd_notifiers() call
+ * \see libusb_set_pollfd_notifiers()
+ */
+typedef void (LIBUSB_CALL *libusb_event_removed_cb)(libusb_event_handle handle,
+    void *user_data);
+
+const struct libusb_event ** LIBUSB_CALL libusb_get_events(
+	libusb_context *ctx);
+void LIBUSB_CALL libusb_set_event_notifiers(libusb_context *ctx,
+	libusb_event_added_cb added_cb, libusb_event_removed_cb removed_cb,
+	void *user_data);
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.7.9

------------------------------------------------------------------------------
Precog is a next-generation analytics platform capable of advanced
analytics on semi-structured data. The platform includes APIs for building
apps and a phenomenal toolset for data science. Developers can use
our toolset for easy data analysis & visualization. Get a free account!
http://www2.precog.com/precogplatform/slashdotnewsletter
_______________________________________________
libusbx-devel mailing list
libusbx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libusbx-devel

Reply via email to