The safest way to do this is wrap Lwt code within Async, and to invoke the Lwt_main runtime thread via Async_unix.In_thread
Reporting back on how it went.
So far so good. I originally just knocked out a function that constructed the
Lwt deferreds and ran
Lwt_main.run inside of the
Async.In_thread.run to get things going, and it has worked out well enough that I haven’t had to touch it.
let read_usb t len =
In_thread.run (fun () ->
let open Lwt.Infix in
let s = String.make len (Char.of_int_exn 0x0) in
~endpoint:endpoint_address s 0 len
>>= fun transfer ->
if Int.(<>) transfer len then
failwithf "read_usb: failed to read %d bytes: %d" len transfer ();
Lwt.return (Bytes.of_string s)
I’m a little squeamish about starting and finishing
Lwt_main.run on every call. No idea how much overhead that actually involves, but, again, seems to work so I haven’t investigated further.
Down the line, it doesn’t seem like this will go well if I need to talk to two USB devices at the same time, because we could end up with two different threads launching
Lwt_main.run, and I perhaps they will stomp on each other. It is possible to create a dedicated helper thread for
In_thread.run to force serialization there, but that’s not a much better solution.
If I end up in such a place I imagine I’ll rewrite the underlying ocaml usb bindings to be more
Async friendly but this seems good enough for now.