Skip to content

Commit d8f4884

Browse files
authored
Merge pull request #608 from talex5/clock-variants
Convert clocks to new resource system
2 parents 490873e + 6083d1d commit d8f4884

File tree

16 files changed

+220
-133
lines changed

16 files changed

+220
-133
lines changed

doc/prelude.ml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ module Eio_main = struct
55

66
let now = ref 1623940778.27033591
77

8-
let fake_clock real_clock = object (_ : #Eio.Time.clock)
9-
method now = !now
10-
method sleep_until time =
8+
module Fake_clock = struct
9+
type time = float
10+
type t = time Eio.Time.clock_ty r (* The real clock *)
11+
12+
let make real_clock = (real_clock :> t)
13+
14+
let sleep_until real_clock time =
1115
(* The fake times are all in the past, so we just ask to wait until the
1216
fake time is due and it will happen immediately. If we wait for
1317
multiple times, they'll get woken in the right order. At the moment,
@@ -16,8 +20,14 @@ module Eio_main = struct
1620
TODO: This is no longer true (since #213). *)
1721
Eio.Time.sleep_until real_clock time;
1822
now := max !now time
23+
24+
let now _ = !now
1925
end
2026

27+
let fake_clock =
28+
let handler = Eio.Time.Pi.clock (module Fake_clock) in
29+
fun real_clock -> Eio.Resource.T (Fake_clock.make real_clock, handler)
30+
2131
(* To avoid non-deterministic output, we run the examples a single domain. *)
2232
let fake_domain_mgr = object (_ : #Eio.Domain_manager.t)
2333
method run fn =

lib_eio/eio.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ module Stdenv = struct
2828
let net (t : <net : _ Net.t; ..>) = t#net
2929
let process_mgr (t : <process_mgr : #Process.mgr; ..>) = t#process_mgr
3030
let domain_mgr (t : <domain_mgr : #Domain_manager.t; ..>) = t#domain_mgr
31-
let clock (t : <clock : #Time.clock; ..>) = t#clock
32-
let mono_clock (t : <mono_clock : #Time.Mono.t; ..>) = t#mono_clock
31+
let clock (t : <clock : _ Time.clock; ..>) = t#clock
32+
let mono_clock (t : <mono_clock : _ Time.Mono.t; ..>) = t#mono_clock
3333
let secure_random (t: <secure_random : _ Flow.source; ..>) = t#secure_random
3434
let fs (t : <fs : _ Path.t; ..>) = t#fs
3535
let cwd (t : <cwd : _ Path.t; ..>) = t#cwd

lib_eio/eio.mli

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,10 @@ module Stdenv : sig
213213
To use this, see {!Time}.
214214
*)
215215

216-
val clock : <clock : #Time.clock as 'a; ..> -> 'a
216+
val clock : <clock : _ Time.clock as 'a; ..> -> 'a
217217
(** [clock t] is the system clock (used to get the current time and date). *)
218218

219-
val mono_clock : <mono_clock : #Time.Mono.t as 'a; ..> -> 'a
219+
val mono_clock : <mono_clock : _ Time.Mono.t as 'a; ..> -> 'a
220220
(** [mono_clock t] is a monotonic clock (used for measuring intervals). *)
221221

222222
(** {1 Randomness} *)

lib_eio/mock/clock.ml

Lines changed: 65 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
open Eio.Std
22

3+
type 'time ty = [`Mock | 'time Eio.Time.clock_ty]
4+
35
module type S = sig
46
type time
57

6-
type t = <
7-
time Eio.Time.clock_base;
8-
advance : unit;
9-
set_time : time -> unit;
10-
>
8+
type t = time ty r
119

1210
val make : unit -> t
1311
val advance : t -> unit
@@ -22,11 +20,7 @@ module type TIME = sig
2220
end
2321

2422
module Make(T : TIME) : S with type time := T.t = struct
25-
type t = <
26-
T.t Eio.Time.clock_base;
27-
advance : unit;
28-
set_time : T.t -> unit;
29-
>
23+
type t = T.t ty r
3024

3125
module Key = struct
3226
type t = < >
@@ -44,49 +38,68 @@ module Make(T : TIME) : S with type time := T.t = struct
4438

4539
module Q = Psq.Make(Key)(Job)
4640

41+
module Impl = struct
42+
type time = T.t
43+
44+
type t = {
45+
mutable now : T.t;
46+
mutable q : Q.t;
47+
}
48+
49+
let make () =
50+
{
51+
now = T.zero;
52+
q = Q.empty;
53+
}
54+
55+
let now t = t.now
56+
57+
let sleep_until t time =
58+
if T.compare time t.now <= 0 then Fiber.yield ()
59+
else (
60+
let p, r = Promise.create () in
61+
let k = object end in
62+
t.q <- Q.add k { time; resolver = r } t.q;
63+
try
64+
Promise.await p
65+
with Eio.Cancel.Cancelled _ as ex ->
66+
t.q <- Q.remove k t.q;
67+
raise ex
68+
)
69+
70+
let set_time t time =
71+
let rec drain () =
72+
match Q.min t.q with
73+
| Some (_, v) when T.compare v.time time <= 0 ->
74+
Promise.resolve v.resolver ();
75+
t.q <- Option.get (Q.rest t.q);
76+
drain ()
77+
| _ -> ()
78+
in
79+
drain ();
80+
t.now <- time;
81+
traceln "mock time is now %a" T.pp t.now
82+
83+
let advance t =
84+
match Q.min t.q with
85+
| None -> invalid_arg "No further events scheduled on mock clock"
86+
| Some (_, v) -> set_time t v.time
87+
88+
type (_, _, _) Eio.Resource.pi += Raw : ('t, 't -> t, T.t ty) Eio.Resource.pi
89+
let raw (Eio.Resource.T (t, ops)) = Eio.Resource.get ops Raw t
90+
end
91+
92+
let handler =
93+
Eio.Resource.handler (
94+
H (Impl.Raw, Fun.id) ::
95+
Eio.Resource.bindings (Eio.Time.Pi.clock (module Impl));
96+
)
97+
4798
let make () =
48-
object (self)
49-
inherit [T.t] Eio.Time.clock_base
50-
51-
val mutable now = T.zero
52-
val mutable q = Q.empty
53-
54-
method now = now
55-
56-
method sleep_until time =
57-
if T.compare time now <= 0 then Fiber.yield ()
58-
else (
59-
let p, r = Promise.create () in
60-
let k = object end in
61-
q <- Q.add k { time; resolver = r } q;
62-
try
63-
Promise.await p
64-
with Eio.Cancel.Cancelled _ as ex ->
65-
q <- Q.remove k q;
66-
raise ex
67-
)
68-
69-
method set_time time =
70-
let rec drain () =
71-
match Q.min q with
72-
| Some (_, v) when T.compare v.time time <= 0 ->
73-
Promise.resolve v.resolver ();
74-
q <- Option.get (Q.rest q);
75-
drain ()
76-
| _ -> ()
77-
in
78-
drain ();
79-
now <- time;
80-
traceln "mock time is now %a" T.pp now
81-
82-
method advance =
83-
match Q.min q with
84-
| None -> invalid_arg "No further events scheduled on mock clock"
85-
| Some (_, v) -> self#set_time v.time
86-
end
87-
88-
let set_time (t:t) time = t#set_time time
89-
let advance (t:t) = t#advance
99+
Eio.Resource.T (Impl.make (), handler)
100+
101+
let set_time t v = Impl.set_time (Impl.raw t) v
102+
let advance t = Impl.advance (Impl.raw t)
90103
end
91104

92105
module Old_time = struct

lib_eio/mock/clock.mli

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
open Eio.Std
2+
3+
type 'time ty = [`Mock | 'time Eio.Time.clock_ty]
4+
15
module type S = sig
26
type time
37

4-
type t = <
5-
time Eio.Time.clock_base;
6-
advance : unit;
7-
set_time : time -> unit;
8-
>
8+
type t = time ty r
99

1010
val make : unit -> t
1111
(** [make ()] is a new clock.

lib_eio/time.ml

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,42 @@
1+
open Std
2+
13
exception Timeout
24

3-
class virtual ['a] clock_base = object
4-
method virtual now : 'a
5-
method virtual sleep_until : 'a -> unit
6-
end
5+
type 'a clock_ty = [`Clock of 'a]
6+
type 'a clock_base = 'a r constraint 'a = [> _ clock_ty]
7+
8+
module Pi = struct
9+
module type CLOCK = sig
10+
type t
11+
type time
12+
val now : t -> time
13+
val sleep_until : t -> time -> unit
14+
end
715

8-
class virtual clock = object
9-
inherit [float] clock_base
16+
type (_, _, _) Resource.pi +=
17+
| Clock : ('t, (module CLOCK with type t = 't and type time = 'time), [> 'time clock_ty]) Resource.pi
18+
19+
let clock (type t time) (module X : CLOCK with type t = t and type time = time) =
20+
Resource.handler [ H (Clock, (module X)) ]
1021
end
1122

12-
let now (t : _ #clock_base) = t#now
23+
type 'a clock = ([> float clock_ty] as 'a) r
24+
25+
let now (type time) (t : [> time clock_ty] r) =
26+
let Resource.T (t, ops) = t in
27+
let module X = (val (Resource.get ops Pi.Clock)) in
28+
X.now t
1329

14-
let sleep_until (t : _ #clock_base) time = t#sleep_until time
30+
let sleep_until (type time) (t : [> time clock_ty] r) time =
31+
let Resource.T (t, ops) = t in
32+
let module X = (val (Resource.get ops Pi.Clock)) in
33+
X.sleep_until t time
1534

1635
let sleep t d = sleep_until t (now t +. d)
1736

1837
module Mono = struct
19-
class virtual t = object
20-
inherit [Mtime.t] clock_base
21-
end
38+
type ty = Mtime.t clock_ty
39+
type 'a t = ([> ty] as 'a) r
2240

2341
let now = now
2442
let sleep_until = sleep_until
@@ -39,7 +57,7 @@ module Mono = struct
3957
else Mtime.Span.of_uint64_ns (Int64.of_float ns)
4058
) else Mtime.Span.zero (* Also happens for NaN and negative infinity *)
4159

42-
let sleep (t : #t) s =
60+
let sleep t s =
4361
sleep_span t (span_of_s s)
4462
end
4563

@@ -48,11 +66,11 @@ let with_timeout_exn t d = Fiber.first (fun () -> sleep t d; raise Timeout)
4866

4967
module Timeout = struct
5068
type t =
51-
| Timeout of Mono.t * Mtime.Span.t
69+
| Timeout of Mono.ty r * Mtime.Span.t
5270
| Unlimited
5371

5472
let none = Unlimited
55-
let v clock time = Timeout ((clock :> Mono.t), time)
73+
let v clock time = Timeout ((clock :> Mono.ty r), time)
5674

5775
let seconds clock time =
5876
v clock (Mono.span_of_s time)

lib_eio/time.mli

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
1-
class virtual ['a] clock_base : object
2-
method virtual now : 'a
3-
method virtual sleep_until : 'a -> unit
4-
end
1+
open Std
52

6-
class virtual clock : object
7-
inherit [float] clock_base
8-
end
3+
type 'a clock_ty = [`Clock of 'a]
4+
type 'a clock_base = 'a r constraint 'a = [> _ clock_ty]
5+
6+
type 'a clock = ([> float clock_ty] as 'a) r
97

10-
val now : #clock -> float
8+
val now : _ clock -> float
119
(** [now t] is the current time since 00:00:00 GMT, Jan. 1, 1970 - in seconds - according to [t]. *)
1210

13-
val sleep_until : #clock -> float -> unit
11+
val sleep_until : _ clock -> float -> unit
1412
(** [sleep_until t time] waits until the given time is reached. *)
1513

16-
val sleep : #clock -> float -> unit
14+
val sleep : _ clock -> float -> unit
1715
(** [sleep t d] waits for [d] seconds. *)
1816

1917
(** Monotonic clocks. *)
@@ -24,43 +22,42 @@ module Mono : sig
2422
2523
A monotonic clock may or may not include time while the computer is suspended. *)
2624

27-
class virtual t : object
28-
inherit [Mtime.t] clock_base
29-
end
25+
type ty = Mtime.t clock_ty
26+
type 'a t = ([> ty] as 'a) r
3027

31-
val now : #t -> Mtime.t
28+
val now : _ t -> Mtime.t
3229
(** [now t] is the current time according to [t]. *)
3330

34-
val sleep_until : #t -> Mtime.t -> unit
31+
val sleep_until : _ t -> Mtime.t -> unit
3532
(** [sleep_until t time] waits until [time] before returning. *)
3633

37-
val sleep : #t -> float -> unit
34+
val sleep : _ t -> float -> unit
3835
(** [sleep t d] waits for [d] seconds. *)
3936

40-
val sleep_span : #t -> Mtime.span -> unit
37+
val sleep_span : _ t -> Mtime.span -> unit
4138
(** [sleep_span t d] waits for duration [d]. *)
4239
end
4340

4441
(** {2 Timeouts} *)
4542

4643
exception Timeout
4744

48-
val with_timeout : #clock -> float -> (unit -> ('a, 'e) result) -> ('a, [> `Timeout] as 'e) result
45+
val with_timeout : _ clock -> float -> (unit -> ('a, 'e) result) -> ('a, [> `Timeout] as 'e) result
4946
(** [with_timeout clock d fn] runs [fn ()] but cancels it after [d] seconds. *)
5047

51-
val with_timeout_exn : #clock -> float -> (unit -> 'a) -> 'a
48+
val with_timeout_exn : _ clock -> float -> (unit -> 'a) -> 'a
5249
(** [with_timeout_exn clock d fn] runs [fn ()] but cancels it after [d] seconds,
5350
raising exception {!exception-Timeout}. *)
5451

5552
(** Timeout values. *)
5653
module Timeout : sig
5754
type t
5855

59-
val v : #Mono.t -> Mtime.Span.t -> t
56+
val v : _ Mono.t -> Mtime.Span.t -> t
6057
(** [v clock duration] is a timeout of [duration], as measured by [clock].
6158
Internally, this is just the tuple [(clock, duration)]. *)
6259

63-
val seconds : #Mono.t -> float -> t
60+
val seconds : _ Mono.t -> float -> t
6461
(** [seconds clock duration] is a timeout of [duration] seconds, as measured by [clock]. *)
6562

6663
val none : t
@@ -77,3 +74,21 @@ module Timeout : sig
7774
(** [pp] formats a timeout as a duration (e.g. "5s").
7875
This is intended for use in error messages and logging and is rounded. *)
7976
end
77+
78+
module Pi : sig
79+
module type CLOCK = sig
80+
type t
81+
type time
82+
83+
val now : t -> time
84+
val sleep_until : t -> time -> unit
85+
end
86+
87+
type (_, _, _) Resource.pi +=
88+
Clock : ('t, (module CLOCK with type t = 't and type time = 'time),
89+
[> 'time clock_ty ]) Resource.pi
90+
91+
val clock :
92+
(module CLOCK with type t = 't and type time = 'time) ->
93+
('t, [> 'time clock_ty]) Resource.handler
94+
end

0 commit comments

Comments
 (0)