Skip to content

Commit 57d40d4

Browse files
authored
Merge pull request #574 from ocaml/thread-safety
Thread safety
2 parents 6b93ff5 + 070c9a8 commit 57d40d4

File tree

13 files changed

+389
-79
lines changed

13 files changed

+389
-79
lines changed

.github/workflows/main.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,16 @@ jobs:
1414
ocaml-compiler:
1515
- "4.14"
1616
- "5.2"
17+
include:
18+
- os: ubuntu-24.04-arm
19+
ocaml-compiler: "ocaml-variants.5.2.1+options,ocaml-option-tsan"
1720
runs-on: ${{ matrix.os }}
1821
steps:
1922
- uses: actions/checkout@v4
23+
- run: |
24+
sudo apt update
25+
sudo apt install libunwind-dev
26+
if: ${{ matrix.os == 'ubuntu-24.04-arm' }}
2027
- uses: ocaml/setup-ocaml@v3
2128
with:
2229
ocaml-compiler: ${{ matrix.ocaml-compiler }}

lib/automata.ml

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,8 @@ module State = struct
597597
; mutable status : Status.t option
598598
; hash : int
599599
}
600+
(* Thread-safety: We use double-checked locking to access field
601+
[status] in function [status] below. *)
600602

601603
let pp fmt t = Desc.pp fmt t.desc
602604
let[@inline] idx t = t.idx
@@ -629,7 +631,8 @@ module State = struct
629631
&& Desc.equal desc t.desc
630632
;;
631633

632-
let status s =
634+
(* To be called when the mutex has already been acquired *)
635+
let status_no_mutex s =
633636
match s.status with
634637
| Some s -> s
635638
| None ->
@@ -638,6 +641,16 @@ module State = struct
638641
st
639642
;;
640643

644+
let status m s =
645+
match s.status with
646+
| Some s -> s
647+
| None ->
648+
Mutex.lock m;
649+
let st = status_no_mutex s in
650+
Mutex.unlock m;
651+
st
652+
;;
653+
641654
module Table = Hashtbl.Make (struct
642655
type nonrec t = t
643656

@@ -652,10 +665,17 @@ module Working_area = struct
652665
type t =
653666
{ mutable ids : Bit_vector.t
654667
; seen : Id.Hash_set.t
668+
; index_count : int Atomic.t
669+
}
670+
671+
let create () =
672+
{ ids = Bit_vector.create_zero 1
673+
; seen = Id.Hash_set.create ()
674+
; index_count = Atomic.make 0
655675
}
676+
;;
656677

657-
let create () = { ids = Bit_vector.create_zero 1; seen = Id.Hash_set.create () }
658-
let index_count w = Bit_vector.length w.ids
678+
let index_count w = Atomic.get w.index_count
659679

660680
let mark_used_indices tbl =
661681
Desc.iter_marks ~f:(fun marks ->
@@ -672,7 +692,13 @@ module Working_area = struct
672692
mark_used_indices t.ids l;
673693
let len = Bit_vector.length t.ids in
674694
let idx = find_free t.ids 0 len in
675-
if idx = len then t.ids <- Bit_vector.create_zero (2 * len);
695+
if idx = len
696+
then (
697+
t.ids <- Bit_vector.create_zero (2 * len);
698+
(* This function is only called when the mutex is locked. So we
699+
are sure that this is always coherent with the length of
700+
[t.ids]. *)
701+
Atomic.set t.index_count (2 * len));
676702
Idx.make idx
677703
;;
678704
end

lib/automata.mli

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ module State : sig
102102
val dummy : t
103103
val create : Category.t -> expr -> t
104104
val idx : t -> Idx.t
105-
val status : t -> Status.t
105+
val status_no_mutex : t -> Status.t
106+
val status : Mutex.t -> t -> Status.t
106107
val to_dyn : t -> Dyn.t
107108

108109
module Table : Hashtbl.S with type key = t

0 commit comments

Comments
 (0)