/* m4 for loop definition define(`for',`ifelse($#,0,``$0'',`ifelse(eval($2<=$3),1, `pushdef(`$1',$2)$4`'popdef(`$1')$0(`$1',incr($2),$3,`$4')')')') */ int a[LENGTH]; // array to reverse int r_s[LENGTH]; // for SequentialReverser: where the reverse is stored int r_p[LENGTH]; // for ParallelReverser: where the reverse is stored // stores termination of each reverser // index 0 is for the sequential algorithm // indices 1-N are for the ThreadedReverser instances bool done[N + 1]; // initialized to false bool seq_eq_to_parallel = true; // ThreadedReverser implementation proctype ThreadedReverser(int from; int to; int n) { printf("proc[%d]: started from=%d to=%d\n", n, from, to); int k; for (k: from .. (to - 1)) { printf("r_p[%d] = a[%d]\n", LENGTH - k - 1, k); r_p[LENGTH - k - 1] = a[k]; } printf("proc[%d]: ended\n", n); done[n] = true; } // SequentialReverser implementation proctype SequentialReverser() { int k; for (k: 0 .. (LENGTH - 1)) { r_s[LENGTH - k - 1] = a[k]; printf("r_s[%d] = a[%d]\n", LENGTH - k - 1, k); } done[0] = true; // mark sequential end } // ParallelReverser implementation proctype ParallelReverser() { int n; int s = LENGTH / N; // fork section for (n: 0 .. (N - 1)) { int from = n * s; int to; if :: (n == N - 1) -> to = LENGTH; :: else -> to = n * s + s; fi run ThreadedReverser(from, to, n + 1); // run as "thread n" } // join section for (n: 1 .. N) { (done[n] == true); // wait "thread n" printf("[%d] joined\n", n); } } init { printf("program start\n"); // array initialization { int i; for (i in a) { int value; select(value: 0 .. R); a[i] = value; printf("a[%d]: %d\n", i, value); } } printf("sequential start\n"); run SequentialReverser(); printf("parallel start\n"); run ParallelReverser(); (done[0] == true && done[N] == true); // test if seq and parallel are the same { int i; for (i: 0 .. (LENGTH - 1)) { if :: (r_s[i] != r_p[i]) -> seq_eq_to_parallel = false; fi } } } // ltl syntax: https://spinroot.com/spin/Man/ltl.html ltl seq_eq_parallel { // the variable seq_eq_to_parallel will never be false if all the elements // between the sequential and parallel reversed arrays are equal [] (seq_eq_to_parallel == true) } ltl termination { // termination happens when the sequential reverser terminates // (done[0] is true) and the last process in the parallel reverser joins // (done[N] is true) <> (done[0] == true && done[N] == true) } // Due to avoid excessive parser complexity when checking the model // with other ltl properties the correctness_seq is excluded by m4 from the // ProMeLa source when there is no need to check it // ifelse(LTL, correctness_seq, ` ltl correctness_seq { [] (done[0] == true -> (true for(`k', 0, LENGTH-1, ` && r_s[eval(LENGTH - k - 1)] == a[k]'))) } // ', `') // Similar exclusion logic is applied to correctness_par // ifelse(LTL, correctness_par, ` ltl correctness_par { [] (done[2] == true -> (true for(`k', 0, LENGTH / N - 1, ` && r_p[eval(LENGTH - k - 1)] == a[k]'))) } // ', `')