[Haskell-cafe] Need comments on a libusb asynchronous select/poll loop

John Obbele john.obbele at gmail.com
Tue Apr 19 15:06:05 CEST 2011


I was reading the recent thread about select/poll, events
handling and why forkIO is the only thing you should need (sorry
if this is a horrible summary ;) and I'm realizing I could use
some advice concerning my last project.

I'm trying to implement an asynchronous interface to libusb, re-using
the raw bindings-usb (by Maurício C. Antunes) and partially copying what
can be found in the (great but synchronous-only) usb package (from Bas
van Dijk).

The issues are:

1) I don't know how to expose the asynchronous API to Haskell. (How would
you 'functionalize' it ?)

2) I am messing with lots of FFI calls around epoll and libusb and would
appreciate if someone could sanitize my approach.

A pre-alpha-use-at-your-own-risk code preview is available there[1].

[1]: https://patch-tag.com/r/obbele/usb-asynchronous/home

So far, my answer to both issues was:

Issue 1)
Create an 'AsyncManager' data type to use in code like the following:

>readAsyncIO = do $
>	dev      <- getDeviceByVIDPID
>	amanager <- newAsyncManager dev iface
>	-- AsyncManager set a background thread to poll libusb for new events.
>
>	sendURB amanager dummyURB -- non-blocking call
>	urb <- getURB amanager -- blocking
>	putStr . pprintURB $ urb
>
>	closeAsyncManager amanager
>
>  where iface = 0
>		dummyURB = newControlTransfer … 

Any opinions on this model ?
(N.B.: to keep things simple, I do not yet plan to add a 'cancel'
feature to this binding).


Issue 2)
What libusb asynchronous API requires is the following:

1. initialize resources, get device handles, etc.

2. get a set of file descriptors and select/poll them for read or write
   access.

3. register USB transfers

4. when the transfers are completed, libusb will signal it on one of the
   file descriptors. (but we don't know which one)

5. when your select/poll awakes from one event (it doesn't matter which
   one), you call libusb_handle_events which will flush every pending
   transfer by calling its associated callback function.

   This results in the C runtime calling back an Haskell function (thus
   the RTS will spawn an OS thread to handle it -- which doesn't bug
   anymore since GHC 7.0.2.x :)

6. GOTO 3 or 4

Complete libusb idiosyncrasies are explained in [2] and [3]:
[2]: http://libusb.sourceforge.net/api-1.0/group__asyncio.html
[3]: http://libusb.sourceforge.net/api-1.0/mtasync.html

So far, I didn't find a 'blessed' FFI interface to select/poll the set
of file descriptors and I'm currently using Toralf Wittner's Epoll
package. (which is very fine albeit a linux-only hack).

I am wondering if anyone know a magic wand (or abstraction model) to
ease my headaches in Haskell.

Something that could be more cross-platform ?
Something that could be well-integrated with the (GHC) FFI ?
Something that could be ... simple ?


any help appreciated ,)
/John


P.S.: and third question : how the heck am I supposed to debug threaded
FFI code in Haskell ? With GDB ?

Yes I'm particularly upset about background Haskell threads which die
silently (e.g. when encountering a segfault) and dead-lock the whole
RTS.



More information about the Haskell-Cafe mailing list