package affect
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Streamlined and natural concurrency model for OCaml
Install
dune-project
Dependency
Authors
Maintainers
Sources
affect-0.0.0.tbz
sha512=b328f6696e60c489da8cc2e8fad0537ca6634a39fc0c5de5840d4f98561f110617ef79ba8285ee8427dd99908c6b3d39114973598cddc5ded91abcce3b91b9a6
doc/src/affect.unix/affect_unix__timeline.ml.html
Source file affect_unix__timeline.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 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 147 148 149 150 151 152 153 154 155 156 157(*--------------------------------------------------------------------------- Copyright (c) 2026 The affect programmers. All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*) open Affect__base open Affect.Action.Private (* Monotonic clock We have the minimal set of operations for the timeline here, the rest is in [Affect_unix__mtime.ml]. *) type uint64 = int64 type mtime_ns = uint64 type mtime_span_ns = uint64 external mtime_now_ns : unit -> mtime_ns = "ocaml_affect_mtime_now_ns" let int64_min_int_float = Int64.to_float Int64.min_int let int64_max_int_float = Int64.to_float Int64.max_int let mtime_span_ns_to_float_ns span = if Int64.compare 0L span <= 0 then Int64.to_float span else int64_max_int_float +. (-. int64_min_int_float +. Int64.to_float span) let mtime_span_ns_to_float_s span = 1e-9 *. mtime_span_ns_to_float_ns span let mtime_span_ns_to_int_ms span = match Int64.unsigned_to_int (Int64.unsigned_div span 1_000_000L) with | None -> max_int | Some ms -> ms let mtime_compare = Int64.unsigned_compare let mtime_max_stamp = -1L let mtime_add_span t span = let sum = Int64.add t span in if mtime_compare t sum <= 0 then Some sum else None (* POSIX clock We have the minimal set of operations for the timeline here, the rest is in [Affect_unix__posix.ml]. *) type ptime_d_ps = int * int64 external ptime_now_d_ps : unit -> ptime_d_ps = "ocaml_affect_ptime_now_d_ps" let ps_count_in_day = 86_400_000_000_000_000L let ns_count_in_day = 86_400_000_000_000L let ptime_neg = function | (d, 0L) -> (-d, 0L) | (d, ps) -> (-(d + 1), Int64.sub ps_count_in_day ps) let ptime_add (d0, ps0) (d1, ps1) = let d = d0 + d1 in let ps = Int64.add ps0 ps1 in let ps_clamp = Int64.rem ps ps_count_in_day in let d = d + Int64.compare ps ps_clamp in d, ps_clamp let ptime_sub s0 s1 = ptime_add s0 (ptime_neg s1) let ptime_compare (d0, ps0) (d1, ps1) = let c = Int.compare d0 d1 in if c <> 0 then c else Int64.compare ps0 ps1 let ptime_span_to_mtime_span_ns (d, ps) = (* assert (d >= 0) *) let d_ns = Int64.(mul (of_int d) ns_count_in_day) in let ns = Int64.div ps 1000L in Int64.add d_ns ns (* Timelines *) type blocked_wait = | Mtime of Action.Blocked.Value.t | Ptime of ptime_d_ps * Action.Blocked.Value.t module Deadline = struct type t = mtime_ns * blocked_wait let compare (t0, _) (t1, _) = mtime_compare t0 t1 end module Deadlines = Synchronized_pqueue.MakeMin (Deadline) type t = { gc_count : int Atomic.t; deadlines : Deadlines.t; } let make () = { gc_count = Atomic.make 0; deadlines = Deadlines.make () } let gc_threshold = 300 let gc_synced tl = let not_synced = function | _, Mtime blocked -> Action.Blocked.Value.is_not_synced blocked | _, Ptime (_, blocked) -> Action.Blocked.Value.is_not_synced blocked in Atomic.set tl.gc_count 0; Deadlines.keep ~sat:not_synced tl.deadlines let maybe_gc_synced tl = if Atomic.get tl.gc_count > gc_threshold then gc_synced tl let is_empty tl = gc_synced tl; Deadlines.is_empty tl.deadlines let add_deadline deadline tl = Atomic.incr tl.gc_count; Deadlines.add deadline tl.deadlines let add_mtime_deadline tl t blocked = add_deadline (t, Mtime blocked) tl let add_ptime_deadline tl ~now ptime blocked = let posix_span = ptime_sub ptime now in (* assert (ptime > now) *) let mtime_span_ns = ptime_span_to_mtime_span_ns posix_span in let now = mtime_now_ns () in let mt = match mtime_add_span now mtime_span_ns with | None -> mtime_max_stamp (* well… *) | Some t -> t in add_deadline (mt, Ptime (ptime, blocked)) tl let unblock_blocked_wait tl blocked_wait = match blocked_wait with | Mtime blocked -> Action.Blocked.Value.synced_unblock_is_ours blocked | Ptime (t, blocked) -> let now = ptime_now_d_ps () in if ptime_compare t now <= 0 then Action.Blocked.Value.synced_unblock_is_ours blocked else (add_ptime_deadline tl ~now t blocked; false) let mtime_deadline_expired t ~now = mtime_compare t now <= 0 let progress_to_next_deadline tl = let rec unblock ~did_unblock tl ~now = let expired (t, _) = mtime_deadline_expired t ~now in match Deadlines.pop_sat_or_peek_min ~sat:expired tl.deadlines with | None -> did_unblock, None | Some Either.Left (_, blocked_wait) -> Atomic.decr tl.gc_count; let unblocked = unblock_blocked_wait tl blocked_wait in let did_unblock = did_unblock || unblocked in unblock ~did_unblock tl ~now | Some Either.Right (t, _) -> let now = mtime_now_ns () in if mtime_deadline_expired t ~now then unblock ~did_unblock tl ~now else let next_deadline_in_ns = Int64.sub t now in did_unblock, Some next_deadline_in_ns in let ret = unblock ~did_unblock:false tl ~now:(mtime_now_ns ()) in maybe_gc_synced tl; ret (* Domain local timeline Each domain may know about a timeline via domain local storage. This allows APIs calls in Mtime and Ptime to register deadlines on the appropriate timeline. *) let nil = make () let err_timeline_not_set () = invalid_arg "Timeline not set" let key : t Domain.DLS.key = Domain.DLS.new_key (fun () -> nil) let set_domain_local tl = Domain.DLS.set key tl let clear_domain_local () = set_domain_local nil let get_domain_local () = let tl = Domain.DLS.get key in if Repr.phys_equal tl nil then err_timeline_not_set () else tl
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>