package containers
A modular, clean and powerful extension of the OCaml standard library
Install
Dune Dependency
Authors
Maintainers
Sources
v2.8.tar.gz
md5=03b80e963186e91ddac62ef645bf7fb2
sha512=c8f434808be540c16926bf03d89f394d33fc2d092f963a7b6d412481229e0a96290f1ad7c7d522415115d35426b7aa0b3fda4b991ddc321dad279d402c9a0c0b
doc/src/containers.thread/CCTimer.ml.html
Source file CCTimer.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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
(* This file is free software, part of containers. See file "license" for more details. *) (** {1 Event timer} *) type job = | Job : float * (unit -> 'a) -> job let (<=) (a : float) b = Stdlib.(<=) a b let (>=) (a : float) b = Stdlib.(>=) a b let (<) (a : float) b = Stdlib.(<) a b let (>) (a : float) b = Stdlib.(>) a b module TaskHeap = CCHeap.Make(struct type t = job let leq (Job(f1,_)) (Job (f2,_)) = f1 <= f2 end) exception Stopped type t = { mutable stop : bool; mutable tasks : TaskHeap.t; mutable exn_handler : (exn -> unit); t_mutex : Mutex.t; fifo_in : Unix.file_descr; fifo_out : Unix.file_descr; } let set_exn_handler timer f = timer.exn_handler <- f let standby_wait = 10. (* when no task is scheduled, this is the amount of time that is waited in a row for something to happen. This is also the maximal delay between the call to {!stop} and the actual termination of the thread. *) let epsilon = 0.0001 (* accepted time diff for actions. *) let with_lock_ t f = Mutex.lock t.t_mutex; try let x = f t in Mutex.unlock t.t_mutex; x with e -> Mutex.unlock t.t_mutex; raise e type command = | Quit | Run : (unit -> _) -> command | Wait of float let pop_task_ t = let tasks, _ = TaskHeap.take_exn t.tasks in t.tasks <- tasks let call_ timer f = try ignore (f ()) with e -> timer.exn_handler e (* check next task *) let next_task_ timer = match TaskHeap.find_min timer.tasks with | _ when timer.stop -> Quit | None -> Wait standby_wait | Some Job (time, f) -> let now = Unix.gettimeofday () in if now +. epsilon > time then ( (* now! *) pop_task_ timer; Run f ) else Wait (time -. now) (* The main thread function: wait for next event, run it, and loop *) let serve timer = let buf = Bytes.make 1 '_' in (* acquire lock, call [process_task] and do as it commands *) let rec next () = match with_lock_ timer next_task_ with | Quit -> () | Run f -> call_ timer f; (* call outside of any lock *) next () | Wait delay -> wait delay (* wait for [delay] seconds, or until something happens on [fifo_in] *) and wait delay = let read = Thread.wait_timed_read timer.fifo_in delay in (* remove char from fifo, so that next write can happen *) if read then ignore (Unix.read timer.fifo_in buf 0 1); next () in next () let nop_handler_ _ = () let create () = let fifo_in, fifo_out = Unix.pipe () in let timer = { stop = false; tasks = TaskHeap.empty; exn_handler = nop_handler_; t_mutex = Mutex.create (); fifo_in; fifo_out; } in (* start a thread to process tasks *) let _t = Thread.create serve timer in timer let underscore_ = Bytes.make 1 '_' (* awake the thread *) let awaken_ timer = ignore (Unix.single_write timer.fifo_out underscore_ 0 1) (** [at s t ~f] will run [f ()] at the Unix echo [t] *) let at timer time ~f = if timer.stop then raise Stopped; let now = Unix.gettimeofday () in if now >= time then call_ timer f else with_lock_ timer (fun timer -> if timer.stop then raise Stopped; (* time of the next scheduled event *) let next_time = match TaskHeap.find_min timer.tasks with | None -> max_float | Some Job (d, _) -> d in (* insert task *) timer.tasks <- TaskHeap.insert (Job (time, f)) timer.tasks; (* see if the timer thread needs to be awaken earlier *) if time < next_time then awaken_ timer ) let after timer delay ~f = assert (delay >= 0.); let now = Unix.gettimeofday () in at timer (now +. delay) ~f exception ExitEvery let every ?delay timer d ~f = let rec run () = try ignore (f ()); schedule() with ExitEvery -> () (* stop *) and schedule () = after timer d ~f:run in match delay with | None -> run() | Some d -> after timer d ~f:run (*$R let start = Unix.gettimeofday() in let timer = create() in let res = CCLock.create 0 in let sem = CCSemaphore.create 1 in CCSemaphore.acquire 1 sem; let stop = ref 0. in every timer 0.1 ~f:(fun () -> if CCLock.incr_then_get res > 5 then ( stop := Unix.gettimeofday(); CCSemaphore.release 1 sem; raise ExitEvery )); CCSemaphore.acquire 1 sem; (* wait *) OUnit.assert_equal ~printer:CCInt.to_string 6 (CCLock.get res); OUnit.assert_bool "estimate delay" (abs_float (!stop -. start -. 0.5) < 0.2); *) let active timer = not timer.stop (** Stop the given timer, cancelling pending tasks *) let stop timer = with_lock_ timer (fun timer -> if not timer.stop then ( timer.stop <- true; (* empty heap of tasks *) timer.tasks <- TaskHeap.empty; (* tell the thread to stop *) awaken_ timer; ) ) (*$R (* scenario: n := 1; n := n*4 ; n := n+2; res := n *) let timer = create () in let n = CCLock.create 1 in let res = CCLock.create 0 in after timer 0.3 ~f:(fun () -> CCLock.update n (fun x -> x+2)); ignore (Thread.create (fun _ -> Thread.delay 0.4; CCLock.set res (CCLock.get n)) ()); after timer 0.2 ~f:(fun () -> CCLock.update n (fun x -> x * 4)); Thread.delay 0.6 ; OUnit.assert_equal 6 (CCLock.get res); *)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>