-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsuzuki2.pml
255 lines (225 loc) · 5.1 KB
/
suzuki2.pml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#define N 2
#define L 2
#define _empty(_ch) (len(_ch) == 0)
#define _nempty(_ch) (len(_ch) != 0)
/* Request message type */
typedef REQUEST{
chan ch = [N] of {byte, short};
}
/* Used to create an array of arrays */
typedef Array{
short ind[N];
}
/* Queue datatype */
typedef Queue {
chan ch = [N] of {short};
bool inQ[N];
}
/* PRIVILEGE message type */
typedef PRIVILEGE {
chan ch = [N] of {Queue, Array};
}
/* Reply channel */
chan reply[N] = [N] of {bool};
Array RN[N]; /* "local" copies of RN and LN, have to be visible for both P1 and P2 */
Array LN[N];
bool havePrivilege[N]; /* True when ones own is set to true. Only someone with privilege alters this */
bool requesting[N]; /* True when a process is requesting */
byte replycount[N]; /* Reflects the number of reply messages received */
short counter; /* Used when checking for mutual exclusion */
Queue Q[N];
PRIVILEGE priv; /* The privilege channel, only the current privilege-holder may read this */
REQUEST req[N]; /* Request channels */
proctype P1(byte i){
byte c; /* Counter */
bool nreceived=0; /* This is set to one when N-1 reply messages have been received */
do
:: 1 ->
d_step{c=0; requesting[i] = true;}
atomic {
if
:: havePrivilege[i] -> skip;
:: else ->
/* Request the privilege */
RN[i].ind[i] = (RN[i].ind[i]+1) % L;
nreceived=0;
do
:: else -> break;
:: c == i -> c++; skip;
:: c < N && c != i ->
req[c].ch!i, RN[i].ind[i]; c++;
od;
/* Wait for privilege */
if
:: havePrivilege[i] ->
priv.ch?Q[i], LN[i];
fi;
fi;
}
progress:
d_step {
/* Read the queue if needed */
if
:: nempty(priv.ch) ->
priv.ch?Q[i], LN[i];
:: empty(priv.ch) ->
skip;
fi;
counter++; // debugging
LN[i].ind[i] = RN[i].ind[i];
}
atomic {
/* Wait if this is the L:th round, and replies have not allready been received */
if /* manipulate the below line to reproduce the found deadlock */
:: (RN[i].ind[i] == L-1) && !nreceived->
if
:: (replycount[i] == N-1) ->
replycount[i] = 0;
nreceived=1;
fi;
:: else -> skip;
fi;
crit: }
/* Add requesting processes to the queue */
d_step {
c=0;
do
:: else -> counter--;break;
:: c==i -> c++; skip;
:: c<N && c!=i ->
if
:: !Q[i].inQ[c] && RN[i].ind[c] == (LN[i].ind[c] + 1) % L->
Q[i].ch!c;
Q[i].inQ[c]=true;
:: else -> skip;
fi;
c++;
od;
/* If any process is requesting, send the privilege to that process */
if
:: nempty(Q[i].ch) ->
Q[i].ch?c;
Q[i].inQ[c]=false;
priv.ch!Q[i], LN[i];
havePrivilege[i] = false;
havePrivilege[c] = true;
:: empty(Q[i].ch) ->
skip;
fi;
requesting[i] = false;
}
od;
}
proctype P2(byte i){
chan rreq = req[i].ch;
xr rreq; /* P2 is the only process reading from this channel */
byte reqee, reqN; /* (node identifier, request identifier) */
byte requestcount[N];
do
/* This could be used to simulate processes being received out of order */
/* :: nempty(req[i].ch) ->
progressdummy:
d_step{
rreq?reqee,reqN;
req[i].ch!reqee,reqN;
}*/
:: nempty(req[i].ch) ->
d_step {
rreq?reqee,reqN;
requestcount[reqee]++;
/* If this is the Lth request, send a REPLY message*/
if
:: requestcount[reqee] == L ->
reply[reqee]!1;
requestcount[reqee] = 0;
:: else -> skip;
fi;
/* Chose the right value of RN */
if
:: requestcount[reqee] == 1 ->
RN[i].ind[reqee] = reqN;
:: else ->
if
:: RN[i].ind[reqee] < reqN ->
RN[i].ind[reqee] = reqN;
:: else ->
skip;
fi;
fi;
/* If P1 is not requesting and another process does, send privilege*/
if
:: havePrivilege[i] && !requesting[i] && RN[i].ind[reqee] == (LN[i].ind[reqee]+1) % L ->
priv.ch!Q[i], LN[i];
havePrivilege[i]=false;
havePrivilege[reqee]=true;
:: else ->
skip;
fi;
}
od;
}
proctype P3(short i){
replycount[i]=0;
bool trash;
chan rreply = reply[i];
xr rreply; /* P3 is the only process reading from this channel */
do
:: nempty(rreply) ->
d_step{
rreply?_; /* "read" the channel */
replycount[i]++;
}
od;
}
init {
byte i,j;
do
:: i<N ->
j=0;
do
:: j < N ->
RN[i].ind[j] = -1;
LN[i].ind[j] = -1;
j++;
:: else -> break;
od;
i++;
:: else -> break;
od;
i=0;
havePrivilege[0]=true;
atomic{
do
:: i < N ->
run P1(i); // unreliable processes
run P2(i);
run P3(i);
i++;
:: else -> break;
od;
i=0;
}
end:
}
#define hP0 havePrivilege[0]
#define hP1 havePrivilege[1]
#define hP2 havePrivilege[2]
#define r0 requesting[0]
#define r1 requesting[1]
#define r2 requesting[2]
/* Uncomment to check Mutual exclusion */
/*
ltl mutex {
[](counter < 2)
}
*/
/* Uncomment to check for deadlock freedom */
/*
ltl deadlock {
[]!timeout
}
*/
/* Uncomment to check for starvation freedom */
ltl starvation {
[](<>[]r1 -> []<>hP1 && <>[]r0 -> []<>hP0) // && <>[]r2 -> []<>hP2)
}