mirror of
https://github.com/ocaml-multicore/eio.git
synced 2025-08-23 00:01:45 -04:00
Improve traceln formatting
- Set up a box so that wrapping works correctly. - Print a `+` at the start of each trace line to show it is trace output. - Format location tag with the rest of the output (fixes wrapping). - Add tests for traceln.
This commit is contained in:
parent
8a1b2c6d82
commit
8f5043c458
88
README.md
88
README.md
@ -137,7 +137,7 @@ e.g.
|
||||
let buffer = Buffer.create 20 in
|
||||
main ~stdout:(Eio.Flow.buffer_sink buffer);
|
||||
traceln "Main would print %S" (Buffer.contents buffer);;
|
||||
Main would print "Hello, world!\n"
|
||||
+Main would print "Hello, world!\n"
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -158,12 +158,12 @@ let main _env =
|
||||
|
||||
```ocaml
|
||||
# Eio_main.run main;;
|
||||
x = 1
|
||||
y = 1
|
||||
x = 2
|
||||
y = 2
|
||||
x = 3
|
||||
y = 3
|
||||
+x = 1
|
||||
+y = 1
|
||||
+x = 2
|
||||
+y = 2
|
||||
+x = 3
|
||||
+y = 3
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -186,12 +186,12 @@ We can run the previous code with tracing enabled (writing to a new `trace.ctf`
|
||||
Ctf.Control.start trace_config;
|
||||
Eio_main.run main;
|
||||
Ctf.Control.stop trace_config;;
|
||||
x = 1
|
||||
y = 1
|
||||
x = 2
|
||||
y = 2
|
||||
x = 3
|
||||
y = 3
|
||||
+x = 1
|
||||
+y = 1
|
||||
+x = 2
|
||||
+y = 2
|
||||
+x = 3
|
||||
+y = 3
|
||||
```
|
||||
|
||||
The trace can be viewed using [mirage-trace-viewer][].
|
||||
@ -218,7 +218,7 @@ Here's what happens if one of the two threads above fails:
|
||||
Fibre.both ~sw
|
||||
(fun () -> for x = 1 to 3 do traceln "x = %d" x; Fibre.yield ~sw () done)
|
||||
(fun () -> failwith "Simulated error");;
|
||||
x = 1
|
||||
+x = 1
|
||||
Exception: Failure "Simulated error".
|
||||
```
|
||||
|
||||
@ -248,15 +248,15 @@ Switches can also be used to wait for threads even when there isn't an error. e.
|
||||
traceln "Second thread forked; top-level code is finished"
|
||||
);
|
||||
traceln "Switch is finished";;
|
||||
i = 1
|
||||
First thread forked
|
||||
j = 1
|
||||
i = 2
|
||||
Second thread forked; top-level code is finished
|
||||
j = 2
|
||||
i = 3
|
||||
j = 3
|
||||
Switch is finished
|
||||
+i = 1
|
||||
+First thread forked
|
||||
+j = 1
|
||||
+i = 2
|
||||
+Second thread forked; top-level code is finished
|
||||
+j = 2
|
||||
+i = 3
|
||||
+j = 3
|
||||
+Switch is finished
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -383,11 +383,11 @@ let main ~net ~addr =
|
||||
main
|
||||
~net:(Eio.Stdenv.net env)
|
||||
~addr:(`Tcp (Unix.inet_addr_loopback, 8080))
|
||||
Server ready...
|
||||
Connecting to server...
|
||||
Server accepted connection from client
|
||||
(normally we'd loop and accept more connections here)
|
||||
Server received: "Hello from client"
|
||||
+Server ready...
|
||||
+Connecting to server...
|
||||
+Server accepted connection from client
|
||||
+(normally we'd loop and accept more connections here)
|
||||
+Server received: "Hello from client"
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -464,9 +464,9 @@ let try_mkdir dir path =
|
||||
try_mkdir cwd "dir1";
|
||||
try_mkdir cwd "../dir2";
|
||||
try_mkdir cwd "/tmp/dir3";
|
||||
mkdir "dir1" -> ok
|
||||
mkdir "../dir2" -> Eio.Dir.Permission_denied("..", _)
|
||||
mkdir "/tmp/dir3" -> Eio.Dir.Permission_denied("/tmp", _)
|
||||
+mkdir "dir1" -> ok
|
||||
+mkdir "../dir2" -> Eio.Dir.Permission_denied("..", _)
|
||||
+mkdir "/tmp/dir3" -> Eio.Dir.Permission_denied("/tmp", _)
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -481,9 +481,9 @@ The checks also apply to following symlinks:
|
||||
try_write_file cwd "dir1/file1" "A";
|
||||
try_write_file cwd "link-to-dir1/file2" "B";
|
||||
try_write_file cwd "link-to-tmp/file3" "C"
|
||||
write "dir1/file1" -> ok
|
||||
write "link-to-dir1/file2" -> ok
|
||||
write "link-to-tmp/file3" -> Eio.Dir.Permission_denied("link-to-tmp/file3", _)
|
||||
+write "dir1/file1" -> ok
|
||||
+write "link-to-dir1/file2" -> ok
|
||||
+write "link-to-tmp/file3" -> Eio.Dir.Permission_denied("link-to-tmp/file3", _)
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -495,8 +495,8 @@ You can use `open_dir` (or `with_open_dir`) to create a restricted capability to
|
||||
Eio.Dir.with_open_dir cwd "dir1" @@ fun dir1 ->
|
||||
try_write_file dir1 "file4" "D";
|
||||
try_write_file dir1 "../file5" "E"
|
||||
write "file4" -> ok
|
||||
write "../file5" -> Eio.Dir.Permission_denied("../file5", _)
|
||||
+write "file4" -> ok
|
||||
+write "../file5" -> Eio.Dir.Permission_denied("../file5", _)
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -518,8 +518,8 @@ The standard environment provides a clock with the usual POSIX time:
|
||||
traceln "The time is now %f" (Eio.Time.now clock);
|
||||
Eio.Time.sleep clock 1.0;
|
||||
traceln "The time is now %f" (Eio.Time.now clock)
|
||||
The time is now 1623940778.270336
|
||||
The time is now 1623940779.270336
|
||||
+The time is now 1623940778.270336
|
||||
+The time is now 1623940779.270336
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -562,12 +562,12 @@ let main ~domain_mgr =
|
||||
```ocaml
|
||||
# Eio_main.run @@ fun env ->
|
||||
main ~domain_mgr:(Eio.Stdenv.domain_mgr env)
|
||||
Starting CPU-intensive task...
|
||||
Starting CPU-intensive task...
|
||||
Finished
|
||||
sum 1..50000 = 1250025000
|
||||
Finished
|
||||
sum 1..100000 = 5000050000
|
||||
+Starting CPU-intensive task...
|
||||
+Starting CPU-intensive task...
|
||||
+Finished
|
||||
+sum 1..50000 = 1250025000
|
||||
+Finished
|
||||
+sum 1..100000 = 5000050000
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
|
@ -44,20 +44,6 @@ let rec shiftv cs = function
|
||||
|
||||
effect Close : Unix.file_descr -> int
|
||||
|
||||
let stderr_mutex = Mutex.create ()
|
||||
|
||||
let default_traceln ?__POS__ fmt =
|
||||
fmt |> Format.kasprintf (fun msg ->
|
||||
Ctf.label msg;
|
||||
Mutex.lock stderr_mutex;
|
||||
Fun.protect ~finally:(fun () -> Mutex.unlock stderr_mutex)
|
||||
(fun () ->
|
||||
match __POS__ with
|
||||
| Some (file, lnum, _, _) -> Format.printf "%s:%d %s@." file lnum msg
|
||||
| None -> Format.printf "%s@." msg
|
||||
)
|
||||
)
|
||||
|
||||
module FD = struct
|
||||
type t = {
|
||||
seekable : bool;
|
||||
@ -635,7 +621,7 @@ let accept ~sw fd =
|
||||
let run_compute fn () =
|
||||
match fn () with
|
||||
| x -> x
|
||||
| effect Eio.Private.Effects.Trace k -> continue k default_traceln
|
||||
| effect Eio.Private.Effects.Trace k -> continue k Eunix.Trace.default_traceln
|
||||
|
||||
module Objects = struct
|
||||
type _ Eio.Generic.ty += FD : FD.t Eio.Generic.ty
|
||||
@ -976,7 +962,7 @@ let run ?(queue_depth=64) ?(block_size=4096) main =
|
||||
| exception ex ->
|
||||
Ctf.note_resolved child ~ex:(Some ex)
|
||||
)
|
||||
| effect Eio.Private.Effects.Trace k -> continue k default_traceln
|
||||
| effect Eio.Private.Effects.Trace k -> continue k Eunix.Trace.default_traceln
|
||||
| effect Alloc k ->
|
||||
let k = { Suspended.k; tid } in
|
||||
alloc_buf st k
|
||||
|
17
lib_eunix/trace.ml
Normal file
17
lib_eunix/trace.ml
Normal file
@ -0,0 +1,17 @@
|
||||
let mutex = Mutex.create ()
|
||||
|
||||
let default_traceln ?__POS__:pos fmt =
|
||||
let b = Buffer.create 512 in
|
||||
let k f =
|
||||
Option.iter (fun (file, lnum, _, _) -> Format.fprintf f " [%s:%d]" file lnum) pos;
|
||||
Format.pp_close_box f ();
|
||||
Format.pp_print_flush f ();
|
||||
let msg = Buffer.contents b in
|
||||
Ctf.label msg;
|
||||
let lines = String.split_on_char '\n' msg in
|
||||
Mutex.lock mutex;
|
||||
Fun.protect ~finally:(fun () -> Mutex.unlock mutex) @@ fun () ->
|
||||
List.iter (Printf.eprintf "+%s\n") lines;
|
||||
flush stderr
|
||||
in
|
||||
Format.kfprintf k (Format.formatter_of_buffer b) ("@[" ^^ fmt)
|
9
lib_eunix/trace.mli
Normal file
9
lib_eunix/trace.mli
Normal file
@ -0,0 +1,9 @@
|
||||
val mutex : Mutex.t
|
||||
|
||||
val default_traceln :
|
||||
?__POS__:string * int * int * int ->
|
||||
('a, Format.formatter, unit, unit) format4 -> 'a
|
||||
(** [default_traceln] is a suitable default implementation for {!Eio.Std.traceln}.
|
||||
It writes output to stderr, prefixing each line with a "+".
|
||||
If [__POS__] is given, it also displays the file and line number from that
|
||||
It uses {!mutex} so that only one domain's output is written at a time. *)
|
@ -20,7 +20,7 @@ Spawning a second domain:
|
||||
# run @@ fun mgr ->
|
||||
let response = Eio.Domain_manager.run_compute_unsafe mgr (fun () -> "Hello from new domain") in
|
||||
traceln "Got %S from spawned domain" response
|
||||
Got "Hello from new domain" from spawned domain
|
||||
+Got "Hello from new domain" from spawned domain
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -46,8 +46,8 @@ We can still run other fibres in the main domain while waiting:
|
||||
(fun () ->
|
||||
traceln "Other fibres can still run"
|
||||
)
|
||||
Spawning new domain...
|
||||
Other fibres can still run
|
||||
Got "Hello from new domain" from spawned domain
|
||||
+Spawning new domain...
|
||||
+Other fibres can still run
|
||||
+Got "Hello from new domain" from spawned domain
|
||||
- : unit = ()
|
||||
```
|
||||
|
@ -49,7 +49,7 @@ Creating a file and reading it back:
|
||||
let cwd = Eio.Stdenv.cwd env in
|
||||
write_file ~sw ~create:(`Exclusive 0o666) cwd "test-file" "my-data";
|
||||
traceln "Got %S" @@ read_file ~sw cwd "test-file"
|
||||
Got "my-data"
|
||||
+Got "my-data"
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -103,7 +103,7 @@ If-missing create succeeds if already exists:
|
||||
write_file ~sw ~create:(`If_missing 0o666) cwd "test-file" "1st-write-original";
|
||||
write_file ~sw ~create:(`If_missing 0o666) cwd "test-file" "2nd-write";
|
||||
traceln "Got %S" @@ read_file ~sw cwd "test-file"
|
||||
Got "2nd-write-original"
|
||||
+Got "2nd-write-original"
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -114,7 +114,7 @@ Truncate create succeeds if already exists, and truncates:
|
||||
write_file ~sw ~create:(`Or_truncate 0o666) cwd "test-file" "1st-write-original";
|
||||
write_file ~sw ~create:(`Or_truncate 0o666) cwd "test-file" "2nd-write";
|
||||
traceln "Got %S" @@ read_file ~sw cwd "test-file"
|
||||
Got "2nd-write"
|
||||
+Got "2nd-write"
|
||||
- : unit = ()
|
||||
# Unix.unlink "test-file";;
|
||||
- : unit = ()
|
||||
@ -136,7 +136,7 @@ Appending to an existing file:
|
||||
write_file ~sw ~create:(`Or_truncate 0o666) cwd "test-file" "1st-write-original";
|
||||
write_file ~sw ~create:`Never ~append:true cwd "test-file" "2nd-write";
|
||||
traceln "Got %S" @@ read_file ~sw cwd "test-file"
|
||||
Got "1st-write-original2nd-write"
|
||||
+Got "1st-write-original2nd-write"
|
||||
- : unit = ()
|
||||
# Unix.unlink "test-file";;
|
||||
- : unit = ()
|
||||
@ -151,8 +151,8 @@ Got "1st-write-original2nd-write"
|
||||
try_mkdir cwd "subdir/nested";
|
||||
write_file ~sw ~create:(`Exclusive 0o600) cwd "subdir/nested/test-file" "data";
|
||||
()
|
||||
mkdir "subdir" -> ok
|
||||
mkdir "subdir/nested" -> ok
|
||||
+mkdir "subdir" -> ok
|
||||
+mkdir "subdir/nested" -> ok
|
||||
- : unit = ()
|
||||
# Unix.unlink "subdir/nested/test-file"; Unix.rmdir "subdir/nested"; Unix.rmdir "subdir";;
|
||||
- : unit = ()
|
||||
@ -175,12 +175,12 @@ Creating directories with nesting, symlinks, etc:
|
||||
try_mkdir cwd "to-subdir";
|
||||
try_mkdir cwd "dangle/foo";
|
||||
()
|
||||
mkdir "subdir" -> ok
|
||||
mkdir "to-subdir/nested" -> ok
|
||||
mkdir "to-root/tmp/foo" -> Eio.Dir.Permission_denied("to-root/tmp", _)
|
||||
mkdir "../foo" -> Eio.Dir.Permission_denied("..", _)
|
||||
mkdir "to-subdir" -> Unix.Unix_error(Unix.EEXIST, "mkdirat", "to-subdir")
|
||||
mkdir "dangle/foo" -> Unix.Unix_error(Unix.ENOENT, "openat2", "")
|
||||
+mkdir "subdir" -> ok
|
||||
+mkdir "to-subdir/nested" -> ok
|
||||
+mkdir "to-root/tmp/foo" -> Eio.Dir.Permission_denied("to-root/tmp", _)
|
||||
+mkdir "../foo" -> Eio.Dir.Permission_denied("..", _)
|
||||
+mkdir "to-subdir" -> Unix.Unix_error(Unix.EEXIST, "mkdirat", "to-subdir")
|
||||
+mkdir "dangle/foo" -> Unix.Unix_error(Unix.ENOENT, "openat2", "")
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -195,9 +195,9 @@ Create a sandbox, write a file with it, then read it from outside:
|
||||
write_file ~sw ~create:(`Exclusive 0o600) subdir "test-file" "data";
|
||||
try_mkdir subdir "../new-sandbox";
|
||||
traceln "Got %S" @@ read_file ~sw cwd "sandbox/test-file"
|
||||
mkdir "sandbox" -> ok
|
||||
mkdir "../new-sandbox" -> Eio.Dir.Permission_denied("..", _)
|
||||
Got "data"
|
||||
+mkdir "sandbox" -> ok
|
||||
+mkdir "../new-sandbox" -> Eio.Dir.Permission_denied("..", _)
|
||||
+Got "data"
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -219,12 +219,12 @@ Using `cwd` we can't access the parent, but using `fs` we can:
|
||||
);
|
||||
Unix.unlink "test-file";
|
||||
Unix.rmdir "outside-cwd"
|
||||
mkdir "fs-test" -> ok
|
||||
chdir "fs-test"
|
||||
mkdir "../outside-cwd" -> Eio.Dir.Permission_denied("..", _)
|
||||
write "../test-file" -> Eio.Dir.Permission_denied("../test-file", _)
|
||||
mkdir "../outside-cwd" -> ok
|
||||
write "../test-file" -> ok
|
||||
chdir ".."
|
||||
+mkdir "fs-test" -> ok
|
||||
+chdir "fs-test"
|
||||
+mkdir "../outside-cwd" -> Eio.Dir.Permission_denied("..", _)
|
||||
+write "../test-file" -> Eio.Dir.Permission_denied("../test-file", _)
|
||||
+mkdir "../outside-cwd" -> ok
|
||||
+write "../test-file" -> ok
|
||||
+chdir ".."
|
||||
- : unit = ()
|
||||
```
|
||||
|
@ -69,11 +69,11 @@ Handling one connection, then cancelling the server:
|
||||
|
||||
```ocaml
|
||||
# run (test_address addr)
|
||||
Connecting to server...
|
||||
Server accepted connection from client
|
||||
Server received: "Hello from client"
|
||||
Client received: "Bye"
|
||||
Client finished - cancelling server
|
||||
+Connecting to server...
|
||||
+Server accepted connection from client
|
||||
+Server received: "Hello from client"
|
||||
+Client received: "Bye"
|
||||
+Client finished - cancelling server
|
||||
Exception: Failure "Test is over".
|
||||
```
|
||||
|
||||
@ -81,11 +81,11 @@ Handling one connection on a Unix domain socket:
|
||||
|
||||
```ocaml
|
||||
# run (test_address (`Unix "/tmp/eio-test.sock"))
|
||||
Connecting to server...
|
||||
Server accepted connection from client
|
||||
Server received: "Hello from client"
|
||||
Client received: "Bye"
|
||||
Client finished - cancelling server
|
||||
+Connecting to server...
|
||||
+Server accepted connection from client
|
||||
+Server received: "Hello from client"
|
||||
+Client received: "Bye"
|
||||
+Client finished - cancelling server
|
||||
Exception: Failure "Test is over".
|
||||
```
|
||||
|
||||
@ -93,11 +93,11 @@ Handling one connection on an abstract Unix domain socket:
|
||||
|
||||
```ocaml
|
||||
# run (test_address (`Unix "\x00/tmp/eio-test.sock"))
|
||||
Connecting to server...
|
||||
Server accepted connection from client
|
||||
Server received: "Hello from client"
|
||||
Client received: "Bye"
|
||||
Client finished - cancelling server
|
||||
+Connecting to server...
|
||||
+Server accepted connection from client
|
||||
+Server received: "Hello from client"
|
||||
+Client received: "Bye"
|
||||
+Client finished - cancelling server
|
||||
Exception: Failure "Test is over".
|
||||
```
|
||||
|
||||
@ -125,9 +125,9 @@ Cancelling the read:
|
||||
let msg = read_all flow in
|
||||
traceln "Client received: %S" msg
|
||||
)
|
||||
Connecting to server...
|
||||
Connection opened - cancelling server's read
|
||||
Client received: "Request cancelled"
|
||||
+Connecting to server...
|
||||
+Connection opened - cancelling server's read
|
||||
+Client received: "Request cancelled"
|
||||
Exception: Graceful_shutdown.
|
||||
```
|
||||
|
||||
|
@ -20,7 +20,7 @@ A very basic example:
|
||||
# run (fun _sw ->
|
||||
traceln "Running"
|
||||
);
|
||||
Running
|
||||
+Running
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -32,8 +32,8 @@ Turning off a switch still allows you to perform clean-up operations:
|
||||
Switch.turn_off sw (Failure "Cancel");
|
||||
traceln "Clean up"
|
||||
);
|
||||
Running
|
||||
Clean up
|
||||
+Running
|
||||
+Clean up
|
||||
Exception: Failure "Cancel".
|
||||
```
|
||||
|
||||
@ -45,10 +45,10 @@ Exception: Failure "Cancel".
|
||||
(fun () -> for i = 1 to 2 do traceln "i = %d" i; Fibre.yield ~sw () done)
|
||||
(fun () -> for j = 1 to 2 do traceln "j = %d" j; Fibre.yield ~sw () done)
|
||||
);
|
||||
i = 1
|
||||
j = 1
|
||||
i = 2
|
||||
j = 2
|
||||
+i = 1
|
||||
+j = 1
|
||||
+i = 2
|
||||
+j = 2
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -60,7 +60,7 @@ j = 2
|
||||
(fun () -> for i = 1 to 5 do traceln "i = %d" i; Fibre.yield ~sw () done)
|
||||
(fun () -> failwith "Failed")
|
||||
)
|
||||
i = 1
|
||||
+i = 1
|
||||
Exception: Failure "Failed".
|
||||
```
|
||||
|
||||
@ -72,7 +72,7 @@ Exception: Failure "Failed".
|
||||
(fun () -> Fibre.yield ~sw (); failwith "Failed")
|
||||
(fun () -> for i = 1 to 5 do traceln "i = %d" i; Fibre.yield ~sw () done)
|
||||
)
|
||||
i = 1
|
||||
+i = 1
|
||||
Exception: Failure "Failed".
|
||||
```
|
||||
|
||||
@ -118,7 +118,7 @@ The switch is already turned off when we try to fork. The new fibre doesn't star
|
||||
Fibre.fork_ignore ~sw (fun () -> traceln "Not reached");
|
||||
traceln "Main continues"
|
||||
)
|
||||
Main continues
|
||||
+Main continues
|
||||
Exception: Failure "Cancel".
|
||||
```
|
||||
|
||||
@ -148,9 +148,9 @@ Turning off a switch runs the cancel callbacks, unless they've been removed by t
|
||||
Switch.remove_hook h3;
|
||||
Switch.remove_hook h4
|
||||
)
|
||||
Cancel 3
|
||||
Cancel 1
|
||||
Cancel 4
|
||||
+Cancel 3
|
||||
+Cancel 1
|
||||
+Cancel 4
|
||||
Exception: Failure "Cancelled".
|
||||
```
|
||||
|
||||
@ -162,7 +162,7 @@ Wait for either a promise or a switch; switch cancelled first:
|
||||
Switch.turn_off sw (Failure "Cancelled");
|
||||
Promise.fulfill r ()
|
||||
)
|
||||
Waiting
|
||||
+Waiting
|
||||
Exception: Failure "Cancelled".
|
||||
```
|
||||
|
||||
@ -177,9 +177,9 @@ Wait for either a promise or a switch; promise resolves first:
|
||||
traceln "Now cancelling...";
|
||||
Switch.turn_off sw (Failure "Cancelled")
|
||||
);
|
||||
Waiting
|
||||
Resolved
|
||||
Now cancelling...
|
||||
+Waiting
|
||||
+Resolved
|
||||
+Now cancelling...
|
||||
Exception: Failure "Cancelled".
|
||||
```
|
||||
|
||||
@ -192,7 +192,7 @@ Wait for either a promise or a switch; switch cancelled first. Result version.
|
||||
Switch.turn_off sw (Failure "Cancelled");
|
||||
Promise.fulfill r ()
|
||||
);
|
||||
Waiting
|
||||
+Waiting
|
||||
Exception: Failure "Cancelled".
|
||||
```
|
||||
|
||||
@ -206,8 +206,8 @@ Wait for either a promise or a switch; promise resolves first but switch off wit
|
||||
traceln "Now cancelling...";
|
||||
Switch.turn_off sw (Failure "Cancelled")
|
||||
)
|
||||
Waiting
|
||||
Now cancelling...
|
||||
+Waiting
|
||||
+Now cancelling...
|
||||
Exception: Failure "Cancelled".
|
||||
```
|
||||
|
||||
@ -221,10 +221,10 @@ Child switches are cancelled when the parent is cancelled:
|
||||
Fibre.fork_sub_ignore ~sw ~on_error (fun sw -> traceln "Child 2"; Promise.await ~sw p);
|
||||
Switch.turn_off sw (Failure "Cancel parent")
|
||||
)
|
||||
Child 1
|
||||
Child 2
|
||||
child: Failure("Cancel parent")
|
||||
child: Failure("Cancel parent")
|
||||
+Child 1
|
||||
+Child 2
|
||||
+child: Failure("Cancel parent")
|
||||
+child: Failure("Cancel parent")
|
||||
Exception: Failure "Cancel parent".
|
||||
```
|
||||
|
||||
@ -242,10 +242,10 @@ A child can fail independently of the parent:
|
||||
Fibre.yield ~sw ();
|
||||
traceln "Parent fibre is still running"
|
||||
)
|
||||
Child 1
|
||||
Child 2
|
||||
child: Failure("Child error")
|
||||
Parent fibre is still running
|
||||
+Child 1
|
||||
+Child 2
|
||||
+child: Failure("Child error")
|
||||
+Parent fibre is still running
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -265,9 +265,9 @@ A child can be cancelled independently of the parent:
|
||||
Fibre.yield ~sw ();
|
||||
traceln "Parent fibre is still running"
|
||||
);
|
||||
Child 1
|
||||
child: Failure("Cancel child")
|
||||
Parent fibre is still running
|
||||
+Child 1
|
||||
+child: Failure("Cancel child")
|
||||
+Parent fibre is still running
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -282,7 +282,7 @@ A child error handle raises:
|
||||
Fibre.yield ~sw ();
|
||||
traceln "Not reached"
|
||||
)
|
||||
Child
|
||||
+Child
|
||||
Exception: Failure "Child error escapes".
|
||||
```
|
||||
|
||||
@ -294,8 +294,8 @@ A child error handler deals with the exception:
|
||||
let x = Switch.sub sw ~on_error:print (fun _sw -> failwith "Child error") in
|
||||
traceln "x = %d" x
|
||||
)
|
||||
Failure("Child error")
|
||||
x = 0
|
||||
+Failure("Child error")
|
||||
+x = 0
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -320,8 +320,8 @@ Release on success:
|
||||
Switch.on_release sw (fun () -> traceln "release 1");
|
||||
Switch.on_release sw (fun () -> traceln "release 2");
|
||||
)
|
||||
release 2
|
||||
release 1
|
||||
+release 2
|
||||
+release 1
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -333,8 +333,8 @@ Release on error:
|
||||
Switch.on_release sw (fun () -> traceln "release 2");
|
||||
failwith "Test error"
|
||||
)
|
||||
release 2
|
||||
release 1
|
||||
+release 2
|
||||
+release 1
|
||||
Exception: Failure "Test error".
|
||||
```
|
||||
|
||||
@ -346,9 +346,9 @@ A release operation itself fails:
|
||||
Switch.on_release sw (fun () -> traceln "release 2");
|
||||
Switch.on_release sw (fun () -> traceln "release 3"; failwith "failure 3");
|
||||
)
|
||||
release 3
|
||||
release 2
|
||||
release 1
|
||||
+release 3
|
||||
+release 2
|
||||
+release 1
|
||||
Exception: Multiple exceptions:
|
||||
Failure("failure 3")
|
||||
and
|
||||
@ -376,12 +376,12 @@ Using switch from inside release handler:
|
||||
);
|
||||
traceln "Main fibre done"
|
||||
)
|
||||
Main fibre done
|
||||
Starting release 2
|
||||
Starting release 1
|
||||
Finished release 2
|
||||
Finished release 1
|
||||
Late release
|
||||
+Main fibre done
|
||||
+Starting release 2
|
||||
+Starting release 1
|
||||
+Finished release 2
|
||||
+Finished release 1
|
||||
+Late release
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -401,9 +401,9 @@ We release when `fork_sub_ignore` returns:
|
||||
# run (fun sw ->
|
||||
fork_sub_ignore_resource sw
|
||||
)
|
||||
Allocate resource
|
||||
Child fibre running
|
||||
Free resource
|
||||
+Allocate resource
|
||||
+Child fibre running
|
||||
+Free resource
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -414,8 +414,8 @@ We release when `fork_sub_ignore` fails due to parent switch being already off:
|
||||
Switch.turn_off sw (Failure "Switch already off");
|
||||
fork_sub_ignore_resource sw
|
||||
)
|
||||
Allocate resource
|
||||
Free resource
|
||||
+Allocate resource
|
||||
+Free resource
|
||||
Exception: Failure "Switch already off".
|
||||
```
|
||||
|
||||
@ -427,8 +427,8 @@ We release when `fork_sub_ignore` fails due to parent switch being invalid:
|
||||
Switch.sub sw ~on_error:raise (fun sub -> copy := sub);
|
||||
fork_sub_ignore_resource !copy
|
||||
)
|
||||
Allocate resource
|
||||
Free resource
|
||||
+Allocate resource
|
||||
+Free resource
|
||||
Exception: Invalid_argument "Switch finished!".
|
||||
```
|
||||
|
||||
@ -441,7 +441,7 @@ We release when `fork_sub_ignore`'s switch is turned off while running:
|
||||
~on_release:(fun () -> traceln "Free resource")
|
||||
(fun _sw -> failwith "Simulated error")
|
||||
)
|
||||
Allocate resource
|
||||
Free resource
|
||||
+Allocate resource
|
||||
+Free resource
|
||||
Exception: Failure "Simulated error".
|
||||
```
|
||||
|
@ -31,11 +31,11 @@ Create a promise, fork a thread waiting for it, then fulfull it:
|
||||
Fibre.yield ();
|
||||
traceln "Thread after yield: %a" (pp_promise Fmt.string) thread;
|
||||
traceln "Final result: %s" (Promise.await thread)
|
||||
Initial state: unresolved
|
||||
After being fulfilled: fulfilled:ok
|
||||
Thread before yield: unresolved
|
||||
Thread after yield: fulfilled:ok
|
||||
Final result: ok
|
||||
+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:
|
||||
@ -54,11 +54,11 @@ Create a promise, fork a thread waiting for it, then break it:
|
||||
match Promise.await 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
|
||||
+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_ignore`:
|
||||
@ -80,9 +80,9 @@ Some simple tests of `fork_ignore`:
|
||||
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
|
||||
+Forked code ran; i is now 1
|
||||
+Forked code waiting; i is still 1
|
||||
+Forked code ran; i is now 2
|
||||
```
|
||||
|
||||
Basic semaphore tests:
|
||||
@ -116,9 +116,9 @@ Basic semaphore tests:
|
||||
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
|
||||
+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:
|
||||
@ -137,8 +137,8 @@ Releasing a semaphore when no-one is waiting for it:
|
||||
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
|
||||
+Initial config: 1
|
||||
+A running: 0
|
||||
+Now b running: 0
|
||||
+Finished: 1
|
||||
```
|
||||
|
@ -68,9 +68,9 @@ Scheduling a timer that's already due:
|
||||
Fibre.both ~sw
|
||||
(fun () -> traceln "First fibre runs"; Eio.Time.sleep ~sw clock (-1.0); traceln "Sleep done")
|
||||
(fun () -> traceln "Second fibre runs")
|
||||
First fibre runs
|
||||
Second fibre runs
|
||||
Sleep done
|
||||
+First fibre runs
|
||||
+Second fibre runs
|
||||
+Sleep done
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
@ -89,6 +89,6 @@ Check ordering works:
|
||||
traceln "Short timer finished";
|
||||
Switch.turn_off sw (Failure "Simulated cancel")
|
||||
)
|
||||
Short timer finished
|
||||
+Short timer finished
|
||||
Exception: Failure "Simulated cancel".
|
||||
```
|
||||
|
14
tests/test_trace.md
Normal file
14
tests/test_trace.md
Normal file
@ -0,0 +1,14 @@
|
||||
```ocaml
|
||||
# #require "eio_main";;
|
||||
# open Eio.Std;;
|
||||
# Eio_main.run @@ fun _env ->
|
||||
traceln "One-line trace";
|
||||
traceln "@[<v2>A nested list@,Foo@,Bar@]";
|
||||
traceln "Trace with position" ~__POS__:("test_trace.md", 5, 1, 10);
|
||||
+One-line trace
|
||||
+A nested list
|
||||
+ Foo
|
||||
+ Bar
|
||||
+Trace with position [test_trace.md:5]
|
||||
- : unit = ()
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user