Source file timer_wheel.ml
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
open Core
open Util
module Timer = struct
type t = {
id : unit Ref.t;
mode : [ `interval | `one_off ];
mutable started_at : Ptime.t;
ends_at : Ptime.Span.t;
fn : unit -> unit;
}
let pp fmt t =
let mode = if t.mode = `interval then "interval" else "one_off" in
Format.fprintf fmt "Timer { id=%a; started_at=%a; ends_at=%a; mode=%s }"
Ref.pp t.id (Ptime.pp_rfc3339 ()) t.started_at Ptime.Span.pp t.ends_at
mode
let make time mode fn =
let id = Ref.make () in
let started_at = Ptime_clock.now () in
let ends_at = Ptime.Span.of_float_s time |> Option.get in
{ id; started_at; ends_at; fn; mode }
let equal a b = Ref.equal a.id b.id
end
type t = {
timers : (Timer.t, unit) Dashmap.t;
mutable last_t : Ptime.t; [@warning "-69"]
}
let create () = { timers = Dashmap.create (); last_t = Ptime_clock.now () }
let make_timer t time mode fn =
let timer = Timer.make time mode fn in
Dashmap.insert t.timers timer ();
timer.id
let ends_at now t1 =
let t0 = Ptime.to_span now in
Ptime.Span.add t0 t1 |> Ptime.of_span |> Option.get
let run_timer t now (timer, ()) =
let open Timer in
let ends_at = ends_at timer.started_at timer.ends_at in
Log.trace (fun f ->
f "Running timer %a with ends_at=%a" Timer.pp timer (Ptime.pp_rfc3339 ())
ends_at);
if Ptime.is_earlier now ~than:ends_at then ()
else (
(match timer.mode with
| `one_off ->
Dashmap.remove_by t.timers (fun (timer', ()) ->
not (Timer.equal timer timer'))
| `interval -> timer.started_at <- now);
timer.fn ())
let tick t =
let now = Ptime_clock.now () in
let timers = Dashmap.entries t.timers in
List.iter (run_timer t now) timers;
t.last_t <- now