As far as I know, async cannot be used with MirageOS. Is there any work someone is doing to enable async to be used with a MirageOS unikernel?
Hi,
Due to the fact that MirageOS is an operating system, usual syscalls and famous libc
functions are surely not available in MirageOS essentially. Indeed, into details, MirageOS (for the Solo5 target) uses a special caml runtime: ocaml-freestanding
which is an hacked version of OCaml with a static link to nolibc
(and few others libraries).
This is why we say: if your library depends (transitively or not) to the Unix
module, your project will not be (fully) available for MirageOS - and it’s why you can see some *-unix
variants of various MirageOS libraries.
About async
, or more precisely async_kernel
and core_kernel
, they widely use some syscalls which are not available in MirageOS (such as localtime
for example). These projects are huge and it’s difficult for the MirageOS core team to try to remove properly these syscalls and maintain a smaller async
compatible with MirageOS on our own way.
In the opposite, lwt
did this split (between the scheduler and Unix
syscalls) at the beginning. You can find lwt
and lwt.unix
. So, it was more easy to integrate lwt
in MirageOS and the time decided to strictly use lwt
as our scheduler - indeed, at some points, we abstracted the scheduler type 'a io
but it was a bit a pain to maintain such abstraction (with a systematic specialisation to 'a Lwt.t
) on all of our libraries.
So, of course, it should be possible to integrate async_kernel
into MirageOS - tweak a bit with ocaml-freestanding
to add some new syscalls or functorize async
over some specific syscalls (such as Mirage_time.S
or Mirage_clock.S
) and let functoria
about the application of these functors.
At the end, most of MirageOS projects are functorized over a scheduler. For example, you have a version of cohttp
for async
or some others libraries such as ocaml-tls
or decompress
don’t depends on any syscalls (so they can be used with async
, lwt
or … nothing!). This is on what we believe, be system-agnostic.
So about MirageOS itself, I don’t think that we have any plan to use async
- as I said, it’s a huge work. But the limit is mostly on theasync
side than MirageOS according to our abstraction - and I don’t blame Janestreet , it’s fine and they may be don’t have the resource to do this job too! Indeed, we continuously think about lwt
as a spontaneous dependency due to its design but we keep in our mind that the community is larger than lwt
and the future will be about ocaml-multicore
.
Great writeup, @dinosaure!
FWIW, the Async_unix
/Async_kernel
is meant to convey the distinction between the parts of Async that depend on Unix and those that don’t. But, “does not depend on Unix” in this case means “works in js_of_ocaml and theoretically on Windows” but not “works in MirageOS”, so for example Core_kernel
's dependency on libc’s localtime (for use in strftime) is complemented by a separate JavaScript stub for strftime. This works fine for the first standard but not the second, sadly.
You are right but evil are in the details!
Indeed, the problem comes with the Unix
dependency but more globally, anything with C stubs (like async_kernel
/core_kernel
or the Unix
module) will have a problem with MirageOS.
As I explained, the first problem is the non-availability of some C functions (due to nolibc
). But the second problem is: how to compile a C stubs (like otherlibs/unix/*.c
or your own C stubs). Indeed, C stubs must be compiled with specific *.h
and, for Solo5, with specific flags.
MirageOS, or more specially ocaml-freestanding
and Solo5 put some pkg-config
files into your OPAM environment. By this way, some libraries such as digestif
or mirage-crypto
can compile C stubs with specific flags. Currently, these flags are available with:
PKG_CONFIG_PATH := $(opam config var prefix)/lib/pkgconfig
PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config --cflags ocaml-freestanding
You can see a real example with mirage-crypto
here.
Then, the mirage
tool does the right things about the link-step (to craft the operating system). Indeed, it will take these special artifact with ocamlfind
(unusable for a simple executable) with your operating system. By this way, we ensure a sanitized ELF object (between nolibc
, ocaml-freestanding
- the caml runtime and third-part libraries with C stubs such as mirage-crypto
or digestif
).
Such plumbing is a bit a pain and error-prone. So, in the case of async_kernel
/core_kernel
, the second problem will be to ask JaneStreet to compile twice the *.a
of C stubs:
- one for an usual link with a simple host OCaml program
- the other to be able to link them with our special caml-runtime (
ocaml-freestanding
)
This is what we did for bigstringaf
which is a library outside the scope of the MirageOS eco-system but widely used by us. But, about async
, the problem will be more complex - the codebase is bigger and we talk about C so we can have some surprises!
Of course, at this point, you can say that such solution does not really scale and… you are true. Even if we want to limit as much as possible C stubs in our codebase, we reached several times some limitations (cross-compilation comes to my mind). This is an other big difference with lwt
, the core library does not have any C stubs!
However, the good news is (some teasing…): MirageOS 4! With the MirageOS core team, we currently work on a realistic solution about C stubs. I don’t want to go to details but the next release is through to fix these problem specially (with dune
).
So the first biggest issue (roadblock) with attempting to adapt Async to MirageOS is how the c stubs are handled by the MirageOS build system. After that the async stubs will need to be adapted to MirageOS?
So MirageOS 4 - with its dune integration - aims to solve the first issue?
Not exactly unfortunately, the first problem (about unavailable C functions) remains. However, MirageOS 4 should help to extend the set of MirageOS targets. Due to the story of ocaml-freestandng
/Solo5/Xen, we are currently stuck to few targets (Unix, Solo5 & Xen) and an extension of them need an incredible work on third-part libraries (digestif
and mirage-crypto
will must compile a third artifact according to the new target).
MirageOS 4 wants to solve that and propose an other way to link third-part libraries - more concretely, we will compile locally third-part libraries according to your requested target (and C flags) and solve by this way the question about C stubs.
The solution focus on:
- the extension of targets (including cross-compiled targets)
- third-part libraries (with C stubs)
As you can see, we don’t talk about scheduler here because several questions comes:
- the
type 'a io
currently specialized to'a Lwt.t
. Even if most of our libraries abstract this type, it’s not systematically the true. For instance,ocaml-git
and Irmin useslwt
directly - the main loop, as you can see here is defined by the back-end chosen (where
mirage-unix
uselwt.unix
/Lwt_engine
)
So a move to async
(with MirageOS 4 - which is not released yet ) implies:
- some patches on
ocaml-freestanding
(to implement missing C functions) - a new
mirage
back-end (with another implementation of the main loop) - an systemic abstraction (with functors) of some famous MirageOS libraries
If you look into details, most of issues is about a inherent technical debt about our choices in the past. Anything is possible but should we spend our time to that? As I said most of times, we are few to maintain MirageOS and we must choose intelligently our path. For my perspective, I never used async
and I don’t need it when lwt
exists on the other side (and fits well in our case) - but I’m surely biased when I did my first internship at ocsigen !
Of course, if anyone wants async
with MirageOS, the path is open - and we will gladly help you.
Thank you for the detailed answer @dinosaure. Much appreciated.
@dinosaure what about the janestreet base
package? Is it compatible with mirage?
It seems that base
integrate few C stubs (and you can find their equivalent in JavaScript). As I said and according to the current state of MirageOS 3, base
must:
- provides a re-compilation of these C stubs with flags from
ocaml-freestanding
- tricks on the
META
file to give an opportunity to take the produced*.a
by themirage
tool at the link time
Again, the minimal example of such plumbing exists: see the freestanding
artifact of bigstringaf
. You have 2 options:
- propose a pull-request to
janestreet/base
to be compatible with MirageOS 3 - fork
base
and use this fork instead of upstream
We usually want to follow the first option but we understand that such plumbing can be a pain for maintainers. The needed effort can be in contrast with what’s happening now. Indeed, nobody really notice that but we released several packages (mirage-tcpip
, io-page
, etc.) to prepare MirageOS 4 (and keep the compatibility with MirageOS 3 in the mid term).
That does not mean that MirageOS 4 will appear tomorrow but I’m confident to say that the release will appear soon and we already launched the train. For MirageOS 4, we still have an issue with base
& parsexp
but, as far as I can say, the next release of them (or the current release) will fix the hypothetic support of MirageOS 4.
So I would like to say to be patient and wait the next major release of MirageOS 4 .
Nice. Already looking forward to MirageOS 4.