mirror of
https://github.com/ocaml-multicore/eio.git
synced 2025-11-27 00:04:06 -05:00
Add Time.now and Time.sleep_until
Providers now provide `sleep_until`. `sleep` is implemented using that. This makes things a little more precise.
This commit is contained in:
parent
49dc7c62ca
commit
1b853cca44
19
README.md
19
README.md
@ -22,6 +22,7 @@ unreleased repository.
|
||||
* [Networking](#networking)
|
||||
* [Design note: object capabilities](#design-note-object-capabilities)
|
||||
* [Filesystem access](#filesystem-access)
|
||||
* [Time](#time)
|
||||
* [Multicore support](#multicore-support)
|
||||
* [Design note: thread-safety](#design-note-thread-safety)
|
||||
* [Design note: determinism](#design-note-determinism)
|
||||
@ -507,6 +508,24 @@ A program that operates on the current directory will probably want to use `cwd`
|
||||
whereas a program that accepts a path from the user will probably want to use `fs`,
|
||||
perhaps with `open_dir` to constrain all access to be within that directory.
|
||||
|
||||
## Time
|
||||
|
||||
The standard environment provides a clock with the usual POSIX time:
|
||||
|
||||
```ocaml
|
||||
# Eio_main.run @@ fun env ->
|
||||
let clock = Eio.Stdenv.clock env in
|
||||
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
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
You might like to replace this clock with a mock for tests.
|
||||
In fact, this README does just that - see [doc/prelude.ml](doc/prelude.ml) for the fake clock used in the example above!
|
||||
|
||||
## Multicore support
|
||||
|
||||
Fibres are scheduled cooperatively within a single domain, but you can also create new domains that run in parallel.
|
||||
|
||||
@ -3,8 +3,34 @@
|
||||
module Eio_main = struct
|
||||
open Eio.Std
|
||||
|
||||
let now = ref 1623940778.27033591
|
||||
|
||||
let fake_clock real_clock = object (_ : #Eio.Time.clock)
|
||||
method now = !now
|
||||
method sleep_until ?sw time =
|
||||
(* The fake times are all in the past, so we just ask to wait until the
|
||||
fake time is due and it will happen immediately. If we wait for
|
||||
multiple times, they'll get woken in the right order. At the moment,
|
||||
the scheduler only checks for expired timers when the run-queue is
|
||||
empty, so this is a convenient way to wait for the system to be idle.
|
||||
Will need revising if we make the scheduler fair at some point. *)
|
||||
Eio.Time.sleep_until ?sw real_clock time;
|
||||
now := max !now time
|
||||
end
|
||||
|
||||
(* https://github.com/ocaml/ocaml/issues/10324 *)
|
||||
let dontcrash = Sys.opaque_identity
|
||||
|
||||
let run fn =
|
||||
Eio_main.run @@ fun env ->
|
||||
try fn env
|
||||
try
|
||||
fn @@ object
|
||||
method net = dontcrash env#net
|
||||
method stdin = dontcrash env#stdin
|
||||
method stdout = dontcrash env#stdout
|
||||
method cwd = dontcrash env#cwd
|
||||
method domain_mgr = dontcrash env#domain_mgr
|
||||
method clock = fake_clock env#clock
|
||||
end
|
||||
with Failure msg -> traceln "Error: %s" msg
|
||||
end
|
||||
|
||||
@ -169,10 +169,15 @@ end
|
||||
|
||||
module Time = struct
|
||||
class virtual clock = object
|
||||
method virtual sleep : ?sw:Switch.t -> float -> unit
|
||||
method virtual now : float
|
||||
method virtual sleep_until : ?sw:Switch.t -> float -> unit
|
||||
end
|
||||
|
||||
let sleep ?sw (t : #clock) d = t#sleep ?sw d
|
||||
let now (t : #clock) = t#now
|
||||
|
||||
let sleep_until ?sw (t : #clock) time = t#sleep_until ?sw time
|
||||
|
||||
let sleep ?sw t d = sleep_until ?sw t (now t +. d)
|
||||
end
|
||||
|
||||
module Dir = struct
|
||||
|
||||
@ -363,9 +363,17 @@ end
|
||||
|
||||
module Time : sig
|
||||
class virtual clock : object
|
||||
method virtual sleep : ?sw:Switch.t -> float -> unit
|
||||
method virtual now : float
|
||||
method virtual sleep_until : ?sw:Switch.t -> float -> unit
|
||||
end
|
||||
|
||||
val now : #clock -> float
|
||||
(** [now t] is the current time according to [t]. *)
|
||||
|
||||
val sleep_until : ?sw:Switch.t -> #clock -> float -> unit
|
||||
(** [sleep_until t time] waits until the given time is reached.
|
||||
@param sw The sleep is aborted if the switch is turned off. *)
|
||||
|
||||
val sleep : ?sw:Switch.t -> #clock -> float -> unit
|
||||
(** [sleep t d] waits for [d] seconds.
|
||||
@param sw The sleep is aborted if the switch is turned off. *)
|
||||
|
||||
@ -404,9 +404,9 @@ let free_buf st buf =
|
||||
| None -> Uring.Region.free buf
|
||||
| Some k -> enqueue_thread st k buf
|
||||
|
||||
effect Sleep : Switch.t option * float -> unit
|
||||
let sleep ?sw d =
|
||||
perform (Sleep (sw, d))
|
||||
effect Sleep_until : Switch.t option * float -> unit
|
||||
let sleep_until ?sw d =
|
||||
perform (Sleep_until (sw, d))
|
||||
|
||||
effect ERead : (Switch.t option * Optint.Int63.t option * FD.t * Uring.Region.chunk * amount) -> int
|
||||
|
||||
@ -722,7 +722,8 @@ module Objects = struct
|
||||
let clock = object
|
||||
inherit Eio.Time.clock
|
||||
|
||||
method sleep ?sw d = sleep ?sw d
|
||||
method now = Unix.gettimeofday ()
|
||||
method sleep_until = sleep_until
|
||||
end
|
||||
|
||||
class dir fd = object
|
||||
@ -856,9 +857,8 @@ let run ?(queue_depth=64) ?(block_size=4096) main =
|
||||
let k = { Suspended.k; tid } in
|
||||
enqueue_accept ~sw st k fd client_addr;
|
||||
schedule st
|
||||
| effect (Sleep (sw, d)) k ->
|
||||
| effect (Sleep_until (sw, time)) k ->
|
||||
let k = { Suspended.k; tid } in
|
||||
let time = Unix.gettimeofday () +. d in
|
||||
let cancel_hook = ref Switch.null_hook in
|
||||
begin match sw with
|
||||
| None ->
|
||||
|
||||
@ -44,8 +44,8 @@ end
|
||||
|
||||
(** {1 Time functions} *)
|
||||
|
||||
val sleep : ?sw:Switch.t -> float -> unit
|
||||
(** [sleep s] blocks until (at least) [s] seconds have passed.
|
||||
val sleep_until : ?sw:Switch.t -> float -> unit
|
||||
(** [sleep_until time] blocks until the current time is [time].
|
||||
@param sw Cancel the sleep if [sw] is turned off. *)
|
||||
|
||||
(** {1 Memory allocation functions} *)
|
||||
|
||||
@ -24,7 +24,7 @@ let () =
|
||||
let buf = alloc () in
|
||||
let _ = read_exactly fd buf 5 in
|
||||
Logs.debug (fun l -> l "sleeping at %f" (Unix.gettimeofday ()));
|
||||
sleep 1.0;
|
||||
sleep_until (Unix.gettimeofday () +. 1.0);
|
||||
print_endline (Uring.Region.to_string ~len:5 buf);
|
||||
let _ = read_exactly fd ~file_offset:(Int63.of_int 3) buf 3 in
|
||||
print_endline (Uring.Region.to_string ~len:3 buf);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user