1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980openSTMmoduleMakeExt(Spec:SpecExt)=structopenUtilopenQCheckopenInternal.Make(Spec)[@alert"-internal"]exceptionThreadNotFinishedletarb_cmds_triple=arb_cmds_tripleletalloc_callback_src=Thread.yield();Noneletyield_tracker=Gc.Memprof.{null_trackerwithalloc_minor=alloc_callback;alloc_major=alloc_callback;}(* [interp_sut_res] specialized for [Threads] *)letrecinterp_sut_ressutcs=matchcswith|[]->[]|c::cs->Thread.yield();letres=Spec.runcsutin(c,res)::interp_sut_ressutcs(* Concurrent agreement property based on [Threads] *)letagree_prop_conc(seq_pref,cmds1,cmds2)=letsut=Spec.init_sut()inletobs1,obs2=ref(ErrorThreadNotFinished),ref(ErrorThreadNotFinished)in(* Gc.Memprof.{start,stop} raises Failure on OCaml 5.0 and 5.1 *)(tryignore(Gc.Memprof.start~sampling_rate:1e-1~callstack_size:0yield_tracker)withFailure_->());letpref_obs=Spec.wrap_cmd_seq@@fun()->interp_sut_ressutseq_prefinletwait=reftrueinletth1=Thread.create(fun()->Spec.wrap_cmd_seq@@fun()->while!waitdoThread.yield()done;obs1:=tryOk(interp_sut_ressutcmds1)withexn->Errorexn)()inletth2=Thread.create(fun()->Spec.wrap_cmd_seq@@fun()->wait:=false;obs2:=tryOk(interp_sut_ressutcmds2)withexn->Errorexn)()inThread.jointh1;Thread.jointh2;(tryGc.Memprof.stop()withFailure_->());Spec.cleanupsut;letobs1=match!obs1withOkv->v|Errorexn->raiseexninletobs2=match!obs2withOkv->v|Errorexn->raiseexnincheck_obspref_obsobs1obs2Spec.init_state||Test.fail_reportf" Results incompatible with linearized model\n\n%s"@@print_triple_vertical~fig_indent:5~res_width:35(fun(c,r)->Printf.sprintf"%s : %s"(Spec.show_cmdc)(show_resr))(pref_obs,obs1,obs2)(* Common magic constants *)letrep_count=3(* No. of repetitions of the non-deterministic property *)letretries=25(* Additional factor of repetition during shrinking *)letseq_len=20(* max length of the sequential prefix *)letpar_len=12(* max length of the parallel cmd lists *)letagree_test_conc~count~name=(* a bigger [rep_count] for [Threads] as it is more difficult to trigger a problem *)letmax_gen=3*countin(* precond filtering may require extra generation: max. 3*count though *)Test.make~retries~max_gen~count~name(arb_cmds_tripleseq_lenpar_len)(fun((seq_pref,cmds1,cmds2)astriple)->assume(all_interleavings_okseq_prefcmds1cmds2Spec.init_state);repeatrep_countagree_prop_conctriple)(* 100 times each, then 100 * 15 times when shrinking *)letneg_agree_test_conc~count~name=letmax_gen=3*countin(* precond filtering may require extra generation: max. 3*count though *)Test.make_neg~retries~max_gen~count~name(arb_cmds_tripleseq_lenpar_len)(fun((seq_pref,cmds1,cmds2)astriple)->assume(all_interleavings_okseq_prefcmds1cmds2Spec.init_state);repeatrep_countagree_prop_conctriple)(* 100 times each, then 100 * 15 times when shrinking *)endmoduleMake(Spec:Spec)=MakeExt(structincludeSpecDefaultsincludeSpecend)