package miou
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=9231806e6d60945e36ee060e5ca4a881bf87a60510a8ae5fa8bf45d3a16d0b84
sha512=cfac5caaa2fdcc3b572c6a541270ffbe9540e2fc35aa4ef7d84390a4d87f81214f69828642d1b84698c1798de8553f7d7cc5fe88d5dd68a12b694b7ba565b3b2
Description
Published: 22 Aug 2024
README
Miou, a simple scheduler for OCaml 5
let () = Miou.run @@ fun () ->
print_endline "Hello World!"
Miou is a library designed to facilitate the development of applications requiring concurrent and/or parallel tasks. This library has been developed with the aim of offering a fairly simple and straightforward design. It's a pretty small library with few dependencies that frames the behaviour of applications using precise and conservative rules to guide users in their development.
The API documentation is available here. It describes (with examples) Miou's behaviour. The official repository is available here. We also offer a mirror of this repository on GitHub. The project is being maintained by the robur.coop cooperative.
Miou is focusing on 2 objectives:
to provide a best-practice approach to the development of OCaml applications requiring concurrency and/or parallelism
composability that can satisfy the most limited contexts, such as unikernels
Miou meets these objectives by:
conservative and stable rules for the library's behaviour
an API that delegates suspension management to the user
A book is available which explains how to make applications with Miou in details. It introduces the reader to effects, implements a small scheduler and a small echo server as an example. You an also read a simple tutorial from our documentation explaining how to implement this echo server with here. Miou is heavily inspired by picos and we would like to thanks authors of this project.
Rules
Miou complies with several rules that the user must respect. These rules (which can be restrictive) help to guide the user towards good practice and avoid anti-patterns. This notion of rules and anti-patterns is arbitrary 1 - it can therefore be criticised and/or disengage the developer from using Miou. These rules come from our experience of system programming in OCaml, where the development of our software today confirms certain anti-patterns that we would not want to reproduce today (in view of the technical debt that these bring).
Creating and waiting for a task
There are 2 ways of creating a task:
it can run concurrently with other tasks and execute on the domain in which it was created (see
Miou.async
)it can run in parallel with other tasks and be executed on another domain (see
Miou.call
)
The first rule to follow is that the user must wait for all the tasks he/she has created. If they don't, Miou raises an exception: Still_has_children
:
let () = Miou.run @@ fun () ->
ignore (Miou.async @@ fun () -> 42)
Exception: Miou.Still_has_children
The user must therefore take care to use Miou.await
for all the tasks (concurrent and parallel) that he/she has created:
let () = Miou.run @@ fun () ->
let p0 = Miou.async @@ fun () -> 42 in
Miou.await_exn p0
Relationships between tasks
A task can only be awaited by the person who created it.
let () = Miou.run @@ fun () ->
let p0 = Miou.async @@ fun () -> 42 in
let p1 = Miou.async @@ fun () -> Miou.await_exn p0 in
Miou.await_exn p1
Esxception: Miou.Not_a_child
This rule dictates that passing values from one task to another requires (pragmatically) that a resource be allocated accordingly to represent such a transmission. It also reaffirms that such a passage of values must surely be protected by synchronisation mechanisms between the said tasks (with Miou.Mutex
or Miou.Condition
).
The only valid relationship (and transmission of values) between 2 tasks offered by Miou is that between a child and its parent.
Abnormal termination
If a task fails (with an exception), all its sub-tasks also end.
let prgm () = Miouu.run @@ fun () ->
let p = Miou.async @@ fun () ->
let q = Miou.async @@ fun () -> sleep 1. in
raise (Failure "p") in
Miou.await p
let () =
let t0 = Unix.gettimeofday () in
let _ = prgm () in
let t1 = Unix.gettimeofday () in
assert (t1 -. t0 < 1.)
This code shows that if p
fails, we also stop q
(which should wait at least 1 second). This shows that our prgm
didn't actually last a second. Abnormal termination will always attempt to complete all sub-tasks so that there are no zombie tasks.
Wait or cancel
It was explained above that all children must be waited on by the task that created them. However, the user can also Miou.cancel
a task - of course, this produces an abnormal termination of the task which automatically results in the termination of all its children.
let () = Miou.run @@ fun () ->
Miou.cancel (Miou.async @@ fun () -> 42)
This code shows that if it is not possible to ignore
the result of a task, it is still possible to cancel
it.
Randomised tasks
Tasks are taken randomly. That is to say that this code could return 1 as 2.
let prgm () =
Miou.run @@ fun () ->
let a = Miou.async (Fun.const 1) in
let b = Miou.async (Fun.const 2) in
Miou.await_first [ a; b ]
let rec until_its n =
match prgm () with
| Ok n' when n = n' -> ()
| _ -> untils_its n
let () =
until_its 1;
until_its 2
This code shows that it is possible for our program to return 1 or 2. The reason why we decided to randomly select the promises allows:
extend the coverage of your code
be less sensitive to predictions that could help an attacker
We just believe that it corresponds to our problems and our points of view. It is then up to the user to (dis)consider all this - which, as it stands, is much more than a strictly technical description.
Suspension and API
Miou finally proposes that the management of the suspension be delegated to the user. Indeed, task management focuses mainly on suspension management: that is, a task that can block the process.
It turns out that suspend mainly2 only affects the use of resources offered by the system (sockets, files, time, etc.). Our experience in system programming and in the development of unikernels teaches us that this management of system resources, although intrinsic to task management, is:
complex because of the subtleties that may exist between each system (Linux, *BSD, Mac, Windows, unikernels)
specific to the case of the suspension of a task while waiting for a signal from the system
As such and in our objective of composability with exotic systems, we have decided to offer the user two libraries:
miou
, which is the core of our projectmiou.unix
, which is an extension of our core with I/O
The second takes advantage of the API of the first regarding suspension. There is a tutorial explaining this API step by step and how to use it so that you can manage everything related to suspension (and, by extension, your system resources through the API it can offer).
Genesis
The development of Miou began following discussions with a number of actors, where we noted certain differences of opinion. We were not satisfied with the different signals we received on the problem of scheduling in the OCaml ecosystem, despite repeated efforts to reconcile these differences. Miou does not present itself as the absolute solution to the scheduling problem. It is simply the reemergence of these opinions in another environment which has unfortunately not been offered by the actors who had the opportunity to do so.
We would like to make it clear that we do not want to monopolise and/or compete with anyone. We would also like to inform future users that Miou regards our objectives and our vision - which you may not agree with. So, if Miou satisfies you in its approach (and that of its maintainers), and its objectives (and those of its users), welcome!
Dev Dependencies (11)
-
mtime
with-test & >= "2.0.0"
-
dns-client
with-test
-
dns
with-test
-
logs
with-test & >= "0.7.0"
-
ipaddr
with-test
-
mirage-crypto-rng
with-test
-
hxd
with-test
-
dns-client
with-test
-
happy-eyeballs
with-test & >= "0.6.0"
-
digestif
with-test
-
dscheck
with-test & >= "0.4.0"
Conflicts
None