1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
# Setting up the environment
```ocaml
# #require "eio_main";;
```
```ocaml
open Eio.Std
module Trace = Eio.Private.Trace
let pp_promise pp f x =
match Promise.peek x with
| None -> Fmt.string f "unresolved"
| Some Error (Failure msg) -> Fmt.pf f "broken:%s" msg
| Some Error ex -> Fmt.pf f "broken:%a" Fmt.exn ex
| Some Ok x -> Fmt.pf f "fulfilled:%a" pp x
```
# Test cases
Create a promise, fork a thread waiting for it, then fulfull it:
```ocaml
# let () =
Eio_main.run @@ fun _stdenv ->
Switch.run @@ fun sw ->
let p, r = Promise.create () in
traceln "Initial state: %a" (pp_promise Fmt.string) p;
let thread = Fiber.fork_promise ~sw (fun () -> Promise.await_exn p) in
Promise.resolve_ok r "ok";
traceln "After being fulfilled: %a" (pp_promise Fmt.string) p;
traceln "Thread before yield: %a" (pp_promise Fmt.string) thread;
Fiber.yield ();
traceln "Thread after yield: %a" (pp_promise Fmt.string) thread;
traceln "Final result: %s" (Promise.await_exn thread);;
+Initial state: unresolved
+After being fulfilled: fulfilled:ok
+Thread before yield: unresolved
+Thread after yield: fulfilled:ok
+Final result: ok
```
Create a promise, fork a thread waiting for it, then break it:
```ocaml
# let () =
Eio_main.run @@ fun _stdenv ->
Switch.run @@ fun sw ->
let p, r = Promise.create () in
traceln "Initial state: %a" (pp_promise Fmt.string) p;
let thread = Fiber.fork_promise ~sw (fun () -> Promise.await_exn p) in
Promise.resolve_error r (Failure "test");
traceln "After being broken: %a" (pp_promise Fmt.string) p;
traceln "Thread before yield: %a" (pp_promise Fmt.string) thread;
Fiber.yield ();
traceln "Thread after yield: %a" (pp_promise Fmt.string) thread;
match Promise.await_exn thread with
| x -> failwith x
| exception (Failure msg) -> traceln "Final result exception: %s" msg;;
+Initial state: unresolved
+After being broken: broken:test
+Thread before yield: unresolved
+Thread after yield: broken:test
+Final result exception: test
```
Some simple tests of `fork`:
```ocaml
# let () =
Eio_main.run @@ fun _stdenv ->
let i = ref 0 in
Switch.run (fun sw ->
Fiber.fork ~sw (fun () -> incr i);
);
traceln "Forked code ran; i is now %d" !i;
let p1, r1 = Promise.create () in
try
Switch.run (fun sw ->
Fiber.fork ~sw (fun () -> Promise.await p1; incr i; raise Exit);
traceln "Forked code waiting; i is still %d" !i;
Promise.resolve r1 ()
);
assert false
with Exit ->
traceln "Forked code ran; i is now %d" !i;;
+Forked code ran; i is now 1
+Forked code waiting; i is still 1
+Forked code ran; i is now 2
```
Basic semaphore tests:
```ocaml
# let () =
let module Semaphore = Eio.Semaphore in
Eio_main.run @@ fun _stdenv ->
Switch.run @@ fun sw ->
let running = ref 0 in
let sem = Semaphore.make 2 in
let fork = Fiber.fork_promise ~sw in
let a = fork (fun () -> Trace.log "a"; Semaphore.acquire sem; incr running) in
let b = fork (fun () -> Trace.log "b"; Semaphore.acquire sem; incr running) in
let c = fork (fun () -> Trace.log "c"; Semaphore.acquire sem; incr running) in
let d = fork (fun () -> Trace.log "d"; Semaphore.acquire sem; incr running) in
traceln "Semaphore means that only %d threads are running" !running;
Promise.await_exn a;
Promise.await_exn b;
(* a finishes and c starts *)
decr running;
Semaphore.release sem;
traceln "One finished; now %d is running " !running;
Fiber.yield ();
traceln "Yield allows C to start; now %d are running " !running;
Promise.await_exn c;
(* b finishes and d starts *)
decr running;
Semaphore.release sem;
Promise.await_exn d;
decr running;
Semaphore.release sem;
decr running;
Semaphore.release sem;;
+Semaphore means that only 2 threads are running
+One finished; now 1 is running
+Yield allows C to start; now 2 are running
```
Releasing a semaphore when no-one is waiting for it:
```ocaml
# let () =
let module Semaphore = Eio.Semaphore in
Eio_main.run @@ fun _stdenv ->
Switch.run @@ fun sw ->
let sem = Semaphore.make 0 in
Semaphore.release sem; (* Release with free-counter *)
traceln "Initial config: %d" (Semaphore.get_value sem);
Fiber.fork ~sw (fun () -> Trace.log "a"; Semaphore.acquire sem);
Fiber.fork ~sw (fun () -> Trace.log "b"; Semaphore.acquire sem);
traceln "A running: %d" (Semaphore.get_value sem);
Semaphore.release sem; (* Release with a non-empty wait-queue *)
traceln "Now b running: %d" (Semaphore.get_value sem);
Semaphore.release sem; (* Release with an empty wait-queue *)
traceln "Finished: %d" (Semaphore.get_value sem);;
+Initial config: 1
+A running: 0
+Now b running: 0
+Finished: 1
```
|