diff --git a/src/subscriber/trace_subscriber.ml b/src/subscriber/trace_subscriber.ml index fe13910..034a76a 100644 --- a/src/subscriber/trace_subscriber.ml +++ b/src/subscriber/trace_subscriber.ml @@ -1,4 +1,5 @@ open Trace_core +module A = Trace_core.Internal_.Atomic_ module Callbacks = Callbacks module Subscriber = Subscriber include Types @@ -183,3 +184,40 @@ let collector (Sub { st; callbacks = (module CB) } : Subscriber.t) : collector = CB.on_init st ~time_ns end in (module M) + +module Handle = struct + type t = int + + let compare : t -> t -> int = compare +end + +(** how to allocate new handles *) +let new_handle_ = + let a = A.make 0 in + fun () -> A.fetch_and_add a 1 + +module Handle_map = Map.Make (Handle) + +(** Set of subscribers *) +let top_subscribers : t Handle_map.t option A.t = A.make None + +let register_subscriber (s : t) : Handle.t = + let h = new_handle_ () in + let rec loop () = + let old = A.get top_subscribers in + let is_new, new_map = + match old with + | None -> true, Handle_map.singleton h s + | Some m -> false, Handle_map.add h s m + in + if A.compare_and_set top_subscribers old (Some new_map) then + is_new, new_map + else + loop () + in + + let is_new, map = loop () in + + h + +let unregister_subscriber (h : Handle.t) : unit = () diff --git a/src/subscriber/trace_subscriber.mli b/src/subscriber/trace_subscriber.mli index a20daf0..489c44f 100644 --- a/src/subscriber/trace_subscriber.mli +++ b/src/subscriber/trace_subscriber.mli @@ -24,6 +24,28 @@ val collector : t -> Trace_core.collector It uses [mtime] (if available) to obtain timestamps. *) +(** {2 Global set of subscribers} + + There is a global set of subscribers (it is not mandatory to use it). + When the first subscriber is added to it, a {!Trace_core.collector} + is registered (see {!Trace_core.setup_collector}). + + When the last subscriber is unregistered, the collector is shut down. *) + +module Handle : sig + type t = private int + (** A unique handle for a subscriber *) +end + +val register_subscriber : t -> Handle.t +(** Register a subscriber. This calls {!Trace_core.setup_collector} if + no other subscriber is registered. + @raise Invalid_argument if {!Trace_core.setup_collector} fails. *) + +val unregister_subscriber : Handle.t -> unit +(** Remove a subscriber using its handle. If no subscriber remains, + {!Trace_core.shutdown} is called to remove the collector. *) + (**/**) module Private_ : sig