mirror of
https://github.com/c-cube/moonpool.git
synced 2025-12-05 19:00:33 -05:00
177 lines
4.7 KiB
OCaml
177 lines
4.7 KiB
OCaml
open! Moonpool
|
|
module A = Atomic
|
|
module F = Moonpool_fib.Fiber
|
|
|
|
let ( let@ ) = ( @@ )
|
|
|
|
module TS = struct
|
|
type t = int list
|
|
|
|
let show (s : t) = String.concat "." @@ List.map string_of_int s
|
|
let init = [ 0 ]
|
|
|
|
let next_ = function
|
|
| [] -> [ 0 ]
|
|
| n :: tl -> (n + 1) :: tl
|
|
|
|
let tick (t : t ref) = t := next_ !t
|
|
|
|
let tick_get t =
|
|
tick t;
|
|
!t
|
|
end
|
|
|
|
(* more deterministic logging of events *)
|
|
module Log_ = struct
|
|
let events : (TS.t * string) list A.t = A.make []
|
|
|
|
let add_event t msg : unit =
|
|
while
|
|
let old = A.get events in
|
|
not (A.compare_and_set events old ((t, msg) :: old))
|
|
do
|
|
()
|
|
done
|
|
|
|
let logf t fmt = Printf.ksprintf (add_event t) fmt
|
|
|
|
let print_and_clear () =
|
|
let l =
|
|
A.exchange events []
|
|
|> List.map (fun (ts, msg) -> List.rev ts, msg)
|
|
|> List.sort Stdlib.compare
|
|
in
|
|
List.iter (fun (ts, msg) -> Printf.printf "%s: %s\n" (TS.show ts) msg) l
|
|
end
|
|
|
|
let logf = Log_.logf
|
|
|
|
let run1 ~runner () =
|
|
Printf.printf "============\nstart\n%!";
|
|
let clock = ref TS.init in
|
|
let fib =
|
|
F.spawn_top ~on:runner @@ fun () ->
|
|
let chan_progress = Chan.create ~max_size:4 () in
|
|
let chans = Array.init 5 (fun _ -> Chan.create ~max_size:4 ()) in
|
|
|
|
let subs =
|
|
List.init 5 (fun i ->
|
|
F.spawn ~protect:false @@ fun _n ->
|
|
Thread.delay (float i *. 0.01);
|
|
Chan.pop chans.(i);
|
|
Chan.push chan_progress i;
|
|
F.check_if_cancelled ();
|
|
i)
|
|
in
|
|
|
|
logf (TS.tick_get clock) "wait for subs";
|
|
|
|
F.spawn_ignore (fun () ->
|
|
for i = 0 to 4 do
|
|
Chan.push chans.(i) ();
|
|
let i' = Chan.pop chan_progress in
|
|
assert (i = i')
|
|
done);
|
|
|
|
(let clock0 = !clock in
|
|
List.iteri
|
|
(fun i f ->
|
|
let clock = ref (0 :: i :: clock0) in
|
|
logf !clock "await fiber %d" i;
|
|
logf (TS.tick_get clock) "cur fiber[%d] is some: %b" i
|
|
(Option.is_some @@ F.Private_.get_cur_opt ());
|
|
let res = F.await f in
|
|
logf (TS.tick_get clock) "cur fiber[%d] is some: %b" i
|
|
(Option.is_some @@ F.Private_.get_cur_opt ());
|
|
F.yield ();
|
|
logf (TS.tick_get clock) "res %d = %d" i res)
|
|
subs);
|
|
|
|
logf (TS.tick_get clock) "main fiber done"
|
|
in
|
|
|
|
Fut.await @@ F.res fib;
|
|
logf (TS.tick_get clock) "main fiber exited";
|
|
Log_.print_and_clear ();
|
|
()
|
|
|
|
let run2 ~runner () =
|
|
(* same but now, cancel one of the sub-fibers *)
|
|
Printf.printf "============\nstart\n";
|
|
|
|
let clock = ref TS.init in
|
|
let fib =
|
|
F.spawn_top ~on:runner @@ fun () ->
|
|
let@ () =
|
|
F.with_on_self_cancel (fun ebt ->
|
|
logf (TS.tick_get clock) "main fiber cancelled with %s"
|
|
@@ Exn_bt.show ebt)
|
|
in
|
|
|
|
let chans_unblock = Array.init 10 (fun _i -> Chan.create ~max_size:4 ()) in
|
|
let chan_progress = Chan.create ~max_size:4 () in
|
|
|
|
logf (TS.tick_get clock) "start fibers";
|
|
let subs =
|
|
let clock0 = !clock in
|
|
List.init 10 (fun i ->
|
|
let clock = ref (0 :: i :: clock0) in
|
|
F.spawn ~protect:false @@ fun _n ->
|
|
let@ () =
|
|
F.with_on_self_cancel (fun _ ->
|
|
logf (TS.tick_get clock) "sub-fiber %d was cancelled" i)
|
|
in
|
|
Thread.delay 0.002;
|
|
|
|
(* sync for determinism *)
|
|
Chan.pop chans_unblock.(i);
|
|
Chan.push chan_progress i;
|
|
|
|
if i = 7 then (
|
|
logf (TS.tick_get clock) "I'm fiber %d and I'm about to fail…" i;
|
|
failwith "oh no!"
|
|
);
|
|
|
|
F.check_if_cancelled ();
|
|
i)
|
|
in
|
|
|
|
let post = TS.tick_get clock in
|
|
List.iteri
|
|
(fun i fib ->
|
|
F.on_result fib (function
|
|
| Ok _ -> logf (i :: post) "fiber %d resolved as ok" i
|
|
| Error _ -> logf (i :: post) "fiber %d resolved as error" i))
|
|
subs;
|
|
|
|
(* sequentialize the fibers, for determinism *)
|
|
F.spawn_ignore (fun () ->
|
|
for j = 0 to 9 do
|
|
Chan.push chans_unblock.(j) ();
|
|
let j' = Chan.pop chan_progress in
|
|
assert (j = j')
|
|
done);
|
|
|
|
logf (TS.tick_get clock) "wait for subs";
|
|
List.iteri
|
|
(fun i f ->
|
|
logf (TS.tick_get clock) "await fiber %d" i;
|
|
let res = F.await f in
|
|
logf (TS.tick_get clock) "res %d = %d" i res)
|
|
subs;
|
|
logf (TS.tick_get clock) "yield";
|
|
F.yield ();
|
|
logf (TS.tick_get clock) "yielded";
|
|
logf (TS.tick_get clock) "main fiber done"
|
|
in
|
|
|
|
F.on_result fib (function
|
|
| Ok () -> logf (TS.tick_get clock) "main fiber result: ok"
|
|
| Error ebt ->
|
|
logf (TS.tick_get clock) "main fiber result: error %s" (Exn_bt.show ebt));
|
|
|
|
(try Fut.await @@ F.res fib
|
|
with Failure msg -> logf (TS.tick_get clock) "main fib failed with %S" msg);
|
|
logf (TS.tick_get clock) "main fiber exited";
|
|
Log_.print_and_clear ();
|
|
()
|