Skip to content

Commit b77aca2

Browse files
committed
lib: Fix V1.with_backtraces to return an empty backtrace
This makes it behave like the function in the V2 module Signed-off-by: Pau Ruiz Safont <pau.safont@vates.tech>
1 parent 6ca1cde commit b77aca2

2 files changed

Lines changed: 62 additions & 32 deletions

File tree

lib/backtrace.ml

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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

154192
let ( let@ ) f x = f x
155193

156194
let try_result f = try Ok (f ()) with exn -> Error exn
157195

158196
let 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

177211
module V1 = struct
@@ -195,24 +229,21 @@ end
195229

196230
let 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

217248
let reraise old newexn =
218249
add newexn (remove old);

test/reraise.t

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
$ ./raiser.exe -reraise
77
Backtrace lab failed with exception Failure("bar")
88
Raised Failure("bar")
9-
1/2 raiser.exe Raised at file lib/backtrace.ml, line 219
9+
1/2 raiser.exe Raised at file lib/backtrace.ml, line 250
1010
2/2 raiser.exe Called from file test/log.ml, line 55
1111

1212

1313
$ ./raiser.exe -v1-with-backtrace
1414
Backtrace lab failed with exception Failure("foo")
1515
Raised Failure("foo")
16-
1/1 raiser.exe Raised at file (Thread 0 has no backtrace table. Was with_backtraces called?, line 0
17-
16+
raiser.exe: Thread 0 has no backtrace table

0 commit comments

Comments
 (0)