@@ -143,35 +143,69 @@ let remove t exn =
143143 bt :: acc
144144 ) [] |> remove_dups |> List. concat
145145
146- let per_thread_backtraces = Hashtbl. create 37
147- let per_thread_backtraces_m = Mutex. create ()
148146
149- let with_lock f =
150- let finally () = Mutex. unlock per_thread_backtraces_m in
151- Mutex. lock per_thread_backtraces_m;
152- Fun. protect ~finally f
147+ module IntMap = Map. Make (Int )
148+
149+ module ThreadLocalTable = struct
150+ (* The map values behave like stacks here, with shadowing as in Hashtbl.
151+ A Hashtbl is not used here, in order to avoid taking the lock in `find`. *)
152+ type 'a t = {mutable tbl : 'a list IntMap .t ; m : Mutex .t }
153+
154+ let make () =
155+ let tbl = IntMap. empty in
156+ let m = Mutex. create () in
157+ {tbl; m}
158+
159+ let add t v =
160+ let id = Thread. (id (self () )) in
161+ Mutex. execute t.m (fun () ->
162+ t.tbl < -
163+ IntMap. update id
164+ (function Some v' -> Some (v :: v') | None -> Some [v])
165+ t.tbl
166+ )
167+
168+ let remove t =
169+ let id = Thread. (id (self () )) in
170+ Mutex. execute t.m (fun () ->
171+ t.tbl < -
172+ IntMap. update id
173+ (function
174+ | Some [_] ->
175+ None
176+ | Some (_hd :: tl ) ->
177+ Some tl
178+ | Some [] | None ->
179+ None
180+ )
181+ t.tbl
182+ )
183+
184+ let find t =
185+ let id = Thread. (id (self () )) in
186+ IntMap. find_opt id t.tbl
187+ |> Option. fold ~none: None ~some: (function v :: _ -> Some v | [] -> None )
188+ end
189+
190+ let per_thread_backtraces = ThreadLocalTable. make ()
153191
154192let ( let@ ) f x = f x
155193
156194let try_result f = try Ok (f () ) with exn -> Error exn
157195
158196let with_backtraces_common f with_table =
159- let id = Thread. (id (self () )) in
160197 let tbl =
161- let @ () = with_lock in
162- let tbl =
163- match Hashtbl. find_opt per_thread_backtraces id with
198+ let tbl =
199+ match ThreadLocalTable. find per_thread_backtraces with
164200 | Some tbl -> tbl
165201 | None -> make ()
166202 in
167203 (* If we nest these functions we add multiple bindings
168204 to the same mutable table which is ok *)
169- Hashtbl . add per_thread_backtraces id tbl;
205+ ThreadLocalTable . add per_thread_backtraces tbl;
170206 tbl
171207 in
172- let finally () =
173- with_lock (fun () -> Hashtbl. remove per_thread_backtraces id)
174- in
208+ let finally () = ThreadLocalTable. remove per_thread_backtraces in
175209 Fun. protect ~finally (fun () -> with_table tbl (try_result f))
176210
177211module V1 = struct
@@ -195,24 +229,21 @@ end
195229
196230let with_backtraces = V1. with_backtraces
197231
198- let with_table f default =
199- let id = Thread. (id (self () )) in
200- match with_lock (fun () -> Hashtbl. find_opt per_thread_backtraces id) with
201- | None -> default ()
202- | Some tbl -> f tbl
203-
204- let is_important exn = with_table (fun tbl -> is_important tbl exn ) (fun () -> () )
205-
206- let add exn bt = with_table (fun tbl -> add tbl exn bt) (fun () -> () )
232+ let is_important exn =
233+ ThreadLocalTable. find per_thread_backtraces
234+ |> Option. iter (fun tbl -> is_important tbl exn )
207235
208- let warning () =
209- [ { process = ! my_name;
210- filename = Printf. sprintf " (Thread %d has no backtrace table. Was with_backtraces called?" Thread. (id (self () ));
211- line = 0 } ]
236+ let add exn bt =
237+ ThreadLocalTable. find per_thread_backtraces
238+ |> Option. iter (fun tbl -> add tbl exn bt)
212239
213- let remove exn = with_table (fun tbl -> remove tbl exn ) warning
240+ let remove exn =
241+ ThreadLocalTable. find per_thread_backtraces
242+ |> Option. fold ~some: (fun tbl -> remove tbl exn ) ~none: empty
214243
215- let get exn = with_table (fun tbl -> get tbl exn ) warning
244+ let get exn =
245+ ThreadLocalTable. find per_thread_backtraces
246+ |> Option. fold ~some: (fun tbl -> get tbl exn ) ~none: empty
216247
217248let reraise old newexn =
218249 add newexn (remove old);
0 commit comments