xref: /plan9/sys/src/9/port/semaphore.p (revision 3c2ddefeebfd7a80eaebf272955335c2cf163bd5)
1*3c2ddefeSDavid du Colombier/*
2*3c2ddefeSDavid du Colombierspin -a semaphore.p
3*3c2ddefeSDavid du Colombierpcc -DSAFETY -DREACH -DMEMLIM'='500 -o pan pan.c
4*3c2ddefeSDavid du Colombierpan -i
5*3c2ddefeSDavid du Colombierrm pan.* pan
6*3c2ddefeSDavid du Colombier
7*3c2ddefeSDavid du Colombier*/
8*3c2ddefeSDavid du Colombier
9*3c2ddefeSDavid du Colombier#define N 3
10*3c2ddefeSDavid du Colombier
11*3c2ddefeSDavid du Colombierbit listlock;
12*3c2ddefeSDavid du Colombierbyte value;
13*3c2ddefeSDavid du Colombierbit onlist[N];
14*3c2ddefeSDavid du Colombierbit waiting[N];
15*3c2ddefeSDavid du Colombierbit sleeping[N];
16*3c2ddefeSDavid du Colombierbit acquired[N];
17*3c2ddefeSDavid du Colombier
18*3c2ddefeSDavid du Colombierinline lock(x)
19*3c2ddefeSDavid du Colombier{
20*3c2ddefeSDavid du Colombier	atomic { x == 0; x = 1 }
21*3c2ddefeSDavid du Colombier}
22*3c2ddefeSDavid du Colombier
23*3c2ddefeSDavid du Colombierinline unlock(x)
24*3c2ddefeSDavid du Colombier{
25*3c2ddefeSDavid du Colombier	assert x==1;
26*3c2ddefeSDavid du Colombier	x = 0
27*3c2ddefeSDavid du Colombier}
28*3c2ddefeSDavid du Colombier
29*3c2ddefeSDavid du Colombierinline sleep(cond)
30*3c2ddefeSDavid du Colombier{
31*3c2ddefeSDavid du Colombier	assert !sleeping[_pid];
32*3c2ddefeSDavid du Colombier	assert !interrupted;
33*3c2ddefeSDavid du Colombier	if
34*3c2ddefeSDavid du Colombier	:: cond
35*3c2ddefeSDavid du Colombier	:: atomic { else -> sleeping[_pid] = 1 } ->
36*3c2ddefeSDavid du Colombier		!sleeping[_pid]
37*3c2ddefeSDavid du Colombier	fi;
38*3c2ddefeSDavid du Colombier	if
39*3c2ddefeSDavid du Colombier	:: skip
40*3c2ddefeSDavid du Colombier	:: interrupted = 1
41*3c2ddefeSDavid du Colombier	fi
42*3c2ddefeSDavid du Colombier}
43*3c2ddefeSDavid du Colombier
44*3c2ddefeSDavid du Colombierinline wakeup(id)
45*3c2ddefeSDavid du Colombier{
46*3c2ddefeSDavid du Colombier	if
47*3c2ddefeSDavid du Colombier	:: sleeping[id] == 1 -> sleeping[id] = 0
48*3c2ddefeSDavid du Colombier	:: else
49*3c2ddefeSDavid du Colombier	fi
50*3c2ddefeSDavid du Colombier}
51*3c2ddefeSDavid du Colombier
52*3c2ddefeSDavid du Colombierinline semqueue()
53*3c2ddefeSDavid du Colombier{
54*3c2ddefeSDavid du Colombier	lock(listlock);
55*3c2ddefeSDavid du Colombier	assert !onlist[_pid];
56*3c2ddefeSDavid du Colombier	onlist[_pid] = 1;
57*3c2ddefeSDavid du Colombier	unlock(listlock)
58*3c2ddefeSDavid du Colombier}
59*3c2ddefeSDavid du Colombier
60*3c2ddefeSDavid du Colombierinline semdequeue()
61*3c2ddefeSDavid du Colombier{
62*3c2ddefeSDavid du Colombier	lock(listlock);
63*3c2ddefeSDavid du Colombier	assert onlist[_pid];
64*3c2ddefeSDavid du Colombier	onlist[_pid] = 0;
65*3c2ddefeSDavid du Colombier	waiting[_pid] = 0;
66*3c2ddefeSDavid du Colombier	unlock(listlock)
67*3c2ddefeSDavid du Colombier}
68*3c2ddefeSDavid du Colombier
69*3c2ddefeSDavid du Colombierinline semwakeup(n)
70*3c2ddefeSDavid du Colombier{
71*3c2ddefeSDavid du Colombier	byte i, j;
72*3c2ddefeSDavid du Colombier
73*3c2ddefeSDavid du Colombier	lock(listlock);
74*3c2ddefeSDavid du Colombier	i = 0;
75*3c2ddefeSDavid du Colombier	j = n;
76*3c2ddefeSDavid du Colombier	do
77*3c2ddefeSDavid du Colombier	:: (i < N && j > 0) ->
78*3c2ddefeSDavid du Colombier		if
79*3c2ddefeSDavid du Colombier		:: onlist[i] && waiting[i] ->
80*3c2ddefeSDavid du Colombier			atomic { printf("kicked %d\n", i);
81*3c2ddefeSDavid du Colombier			waiting[i] = 0 };
82*3c2ddefeSDavid du Colombier			wakeup(i);
83*3c2ddefeSDavid du Colombier			j--
84*3c2ddefeSDavid du Colombier		:: else
85*3c2ddefeSDavid du Colombier		fi;
86*3c2ddefeSDavid du Colombier		i++
87*3c2ddefeSDavid du Colombier	:: else -> break
88*3c2ddefeSDavid du Colombier	od;
89*3c2ddefeSDavid du Colombier	/* reset i and j to reduce state space */
90*3c2ddefeSDavid du Colombier	i = 0;
91*3c2ddefeSDavid du Colombier	j = 0;
92*3c2ddefeSDavid du Colombier	unlock(listlock)
93*3c2ddefeSDavid du Colombier}
94*3c2ddefeSDavid du Colombier
95*3c2ddefeSDavid du Colombierinline semrelease(n)
96*3c2ddefeSDavid du Colombier{
97*3c2ddefeSDavid du Colombier	atomic { value = value+n; printf("release %d\n", n); };
98*3c2ddefeSDavid du Colombier	semwakeup(n)
99*3c2ddefeSDavid du Colombier}
100*3c2ddefeSDavid du Colombier
101*3c2ddefeSDavid du Colombierinline canacquire()
102*3c2ddefeSDavid du Colombier{
103*3c2ddefeSDavid du Colombier	atomic { value > 0 -> value--; };
104*3c2ddefeSDavid du Colombier	acquired[_pid] = 1
105*3c2ddefeSDavid du Colombier}
106*3c2ddefeSDavid du Colombier
107*3c2ddefeSDavid du Colombier#define semawoke() !waiting[_pid]
108*3c2ddefeSDavid du Colombier
109*3c2ddefeSDavid du Colombierinline semacquire(block)
110*3c2ddefeSDavid du Colombier{
111*3c2ddefeSDavid du Colombier	if
112*3c2ddefeSDavid du Colombier	:: atomic { canacquire() -> printf("easy acquire\n"); } ->
113*3c2ddefeSDavid du Colombier		goto out
114*3c2ddefeSDavid du Colombier	:: else
115*3c2ddefeSDavid du Colombier	fi;
116*3c2ddefeSDavid du Colombier	if
117*3c2ddefeSDavid du Colombier	:: !block -> goto out
118*3c2ddefeSDavid du Colombier	:: else
119*3c2ddefeSDavid du Colombier	fi;
120*3c2ddefeSDavid du Colombier
121*3c2ddefeSDavid du Colombier	semqueue();
122*3c2ddefeSDavid du Colombier	do
123*3c2ddefeSDavid du Colombier	:: skip ->
124*3c2ddefeSDavid du Colombier		waiting[_pid] = 1;
125*3c2ddefeSDavid du Colombier		if
126*3c2ddefeSDavid du Colombier		:: atomic { canacquire() -> printf("hard acquire\n"); } ->
127*3c2ddefeSDavid du Colombier			break
128*3c2ddefeSDavid du Colombier		:: else
129*3c2ddefeSDavid du Colombier		fi;
130*3c2ddefeSDavid du Colombier		sleep(semawoke())
131*3c2ddefeSDavid du Colombier		if
132*3c2ddefeSDavid du Colombier		:: interrupted ->
133*3c2ddefeSDavid du Colombier			printf("%d interrupted\n", _pid);
134*3c2ddefeSDavid du Colombier			break
135*3c2ddefeSDavid du Colombier		:: !interrupted
136*3c2ddefeSDavid du Colombier		fi
137*3c2ddefeSDavid du Colombier	od;
138*3c2ddefeSDavid du Colombier	semdequeue();
139*3c2ddefeSDavid du Colombier	if
140*3c2ddefeSDavid du Colombier	:: !waiting[_pid] ->
141*3c2ddefeSDavid du Colombier		semwakeup(1)
142*3c2ddefeSDavid du Colombier	:: else
143*3c2ddefeSDavid du Colombier	fi;
144*3c2ddefeSDavid du Colombierout:
145*3c2ddefeSDavid du Colombier	assert (!block || interrupted || acquired[_pid]);
146*3c2ddefeSDavid du Colombier	assert !(interrupted && acquired[_pid]);
147*3c2ddefeSDavid du Colombier	assert !waiting[_pid];
148*3c2ddefeSDavid du Colombier	printf("%d done\n", _pid);
149*3c2ddefeSDavid du Colombier}
150*3c2ddefeSDavid du Colombier
151*3c2ddefeSDavid du Colombieractive[N] proctype acquire()
152*3c2ddefeSDavid du Colombier{
153*3c2ddefeSDavid du Colombier	bit interrupted;
154*3c2ddefeSDavid du Colombier
155*3c2ddefeSDavid du Colombier	semacquire(1);
156*3c2ddefeSDavid du Colombier	printf("%d finished\n", _pid);
157*3c2ddefeSDavid du Colombier	skip
158*3c2ddefeSDavid du Colombier}
159*3c2ddefeSDavid du Colombier
160*3c2ddefeSDavid du Colombieractive proctype release()
161*3c2ddefeSDavid du Colombier{
162*3c2ddefeSDavid du Colombier	byte k;
163*3c2ddefeSDavid du Colombier
164*3c2ddefeSDavid du Colombier	k = 0;
165*3c2ddefeSDavid du Colombier	do
166*3c2ddefeSDavid du Colombier	:: k < N ->
167*3c2ddefeSDavid du Colombier		semrelease(1);
168*3c2ddefeSDavid du Colombier		k++;
169*3c2ddefeSDavid du Colombier	:: else -> break
170*3c2ddefeSDavid du Colombier	od;
171*3c2ddefeSDavid du Colombier	skip
172*3c2ddefeSDavid du Colombier}
173*3c2ddefeSDavid du Colombier
174*3c2ddefeSDavid du Colombier/*
175*3c2ddefeSDavid du Colombier * If this guy, the highest-numbered proc, sticks
176*3c2ddefeSDavid du Colombier * around, then everyone else sticks around.
177*3c2ddefeSDavid du Colombier * This makes sure that we get a state line for
178*3c2ddefeSDavid du Colombier * everyone in a proc dump.
179*3c2ddefeSDavid du Colombier */
180*3c2ddefeSDavid du Colombieractive proctype dummy()
181*3c2ddefeSDavid du Colombier{
182*3c2ddefeSDavid du Colombierend:	0;
183*3c2ddefeSDavid du Colombier}
184