System threads in the era of multicore Ocaml?

I’m trying to do so Vulkan stuff with OCaml, but for the life of me I can’t seem to find references for multicore OCaml on how to deal with threads of execution that can block in C calls.

What am I missing? Any pointers to docs or examples would be welcomed.

Thanks.

Assuming you’re writing/studying the Vulkan bindings yourself and you’re somewhat familiar with OCaml 5 domains already, you’re probably looking for this section of the OCaml manual.

In short, a long-running C call is going to inevitably block its thread. Since the thread is holding its domain’s lock, it will also prevent any other thread attached to the same domain from resuming in parallel[1], unless you release the lock manually before the call (and reacquire it later). Releasing the lock, however, prevents the long-running code from accessing any OCaml heap memory during the call, as the GC could invalidate the addresses concurrently.[2]

Which Vulkan APIs do you expect to block? Were you trying to avoid blocking the UI thread, or maybe to cooperate with an effect-based scheduler such as Eio?


  1. You might not care about this if you or your dependencies aren’t spawning systhreads, only single-threaded domains. ↩︎

  2. The backing buffers for bigarrays however are not allocated on the OCaml heap and have got fixed addresses, so they can be accessed without the lock. ↩︎

Any memory allocation reclaim, effectively. Swapchain threads will also block via vkAcquireNextImageKHR, but that’s a completely different ball game.

Memory is mapped via RBAR so that both CPU and GPU can access it. However, once the memory is submitted to the task/mesh/compute shader, some CPU thread has to wait until the GPU is done and signals that it released ownership (generally via timeline semaphores in modern Vulkan) until it can reclaim/reuse the mapped memory.

Task and mesh shaders make this kind of process quite non-deterministic.

Ideally in OCaml 5, these calls would yield to an effect-based scheduler instead of blocking the thread. But Vulkan doesn’t seem to offer yet a way to do this, so you’ll need a blocking C call:

There are extensions to obtain a POSIX file descriptor or Windows handle for a semaphore or fence, which one can usually await, by effect, on an scheduler using epoll/WaitForMultipleObjects to resume the continuation. However, the extensions are not specified to support these APIs and in practice they don’t.[1].

So you’ll need to block some thread for the Vulkan semaphores, maybe a helper thread, like you would using Vulkan in other languages. If you care about other systhreads attached to the same OCaml domain, you might want to release/acquire the domain lock around vkWaitSemaphores as mentioned in the OCaml manual, but other than that there’s no extra ceremony needed.


  1. Even the one case implied to allow epoll, vkGetFenceFdKHR for SYNC_FD handles, seems to lack driver support. ↩︎