mirror of
https://github.com/c-cube/moonpool.git
synced 2025-12-06 11:15:38 -05:00
cleanup the local storage APIs
This commit is contained in:
parent
953947f694
commit
45b8aa9999
12 changed files with 120 additions and 120 deletions
|
|
@ -2,15 +2,14 @@ open Types_
|
|||
include Runner
|
||||
|
||||
let ( let@ ) = ( @@ )
|
||||
let k_storage = Task_local_storage.Private_.Storage.k_storage
|
||||
|
||||
type task_full =
|
||||
| T_start of {
|
||||
ls: Task_local_storage.storage ref;
|
||||
ls: Task_local_storage.t;
|
||||
f: task;
|
||||
}
|
||||
| T_resume : {
|
||||
ls: Task_local_storage.storage ref;
|
||||
ls: Task_local_storage.t;
|
||||
k: 'a -> unit;
|
||||
x: 'a;
|
||||
}
|
||||
|
|
@ -30,7 +29,7 @@ let schedule_ (self : state) (task : task_full) : unit =
|
|||
try Bb_queue.push self.q task with Bb_queue.Closed -> raise Shutdown
|
||||
|
||||
type around_task = AT_pair : (t -> 'a) * (t -> 'a -> unit) -> around_task
|
||||
type worker_state = { mutable cur_ls: Task_local_storage.storage ref option }
|
||||
type worker_state = { mutable cur_ls: Task_local_storage.t option }
|
||||
|
||||
let k_worker_state : worker_state option ref TLS.key =
|
||||
TLS.new_key (fun () -> ref None)
|
||||
|
|
@ -56,7 +55,7 @@ let worker_thread_ (self : state) (runner : t) ~on_exn ~around_task : unit =
|
|||
| T_start { ls; _ } | T_resume { ls; _ } -> ls
|
||||
in
|
||||
w.cur_ls <- Some ls;
|
||||
TLS.set k_storage (Some ls);
|
||||
TLS.get k_cur_storage := Some ls;
|
||||
let _ctx = before_task runner in
|
||||
|
||||
(* run the task now, catching errors, handling effects *)
|
||||
|
|
@ -75,7 +74,7 @@ let worker_thread_ (self : state) (runner : t) ~on_exn ~around_task : unit =
|
|||
on_exn e bt);
|
||||
after_task runner _ctx;
|
||||
w.cur_ls <- None;
|
||||
TLS.set k_storage None
|
||||
TLS.get k_cur_storage := None
|
||||
in
|
||||
|
||||
let main_loop () =
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
open Types_
|
||||
include Runner
|
||||
|
||||
(* convenient alias *)
|
||||
let k_ls = Task_local_storage.Private_.Storage.k_storage
|
||||
|
||||
let run_async_ ~ls:cur_ls f =
|
||||
TLS.set k_ls (Some cur_ls);
|
||||
TLS.get k_cur_storage := Some cur_ls;
|
||||
try
|
||||
let x = f () in
|
||||
TLS.set k_ls None;
|
||||
TLS.get k_cur_storage := None;
|
||||
x
|
||||
with e ->
|
||||
let bt = Printexc.get_raw_backtrace () in
|
||||
TLS.set k_ls None;
|
||||
TLS.get k_cur_storage := None;
|
||||
Printexc.raise_with_backtrace e bt
|
||||
|
||||
let runner : t =
|
||||
|
|
|
|||
|
|
@ -26,15 +26,13 @@ val start_thread_on_some_domain : ('a -> unit) -> 'a -> Thread.t
|
|||
to run the thread. This ensures that we don't always pick the same domain
|
||||
to run all the various threads needed in an application (timers, event loops, etc.) *)
|
||||
|
||||
val run_async :
|
||||
?ls:Task_local_storage.storage ref -> Runner.t -> (unit -> unit) -> unit
|
||||
val run_async : ?ls:Task_local_storage.t -> Runner.t -> (unit -> unit) -> unit
|
||||
(** [run_async runner task] schedules the task to run
|
||||
on the given runner. This means [task()] will be executed
|
||||
at some point in the future, possibly in another thread.
|
||||
@since 0.5 *)
|
||||
|
||||
val run_wait_block :
|
||||
?ls:Task_local_storage.storage ref -> Runner.t -> (unit -> 'a) -> 'a
|
||||
val run_wait_block : ?ls:Task_local_storage.t -> Runner.t -> (unit -> 'a) -> 'a
|
||||
(** [run_wait_block runner f] schedules [f] for later execution
|
||||
on the runner, like {!run_async}.
|
||||
It then blocks the current thread until [f()] is done executing,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
open Types_
|
||||
module TLS = Thread_local_storage_
|
||||
|
||||
type task = unit -> unit
|
||||
|
||||
type t = {
|
||||
run_async: ls:Task_local_storage.storage ref -> task -> unit;
|
||||
type t = runner = {
|
||||
run_async: ls:local_storage -> task -> unit;
|
||||
shutdown: wait:bool -> unit -> unit;
|
||||
size: unit -> int;
|
||||
num_tasks: unit -> int;
|
||||
|
|
@ -11,9 +12,7 @@ type t = {
|
|||
|
||||
exception Shutdown
|
||||
|
||||
let[@inline] run_async
|
||||
?(ls = ref @@ Task_local_storage.Private_.Storage.create ()) (self : t) f :
|
||||
unit =
|
||||
let[@inline] run_async ?(ls = create_local_storage ()) (self : t) f : unit =
|
||||
self.run_async ~ls f
|
||||
|
||||
let[@inline] shutdown (self : t) : unit = self.shutdown ~wait:true ()
|
||||
|
|
@ -41,8 +40,8 @@ module For_runner_implementors = struct
|
|||
let create ~size ~num_tasks ~shutdown ~run_async () : t =
|
||||
{ size; num_tasks; shutdown; run_async }
|
||||
|
||||
let k_cur_runner : t option ref TLS.key = TLS.new_key (fun () -> ref None)
|
||||
let k_cur_runner : t option ref TLS.key = Types_.k_cur_runner
|
||||
end
|
||||
|
||||
let[@inline] get_current_runner () : _ option =
|
||||
!(TLS.get For_runner_implementors.k_cur_runner)
|
||||
let get_current_runner = get_current_runner
|
||||
let get_current_storage = get_current_storage
|
||||
|
|
|
|||
|
|
@ -33,15 +33,14 @@ val shutdown_without_waiting : t -> unit
|
|||
|
||||
exception Shutdown
|
||||
|
||||
val run_async : ?ls:Task_local_storage.storage ref -> t -> task -> unit
|
||||
val run_async : ?ls:Task_local_storage.t -> t -> task -> unit
|
||||
(** [run_async pool f] schedules [f] for later execution on the runner
|
||||
in one of the threads. [f()] will run on one of the runner's
|
||||
worker threads/domains.
|
||||
@param ls if provided, run the task with this initial local storage
|
||||
@raise Shutdown if the runner was shut down before [run_async] was called. *)
|
||||
|
||||
val run_wait_block :
|
||||
?ls:Task_local_storage.storage ref -> t -> (unit -> 'a) -> 'a
|
||||
val run_wait_block : ?ls:Task_local_storage.t -> t -> (unit -> 'a) -> 'a
|
||||
(** [run_wait_block pool f] schedules [f] for later execution
|
||||
on the pool, like {!run_async}.
|
||||
It then blocks the current thread until [f()] is done executing,
|
||||
|
|
@ -61,7 +60,7 @@ module For_runner_implementors : sig
|
|||
size:(unit -> int) ->
|
||||
num_tasks:(unit -> int) ->
|
||||
shutdown:(wait:bool -> unit -> unit) ->
|
||||
run_async:(ls:Task_local_storage.storage ref -> task -> unit) ->
|
||||
run_async:(ls:Task_local_storage.t -> task -> unit) ->
|
||||
unit ->
|
||||
t
|
||||
(** Create a new runner.
|
||||
|
|
@ -80,3 +79,7 @@ val get_current_runner : unit -> t option
|
|||
(** Access the current runner. This returns [Some r] if the call
|
||||
happens on a thread that belongs in a runner.
|
||||
@since 0.5 *)
|
||||
|
||||
val get_current_storage : unit -> Task_local_storage.t option
|
||||
(** [get_current_storage runner] gets the local storage
|
||||
for the currently running task. *)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,44 @@ type 'a key = 'a ls_key
|
|||
|
||||
let key_count_ = A.make 0
|
||||
|
||||
type storage = task_ls
|
||||
type t = local_storage
|
||||
type ls_value += Dummy
|
||||
|
||||
let dummy : t = ref [||]
|
||||
|
||||
(** Resize array of TLS values *)
|
||||
let[@inline never] resize_ (cur : ls_value array ref) n =
|
||||
if n > Sys.max_array_length then failwith "too many task local storage keys";
|
||||
let len = Array.length !cur in
|
||||
let new_ls =
|
||||
Array.make (min Sys.max_array_length (max n ((len * 2) + 2))) Dummy
|
||||
in
|
||||
Array.blit !cur 0 new_ls 0 len;
|
||||
cur := new_ls
|
||||
|
||||
module Direct = struct
|
||||
type nonrec t = t
|
||||
|
||||
let create = create_local_storage
|
||||
let[@inline] copy (self : t) = ref (Array.copy !self)
|
||||
|
||||
let get (type a) (self : t) ((module K) : a key) : a =
|
||||
if K.offset >= Array.length !self then resize_ self (K.offset + 1);
|
||||
match !self.(K.offset) with
|
||||
| K.V x -> (* common case first *) x
|
||||
| Dummy ->
|
||||
(* first time we access this *)
|
||||
let v = K.init () in
|
||||
!self.(K.offset) <- K.V v;
|
||||
v
|
||||
| _ -> assert false
|
||||
|
||||
let set (type a) (self : t) ((module K) : a key) (v : a) : unit =
|
||||
assert (self != dummy);
|
||||
if K.offset >= Array.length !self then resize_ self (K.offset + 1);
|
||||
!self.(K.offset) <- K.V v;
|
||||
()
|
||||
end
|
||||
|
||||
let new_key (type t) ~init () : t key =
|
||||
let offset = A.fetch_and_add key_count_ 1 in
|
||||
|
|
@ -18,68 +55,25 @@ let new_key (type t) ~init () : t key =
|
|||
end : LS_KEY
|
||||
with type t = t)
|
||||
|
||||
type ls_value += Dummy
|
||||
|
||||
(** Resize array of TLS values *)
|
||||
let[@inline never] resize_ (cur : ls_value array ref) n =
|
||||
if n > Sys.max_array_length then failwith "too many task local storage keys";
|
||||
let len = Array.length !cur in
|
||||
let new_ls =
|
||||
Array.make (min Sys.max_array_length (max n ((len * 2) + 2))) Dummy
|
||||
in
|
||||
Array.blit !cur 0 new_ls 0 len;
|
||||
cur := new_ls
|
||||
|
||||
let[@inline] get_cur_ () : ls_value array ref =
|
||||
match TLS.get k_ls_values with
|
||||
match get_current_storage () with
|
||||
| Some r -> r
|
||||
| None -> failwith "Task local storage must be accessed from within a runner."
|
||||
|
||||
let get_from_ (type a) cur ((module K) : a key) : a =
|
||||
if K.offset >= Array.length !cur then resize_ cur (K.offset + 1);
|
||||
match !cur.(K.offset) with
|
||||
| K.V x -> (* common case first *) x
|
||||
| Dummy ->
|
||||
(* first time we access this *)
|
||||
let v = K.init () in
|
||||
!cur.(K.offset) <- K.V v;
|
||||
v
|
||||
| _ -> assert false
|
||||
|
||||
let[@inline] get (key : 'a key) : 'a =
|
||||
let cur = get_cur_ () in
|
||||
get_from_ cur key
|
||||
Direct.get cur key
|
||||
|
||||
let[@inline] get_opt key =
|
||||
match TLS.get k_ls_values with
|
||||
match get_current_storage () with
|
||||
| None -> None
|
||||
| Some cur -> Some (get_from_ cur key)
|
||||
|
||||
let set_into_ (type a) cur ((module K) : a key) (v : a) : unit =
|
||||
if K.offset >= Array.length !cur then resize_ cur (K.offset + 1);
|
||||
!cur.(K.offset) <- K.V v;
|
||||
()
|
||||
| Some cur -> Some (Direct.get cur key)
|
||||
|
||||
let[@inline] set key v : unit =
|
||||
let cur = get_cur_ () in
|
||||
set_into_ cur key v
|
||||
Direct.set cur key v
|
||||
|
||||
let with_value key x f =
|
||||
let old = get key in
|
||||
set key x;
|
||||
Fun.protect ~finally:(fun () -> set key old) f
|
||||
|
||||
module Private_ = struct
|
||||
module Storage = struct
|
||||
type t = storage
|
||||
|
||||
let k_storage = k_ls_values
|
||||
let[@inline] create () = [||]
|
||||
let[@inline] get_cur_opt () = TLS.get k_storage
|
||||
let copy = Array.copy
|
||||
let get = get_from_
|
||||
let set = set_into_
|
||||
let[@inline] copy_of_current () = copy @@ !(get_cur_ ())
|
||||
let dummy = [||]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,8 +8,11 @@
|
|||
@since NEXT_RELEASE
|
||||
*)
|
||||
|
||||
type storage
|
||||
(** Underlying storage for a task *)
|
||||
type t = Types_.local_storage
|
||||
(** Underlying storage for a task. This is mutable and
|
||||
not thread-safe. *)
|
||||
|
||||
val dummy : t
|
||||
|
||||
type 'a key
|
||||
(** A key used to access a particular (typed) storage slot on every task. *)
|
||||
|
|
@ -49,22 +52,12 @@ val with_value : 'a key -> 'a -> (unit -> 'b) -> 'b
|
|||
to [f()]. When [f()] returns (or fails), [k] is restored
|
||||
to its old value. *)
|
||||
|
||||
(**/**)
|
||||
(** Direct access to values from a storage handle *)
|
||||
module Direct : sig
|
||||
val get : t -> 'a key -> 'a
|
||||
(** Access a key *)
|
||||
|
||||
(** Private API *)
|
||||
module Private_ : sig
|
||||
module Storage : sig
|
||||
type t = storage
|
||||
|
||||
val get : t ref -> 'a key -> 'a
|
||||
val set : t ref -> 'a key -> 'a -> unit
|
||||
val k_storage : t ref option Thread_local_storage_.key
|
||||
val get_cur_opt : unit -> t ref option
|
||||
val set : t -> 'a key -> 'a -> unit
|
||||
val create : unit -> t
|
||||
val copy : t -> t
|
||||
val copy_of_current : unit -> t
|
||||
val dummy : t
|
||||
end
|
||||
end
|
||||
|
||||
(**/**)
|
||||
|
|
|
|||
|
|
@ -16,11 +16,21 @@ end
|
|||
type 'a ls_key = (module LS_KEY with type t = 'a)
|
||||
(** A LS key (task local storage) *)
|
||||
|
||||
type task_ls = ls_value array
|
||||
type task = unit -> unit
|
||||
type local_storage = ls_value array ref
|
||||
|
||||
(** Store the current LS values for the current thread.
|
||||
type runner = {
|
||||
run_async: ls:local_storage -> task -> unit;
|
||||
shutdown: wait:bool -> unit -> unit;
|
||||
size: unit -> int;
|
||||
num_tasks: unit -> int;
|
||||
}
|
||||
|
||||
A worker thread is going to cycle through many tasks, each of which
|
||||
has its own storage. This key allows tasks running on the worker
|
||||
to access their own storage *)
|
||||
let k_ls_values : task_ls ref option TLS.key = TLS.new_key (fun () -> None)
|
||||
let k_cur_runner : runner option ref TLS.key = TLS.new_key (fun () -> ref None)
|
||||
|
||||
let k_cur_storage : local_storage option ref TLS.key =
|
||||
TLS.new_key (fun () -> ref None)
|
||||
|
||||
let[@inline] get_current_runner () : _ option = !(TLS.get k_cur_runner)
|
||||
let[@inline] get_current_storage () : _ option = !(TLS.get k_cur_storage)
|
||||
let[@inline] create_local_storage () = ref [||]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
open Types_
|
||||
module WSQ = Ws_deque_
|
||||
module A = Atomic_
|
||||
module TLS = Thread_local_storage_
|
||||
include Runner
|
||||
|
||||
let ( let@ ) = ( @@ )
|
||||
let k_storage = Task_local_storage.Private_.Storage.k_storage
|
||||
|
||||
module Id = struct
|
||||
type t = unit ref
|
||||
|
|
@ -18,11 +18,11 @@ type around_task = AT_pair : (t -> 'a) * (t -> 'a -> unit) -> around_task
|
|||
|
||||
type task_full =
|
||||
| T_start of {
|
||||
ls: Task_local_storage.storage ref;
|
||||
ls: Task_local_storage.t;
|
||||
f: task;
|
||||
}
|
||||
| T_resume : {
|
||||
ls: Task_local_storage.storage ref;
|
||||
ls: Task_local_storage.t;
|
||||
k: 'a -> unit;
|
||||
x: 'a;
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ type worker_state = {
|
|||
pool_id_: Id.t; (** Unique per pool *)
|
||||
mutable thread: Thread.t;
|
||||
q: task_full WSQ.t; (** Work stealing queue *)
|
||||
mutable cur_ls: Task_local_storage.storage ref option; (** Task storage *)
|
||||
mutable cur_ls: Task_local_storage.t option; (** Task storage *)
|
||||
rng: Random.State.t;
|
||||
}
|
||||
(** State for a given worker. Only this worker is
|
||||
|
|
@ -121,7 +121,7 @@ let run_task_now_ (self : state) ~runner ~(w : worker_state) (task : task_full)
|
|||
in
|
||||
|
||||
w.cur_ls <- Some ls;
|
||||
TLS.set k_storage (Some ls);
|
||||
TLS.get k_cur_storage := Some ls;
|
||||
let _ctx = before_task runner in
|
||||
|
||||
let[@inline] on_suspend () : _ ref =
|
||||
|
|
@ -136,7 +136,7 @@ let run_task_now_ (self : state) ~runner ~(w : worker_state) (task : task_full)
|
|||
| Some w when Id.equal w.pool_id_ self.id_ -> Some w
|
||||
| _ -> None
|
||||
in
|
||||
let ls' = ref @@ Task_local_storage.Private_.Storage.copy !ls in
|
||||
let ls' = Task_local_storage.Direct.copy ls in
|
||||
schedule_task_ self ~w @@ T_start { ls = ls'; f = task' }
|
||||
in
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ let run_task_now_ (self : state) ~runner ~(w : worker_state) (task : task_full)
|
|||
|
||||
after_task runner _ctx;
|
||||
w.cur_ls <- None;
|
||||
TLS.set k_storage None
|
||||
TLS.get k_cur_storage := None
|
||||
|
||||
let run_async_ (self : state) ~ls (f : task) : unit =
|
||||
let w = find_current_worker_ () in
|
||||
|
|
@ -289,7 +289,7 @@ type ('a, 'b) create_args =
|
|||
(** Arguments used in {!create}. See {!create} for explanations. *)
|
||||
|
||||
let dummy_task_ : task_full =
|
||||
T_start { f = ignore; ls = ref Task_local_storage.Private_.Storage.dummy }
|
||||
T_start { f = ignore; ls = Task_local_storage.dummy }
|
||||
|
||||
let create ?(on_init_thread = default_thread_init_exit_)
|
||||
?(on_exit_thread = default_thread_init_exit_) ?(on_exn = fun _ _ -> ())
|
||||
|
|
@ -358,7 +358,7 @@ let create ?(on_init_thread = default_thread_init_exit_)
|
|||
let thread = Thread.self () in
|
||||
let t_id = Thread.id thread in
|
||||
on_init_thread ~dom_id:dom_idx ~t_id ();
|
||||
TLS.set k_storage None;
|
||||
TLS.get k_cur_storage := None;
|
||||
|
||||
(* set thread name *)
|
||||
Option.iter
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ module Private_ = struct
|
|||
state: 'a state A.t; (** Current state in the lifetime of the fiber *)
|
||||
res: 'a Fut.t;
|
||||
runner: Runner.t;
|
||||
ls: Task_local_storage.storage ref;
|
||||
ls: Task_local_storage.t;
|
||||
}
|
||||
|
||||
and 'a state =
|
||||
|
|
@ -248,7 +248,7 @@ let spawn_ ~ls (Nursery n) (f : nursery -> 'a) : 'a t =
|
|||
|
||||
let spawn (Nursery n) ?(protect = true) f : _ t =
|
||||
(* spawn [f()] with a copy of our local storage *)
|
||||
let ls = ref (Task_local_storage.Private_.Storage.copy !(n.ls)) in
|
||||
let ls = Task_local_storage.Direct.copy n.ls in
|
||||
let child = spawn_ ~ls (Nursery n) f in
|
||||
add_child_ ~protect n child;
|
||||
child
|
||||
|
|
@ -259,6 +259,8 @@ let[@inline] spawn_ignore n ?protect f : unit =
|
|||
module Nursery = struct
|
||||
type t = nursery
|
||||
|
||||
let[@inline] runner (Nursery n) = n.runner
|
||||
|
||||
let[@inline] await (Nursery n) : unit =
|
||||
ignore (await n);
|
||||
()
|
||||
|
|
@ -266,17 +268,13 @@ module Nursery = struct
|
|||
let cancel_with (Nursery n) ebt : unit = resolve_as_failed_ n ebt
|
||||
|
||||
let with_create_top ~on () f =
|
||||
let n =
|
||||
create_
|
||||
~ls:(ref @@ Task_local_storage.Private_.Storage.create ())
|
||||
~runner:on ()
|
||||
in
|
||||
let n = create_ ~ls:(Task_local_storage.Direct.create ()) ~runner:on () in
|
||||
Fun.protect ~finally:(fun () -> resolve_ok_ n ()) (fun () -> f (Nursery n))
|
||||
|
||||
let with_create_sub ~protect (Nursery parent : t) f =
|
||||
let n =
|
||||
create_
|
||||
~ls:(ref @@ Task_local_storage.Private_.Storage.copy !(parent.ls))
|
||||
~ls:(Task_local_storage.Direct.copy parent.ls)
|
||||
~runner:parent.runner ()
|
||||
in
|
||||
add_child_ ~protect parent n;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ type cancel_callback = Exn_bt.t -> unit
|
|||
module Nursery : sig
|
||||
type t
|
||||
|
||||
val runner : t -> Runner.t
|
||||
(** Recover the runner this nursery uses to spawn fibers *)
|
||||
|
||||
val await : t -> unit
|
||||
(** Await for the nursery to exit. *)
|
||||
|
||||
|
|
@ -59,7 +62,7 @@ module Private_ : sig
|
|||
state: 'a state Atomic.t; (** Current state in the lifetime of the fiber *)
|
||||
res: 'a Fut.t;
|
||||
runner: Runner.t;
|
||||
ls: Task_local_storage.storage ref;
|
||||
ls: Task_local_storage.t;
|
||||
}
|
||||
(** Type definition, exposed so that {!any} can be unboxed.
|
||||
Please do not rely on that. *)
|
||||
|
|
|
|||
6
src/fib/moonpool_fib.ml
Normal file
6
src/fib/moonpool_fib.ml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
(** Fiber for moonpool *)
|
||||
|
||||
module Fiber = Fiber
|
||||
module Fls = Fls
|
||||
module Handle = Handle
|
||||
include Fiber
|
||||
Loading…
Add table
Reference in a new issue