
On Tue, Apr 19, 2011 at 8:06 AM, John Obbele
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 ?
Maybe I'm misunderstanding something, but why why I want to use epoll directly instead of just using forkIO plus threadWaitRead and threadWaitWrite? http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Con... As a developer, the concurrency model offered by the Control.Concurrency module has always been friendly to me. Maybe there was something in the other thread I missed. Antoine