Module Clock_ns.Event
Events provide variants of run_at and run_after with the ability to abort or reschedule an event that hasn't yet happened. Once an event happens or is aborted, Async doesn't use any space for tracking it.
val sexp_of_t : ('a -> Ppx_sexp_conv_lib.Sexp.t) -> ('h -> Ppx_sexp_conv_lib.Sexp.t) -> ('a, 'h) t -> Ppx_sexp_conv_lib.Sexp.t
type t_unit= (unit, unit) t
val sexp_of_t_unit : t_unit -> Ppx_sexp_conv_lib.Sexp.t
include Core_kernel.Invariant.S2 with type ('a, 'b) t := ('a, 'b) t
val invariant : 'a Base__.Invariant_intf.inv -> 'b Base__.Invariant_intf.inv -> ('a, 'b) t Base__.Invariant_intf.inv
module Status : sig ... endval status : ('a, 'h) t -> ('a, 'h) Status.tIf
statusreturnsScheduled_at time, it is possible thattime < Time.now ()if Async's scheduler hasn't yet gotten the chance to update its clock, e.g., due to user jobs running.
val run_at : Time.t -> ('z -> 'h) -> 'z -> (_, 'h) tLet
t = run_at time f z. Attime, this runsf zand transitionsstatus ttoHappened h, wherehis result off z.More precisely, at
time, providedabort t ahas not previously been called, this will callf z, with the guarantee thatstatus t = Scheduled_at time. Iff zreturnshand did not callabort t a, thenstatus tbecomesHappened h. Iff zcallsabort t a, then the result offis ignored, andstatus tisAborted a.If
f zraises, thenstatus tdoes not transition and remainsScheduled_at time, and the exception is sent to the monitor in effect whenrun_atwas called.
val run_after : Time.Span.t -> ('z -> 'h) -> 'z -> (_, 'h) t
module Abort_result = Time_source.Event.Abort_resultval abort : ('a, 'h) t -> 'a -> ('a, 'h) Abort_result.tabort tchangesstatus ttoAbortedand returnsOk, unlesstpreviously happened or was previously aborted.
val abort_exn : ('a, 'h) t -> 'a -> unitabort_exn t areturnsunitifabort t a = `Ok, and otherwise raises.
val abort_if_possible : ('a, _) t -> 'a -> unitabort_if_possible t a = ignore (abort t a).
module Fired = Time_source.Event.Firedval fired : ('a, 'h) t -> ('a, 'h) Fired.t Async_kernel__.Clock_intf.Deferred.t
module Reschedule_result = Time_source.Event.Reschedule_resultval reschedule_at : ('a, 'h) t -> Time.t -> ('a, 'h) Reschedule_result.treschedule_at tandreschedule_after tchange the time thattwill fire, if possible, and if not, give a reason why. Likerun_at, if the requested time is in the past, the event will be scheduled to run immediately. Ifreschedule_at t time = Ok, then subsequentlyscheduled_at t = time.
val reschedule_after : ('a, 'h) t -> Time.Span.t -> ('a, 'h) Reschedule_result.tval at : Time.t -> (_, unit) tat timeisrun_at time ignore ().after timeisrun_after time ignore ().You should generally prefer to use the
run_*functions, which allow you to synchronously update state via a user-supplied function when the event transitions toHappened. That is, there is an important difference between:let t = run_at time f ()and:
let t = at time in fired t >>> function | Happened () -> f () | Aborted () -> ()With
run_at, ifstatus t = Happened, one knows thatfhas run. Withatandfired, one does not know whetherfhas yet run; it may still be scheduled to run. Thus, withatandfired, it is easy to introduce a race. For example, consider these two code snippets:let t = Event.after (sec 2.) in upon (Event.fired t) (function | Aborted () -> () | Happened () -> printf "Timer fired"); upon deferred_event (fun () -> match Event.abort t () with | Ok -> printf "Event occurred" | Previously_aborted () -> assert false | Previously_happened () -> printf "Event occurred after timer fired");let t = Event.run_after (sec 2.) printf "Timer fired" in upon deferred_event (fun () -> match Event.abort t () with | Ok -> printf "Event occurred" | Previously_aborted () -> assert false | Previously_happened () -> printf "Event occurred after timer fired");In both snippets, if
Event.abortreturnsOk, "Timer fired" is never printed. However, the first snippet might print "Event occurred after timer fired" and then "Timer fired". This confused ordering cannot happen withEvent.run_after.
val after : Time.Span.t -> (_, unit) t