# Miou, a simple scheduler for OCaml 5 ```ocaml 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][documentation]. It describes (with examples) Miou's behaviour. The official repository is available [here][repository]. The project is being maintained by the [robur.coop][robur] 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][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][echo]. ### 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](#fn1) - 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`: ```ocaml 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: ```ocaml 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. ```ocaml 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 Exception: 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. ```ocaml let prgm () = Miou_unix.run @@ fun () -> let p = Miou.async @@ fun () -> let q = Miou.async @@ fun () -> Miou_unix.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. ```ocaml 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. ```ocaml 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' -> () | _ -> until_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: 1) extend the coverage of your code 2) be less sensitive to predictions that could help an attacker