Skip to content

Commit e993139

Browse files
committed
Introduce SpecExt to allow wrapping tests with handlers
1 parent 47b70fe commit e993139

8 files changed

+103
-13
lines changed

lib/STM.ml

+13
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,19 @@ sig
108108
Note: [s] is in this case the model's state prior to command execution. *)
109109
end
110110

111+
module type SpecExt =
112+
sig
113+
include Spec
114+
115+
val wrap : (unit -> 'a) -> 'a
116+
end
117+
118+
module SpecDefaults =
119+
struct
120+
let cleanup = ignore
121+
let precond _ _ = true
122+
let wrap th = th ()
123+
end
111124

112125
module Internal =
113126
struct

lib/STM.mli

+46-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ type res =
7575
val show_res : res -> string
7676

7777

78-
(** The specification of a state machine. *)
78+
(** The specification of a state machine.
79+
80+
See also {!SpecExt} and {!SpecDefaults}. *)
7981
module type Spec =
8082
sig
8183
type cmd
@@ -126,6 +128,49 @@ sig
126128
This is helpful to model, e.g., a [remove] [cmd] that returns the removed element. *)
127129
end
128130

131+
module type SpecExt =
132+
sig
133+
(** Extended specification of a state machine.
134+
135+
This signature may be extended in the future with new specifications that
136+
can be given defaults via {!SpecDefaults}. *)
137+
138+
include Spec
139+
140+
val wrap : (unit -> 'a) -> 'a
141+
(** [wrap thunk] must call [thunk ()] and return or raise whatever [thunk ()]
142+
returned or raised. [wrap] is useful, e.g., to handle effects performed
143+
by blocking primitives. *)
144+
end
145+
146+
module SpecDefaults :
147+
sig
148+
(** Default implementations for state machine specifications that can be given
149+
useful defaults.
150+
151+
The intention is that extended spec modules would [include] the defaults:
152+
153+
{[
154+
module MySpec = struct
155+
include SpecDefaults
156+
157+
(* ... *)
158+
end
159+
]}
160+
161+
This way the spec module can usually just continue working after new
162+
specifications have been added to {!SpecExt} with defaults in
163+
{!SpecDefaults}. *)
164+
165+
val cleanup : 'sut -> unit
166+
(** [cleanup sut] just return [()]. *)
167+
168+
val precond : 'cmd -> 'state -> bool
169+
(** [precond cmd state] just returns [true]. *)
170+
171+
val wrap : (unit -> 'a) -> 'a
172+
(** [wrap thunk] is equivalent to [thunk ()]. *)
173+
end
129174

130175
module Internal : sig
131176
open QCheck

lib/STM_domain.ml

+16-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
open STM
22

3-
module Make (Spec: Spec) = struct
3+
module MakeExt (Spec: SpecExt) = struct
44

55
open Util
66
open QCheck
@@ -24,9 +24,10 @@ module Make (Spec: Spec) = struct
2424

2525
let run_par seq_pref cmds1 cmds2 =
2626
let sut = Spec.init_sut () in
27-
let pref_obs = interp_sut_res sut seq_pref in
27+
let pref_obs = Spec.wrap @@ fun () -> interp_sut_res sut seq_pref in
2828
let barrier = Atomic.make 2 in
2929
let main cmds () =
30+
Spec.wrap @@ fun () ->
3031
Atomic.decr barrier;
3132
while Atomic.get barrier <> 0 do Domain.cpu_relax() done;
3233
try Ok (interp_sut_res sut cmds) with exn -> Error exn
@@ -54,17 +55,20 @@ module Make (Spec: Spec) = struct
5455

5556
let agree_prop_par_asym (seq_pref, cmds1, cmds2) =
5657
let sut = Spec.init_sut () in
57-
let pref_obs = interp_sut_res sut seq_pref in
58+
let pref_obs = Spec.wrap @@ fun () -> interp_sut_res sut seq_pref in
5859
let wait = Atomic.make 2 in
5960
let child_dom =
6061
Domain.spawn (fun () ->
62+
Spec.wrap @@ fun () ->
6163
Atomic.decr wait;
6264
while Atomic.get wait <> 0 do Domain.cpu_relax() done;
6365
try Ok (interp_sut_res sut cmds2) with exn -> Error exn)
6466
in
65-
Atomic.decr wait;
66-
while Atomic.get wait <> 0 do Domain.cpu_relax() done;
67-
let parent_obs = try Ok (interp_sut_res sut cmds1) with exn -> Error exn in
67+
let parent_obs =
68+
Spec.wrap @@ fun () ->
69+
Atomic.decr wait;
70+
while Atomic.get wait <> 0 do Domain.cpu_relax() done;
71+
try Ok (interp_sut_res sut cmds1) with exn -> Error exn in
6872
let child_obs = Domain.join child_dom in
6973
let () = Spec.cleanup sut in
7074
let parent_obs = match parent_obs with Ok v -> v | Error exn -> raise exn in
@@ -125,3 +129,9 @@ module Make (Spec: Spec) = struct
125129
assume (all_interleavings_ok triple);
126130
repeat rep_count agree_prop_par_asym triple) (* 25 times each, then 25 * 10 times when shrinking *)
127131
end
132+
133+
module Make (Spec: Spec) =
134+
MakeExt (struct
135+
include SpecDefaults
136+
include Spec
137+
end)

lib/STM_domain.mli

+3
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,6 @@ module Make : functor (Spec : STM.Spec) ->
9696
interleaving search like {!agree_test_par} and {!neg_agree_test_par}. *)
9797

9898
end
99+
100+
module MakeExt : functor (Spec : STM.SpecExt) ->
101+
module type of Make (Spec)

lib/STM_sequential.ml

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
open STM
22

3-
module Make (Spec: Spec) = struct
3+
module MakeExt (Spec: SpecExt) = struct
44

55
open QCheck
66
open Internal.Make(Spec)
@@ -18,7 +18,7 @@ module Make (Spec: Spec) = struct
1818
let agree_prop cs =
1919
assume (cmds_ok Spec.init_state cs);
2020
let sut = Spec.init_sut () in (* reset system's state *)
21-
let res = try Ok (check_disagree Spec.init_state sut cs) with exn -> Error exn in
21+
let res = try Ok (Spec.wrap @@ fun () -> check_disagree Spec.init_state sut cs) with exn -> Error exn in
2222
let () = Spec.cleanup sut in
2323
let res = match res with Ok res -> res | Error exn -> raise exn in
2424
match res with
@@ -34,3 +34,9 @@ module Make (Spec: Spec) = struct
3434
Test.make_neg ~name ~count (arb_cmds Spec.init_state) agree_prop
3535

3636
end
37+
38+
module Make (Spec : Spec) =
39+
MakeExt (struct
40+
include SpecDefaults
41+
include Spec
42+
end)

lib/STM_sequential.mli

+3
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ module Make : functor (Spec : STM.Spec) ->
2525
(** A negative agreement test (for convenience). Accepts two labeled parameters:
2626
[count] is the test count and [name] is the printed test name. *)
2727
end
28+
29+
module MakeExt : functor (Spec : STM.SpecExt) ->
30+
module type of Make (Spec)

lib/STM_thread.ml

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
open STM
22

3-
module Make (Spec: Spec) = struct
3+
module MakeExt (Spec: SpecExt) = struct
44

55
open Util
66
open QCheck
@@ -23,10 +23,10 @@ module Make (Spec: Spec) = struct
2323
let agree_prop_conc (seq_pref,cmds1,cmds2) =
2424
let sut = Spec.init_sut () in
2525
let obs1,obs2 = ref (Error ThreadNotFinished), ref (Error ThreadNotFinished) in
26-
let pref_obs = interp_sut_res sut seq_pref in
26+
let pref_obs = Spec.wrap @@ fun () -> interp_sut_res sut seq_pref in
2727
let wait = ref true in
28-
let th1 = Thread.create (fun () -> while !wait do Thread.yield () done; obs1 := try Ok (interp_sut_res sut cmds1) with exn -> Error exn) () in
29-
let th2 = Thread.create (fun () -> wait := false; obs2 := try Ok (interp_sut_res sut cmds2) with exn -> Error exn) () in
28+
let th1 = Thread.create (fun () -> Spec.wrap @@ fun () -> while !wait do Thread.yield () done; obs1 := try Ok (interp_sut_res sut cmds1) with exn -> Error exn) () in
29+
let th2 = Thread.create (fun () -> Spec.wrap @@ fun () -> wait := false; obs2 := try Ok (interp_sut_res sut cmds2) with exn -> Error exn) () in
3030
let () = Thread.join th1 in
3131
let () = Thread.join th2 in
3232
let () = Spec.cleanup sut in
@@ -59,3 +59,9 @@ module Make (Spec: Spec) = struct
5959
assume (all_interleavings_ok seq_pref cmds1 cmds2 Spec.init_state);
6060
repeat rep_count agree_prop_conc triple) (* 100 times each, then 100 * 15 times when shrinking *)
6161
end
62+
63+
module Make (Spec: Spec) =
64+
MakeExt (struct
65+
include SpecDefaults
66+
include Spec
67+
end)

lib/STM_thread.mli

+4
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,7 @@ module Make : functor (Spec : STM.Spec) ->
2727

2828
end
2929
[@@alert experimental "This module is experimental: It may fail to trigger concurrency issues that are present."]
30+
31+
module MakeExt : functor (Spec : STM.SpecExt) ->
32+
module type of Make (Spec) [@@alert "-experimental"]
33+
[@@alert experimental "This module is experimental: It may fail to trigger concurrency issues that are present."]

0 commit comments

Comments
 (0)