xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/buf.prom (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier#define NBUFS 2
2*219b2ee8SDavid du Colombier#define READMAX 2
3*219b2ee8SDavid du Colombier#define BUFSIZ 2*READMAX
4*219b2ee8SDavid du Colombier#define EOF 255
5*219b2ee8SDavid du Colombier#define TIMEOUT 254
6*219b2ee8SDavid du Colombier#define FILEMAXLEN 20
7*219b2ee8SDavid du Colombier
8*219b2ee8SDavid du Colombierbyte	n[NBUFS];
9*219b2ee8SDavid du Colombierbyte ntotal[NBUFS];
10*219b2ee8SDavid du Colombierbyte putnext[NBUFS];
11*219b2ee8SDavid du Colombierbyte getnext[NBUFS];
12*219b2ee8SDavid du Colombierbool eof[NBUFS];
13*219b2ee8SDavid du Colombierbool roomwait[NBUFS];
14*219b2ee8SDavid du Colombierbool datawait[NBUFS];
15*219b2ee8SDavid du Colombierbyte rwant;
16*219b2ee8SDavid du Colombier
17*219b2ee8SDavid du Colombier/* use one big data array to simulate 2-d array */
18*219b2ee8SDavid du Colombier#define bufstart(slot) (slot*BUFSIZ)
19*219b2ee8SDavid du Colombier#define bufend(slot) ((slot+1)*BUFSIZ)
20*219b2ee8SDavid du Colombier/* bit data[BUFSIZ*NBUFS]; */
21*219b2ee8SDavid du Colombier
22*219b2ee8SDavid du Colombierbool selwait;
23*219b2ee8SDavid du Colombier/* bool hastimeout; */
24*219b2ee8SDavid du Colombier
25*219b2ee8SDavid du Colombier#define get 0
26*219b2ee8SDavid du Colombier#define release 1
27*219b2ee8SDavid du Colombier
28*219b2ee8SDavid du Colombierchan lock = [0] of { bit };
29*219b2ee8SDavid du Colombierchan lockkill = [0] of { bit };
30*219b2ee8SDavid du Colombierchan sel = [0] of { byte };
31*219b2ee8SDavid du Colombierchan selcall = [0] of { byte };
32*219b2ee8SDavid du Colombierchan selans = [0] of { byte, byte };
33*219b2ee8SDavid du Colombierchan selkill = [0] of { bit };
34*219b2ee8SDavid du Colombierchan readcall = [0] of { byte, byte };
35*219b2ee8SDavid du Colombierchan readans = [0] of { byte };
36*219b2ee8SDavid du Colombierchan readkill = [0] of { bit };
37*219b2ee8SDavid du Colombierchan croom[NBUFS] = [0] of { bit };
38*219b2ee8SDavid du Colombierchan cdata[NBUFS] = [0] of { bit };
39*219b2ee8SDavid du Colombier
40*219b2ee8SDavid du Colombierproctype Lockrendez()
41*219b2ee8SDavid du Colombier{
42*219b2ee8SDavid du Colombier	do
43*219b2ee8SDavid du Colombier	:: lock!get -> lock?release
44*219b2ee8SDavid du Colombier	:: lockkill?release -> break
45*219b2ee8SDavid du Colombier	od
46*219b2ee8SDavid du Colombier}
47*219b2ee8SDavid du Colombier
48*219b2ee8SDavid du Colombierproctype Copy(byte fd)
49*219b2ee8SDavid du Colombier{
50*219b2ee8SDavid du Colombier	byte num;
51*219b2ee8SDavid du Colombier	bit b;
52*219b2ee8SDavid du Colombier
53*219b2ee8SDavid du Colombier	do  :: 1 ->
54*219b2ee8SDavid du Colombier		/* make sure there's room */
55*219b2ee8SDavid du Colombier		lock?get;
56*219b2ee8SDavid du Colombier		if
57*219b2ee8SDavid du Colombier		:: (BUFSIZ-putnext[fd]) < READMAX ->
58*219b2ee8SDavid du Colombier			if
59*219b2ee8SDavid du Colombier			:: getnext[fd] == putnext[fd] ->
60*219b2ee8SDavid du Colombier				getnext[fd] = 0;
61*219b2ee8SDavid du Colombier				putnext[fd] = 0;
62*219b2ee8SDavid du Colombier				lock!release
63*219b2ee8SDavid du Colombier			:: getnext[fd] != putnext[fd] ->
64*219b2ee8SDavid du Colombier				roomwait[fd] = 1;
65*219b2ee8SDavid du Colombier				lock!release;
66*219b2ee8SDavid du Colombier				croom[fd]?b
67*219b2ee8SDavid du Colombier			fi
68*219b2ee8SDavid du Colombier		:: (BUFSIZ-putnext[fd]) >= READMAX ->
69*219b2ee8SDavid du Colombier			lock!release
70*219b2ee8SDavid du Colombier		fi;
71*219b2ee8SDavid du Colombier		/* simulate read into data buf at putnext */
72*219b2ee8SDavid du Colombier		if
73*219b2ee8SDavid du Colombier		:: ntotal[fd] > FILEMAXLEN ->
74*219b2ee8SDavid du Colombier			num = EOF
75*219b2ee8SDavid du Colombier		:: ntotal[fd] <= FILEMAXLEN ->
76*219b2ee8SDavid du Colombier			if
77*219b2ee8SDavid du Colombier			:: num = 1
78*219b2ee8SDavid du Colombier			:: num = READMAX
79*219b2ee8SDavid du Colombier			:: num = EOF
80*219b2ee8SDavid du Colombier			fi
81*219b2ee8SDavid du Colombier		fi;
82*219b2ee8SDavid du Colombier		/* here is where data transfer would happen */
83*219b2ee8SDavid du Colombier		lock?get;
84*219b2ee8SDavid du Colombier		if
85*219b2ee8SDavid du Colombier		:: num == EOF ->
86*219b2ee8SDavid du Colombier			eof[fd] = 1;
87*219b2ee8SDavid du Colombier/* printf("Copy %d got eof\n", fd);/**/
88*219b2ee8SDavid du Colombier			if
89*219b2ee8SDavid du Colombier			:: datawait[fd] ->
90*219b2ee8SDavid du Colombier				datawait[fd] = 0;
91*219b2ee8SDavid du Colombier				lock!release;
92*219b2ee8SDavid du Colombier				cdata[fd]!1
93*219b2ee8SDavid du Colombier			:: !datawait[fd] && (rwant & (1<<fd)) && selwait ->
94*219b2ee8SDavid du Colombier				selwait = 0;
95*219b2ee8SDavid du Colombier				lock!release;
96*219b2ee8SDavid du Colombier				sel!fd
97*219b2ee8SDavid du Colombier			:: !datawait[fd] && !((rwant & (1<<fd)) && selwait) ->
98*219b2ee8SDavid du Colombier				lock!release
99*219b2ee8SDavid du Colombier			fi;
100*219b2ee8SDavid du Colombier			break
101*219b2ee8SDavid du Colombier		:: num != EOF ->
102*219b2ee8SDavid du Colombier/* printf("Copy %d putting %d in; old putnext=%d, old n=%d\n", fd, num, putnext[fd], n[fd]); /* */
103*219b2ee8SDavid du Colombier			putnext[fd] = putnext[fd] + num;
104*219b2ee8SDavid du Colombier			n[fd] = n[fd] + num;
105*219b2ee8SDavid du Colombier			ntotal[fd] = ntotal[fd] + num;
106*219b2ee8SDavid du Colombier			assert(n[fd] > 0);
107*219b2ee8SDavid du Colombier			if
108*219b2ee8SDavid du Colombier			:: datawait[fd] ->
109*219b2ee8SDavid du Colombier				datawait[fd] = 0;
110*219b2ee8SDavid du Colombier				lock!release;
111*219b2ee8SDavid du Colombier				cdata[fd]!1
112*219b2ee8SDavid du Colombier			:: !datawait[fd] && (rwant & (1<<fd)) && selwait ->
113*219b2ee8SDavid du Colombier				selwait = 0;
114*219b2ee8SDavid du Colombier				lock!release;
115*219b2ee8SDavid du Colombier				sel!fd
116*219b2ee8SDavid du Colombier			:: !datawait[fd] && !((rwant & (1<<fd)) && selwait) ->
117*219b2ee8SDavid du Colombier				lock!release
118*219b2ee8SDavid du Colombier			fi
119*219b2ee8SDavid du Colombier		fi;
120*219b2ee8SDavid du Colombier	od
121*219b2ee8SDavid du Colombier}
122*219b2ee8SDavid du Colombier
123*219b2ee8SDavid du Colombierproctype Read()
124*219b2ee8SDavid du Colombier{
125*219b2ee8SDavid du Colombier	byte ngot;
126*219b2ee8SDavid du Colombier	byte fd;
127*219b2ee8SDavid du Colombier	byte nwant;
128*219b2ee8SDavid du Colombier	bit b;
129*219b2ee8SDavid du Colombier
130*219b2ee8SDavid du Colombier    do
131*219b2ee8SDavid du Colombier    :: readcall?fd,nwant ->
132*219b2ee8SDavid du Colombier	if
133*219b2ee8SDavid du Colombier	:: eof[fd] && n[fd] == 0 ->
134*219b2ee8SDavid du Colombier		readans!EOF
135*219b2ee8SDavid du Colombier	:: !(eof[fd] && n[fd] == 0) ->
136*219b2ee8SDavid du Colombier		lock?get;
137*219b2ee8SDavid du Colombier		ngot = putnext[fd] - getnext[fd];
138*219b2ee8SDavid du Colombier/* printf("Reading %d, want %d: ngot = %d - %d, n = %d\n", fd, nwant, putnext[fd], getnext[fd], n[fd]); /* */
139*219b2ee8SDavid du Colombier		if
140*219b2ee8SDavid du Colombier		:: ngot == 0 ->
141*219b2ee8SDavid du Colombier			if
142*219b2ee8SDavid du Colombier			:: eof[fd] ->
143*219b2ee8SDavid du Colombier				skip
144*219b2ee8SDavid du Colombier			:: !eof[fd] ->
145*219b2ee8SDavid du Colombier				/* sleep until there's data */
146*219b2ee8SDavid du Colombier				datawait[fd] = 1;
147*219b2ee8SDavid du Colombier/* printf("Read sleeping\n"); /* */
148*219b2ee8SDavid du Colombier				lock!release;
149*219b2ee8SDavid du Colombier				cdata[fd]?b;
150*219b2ee8SDavid du Colombier				lock?get;
151*219b2ee8SDavid du Colombier				ngot = putnext[fd] - getnext[fd];
152*219b2ee8SDavid du Colombier/* printf("Read awoke, ngot = %d\n", ngot); /**/
153*219b2ee8SDavid du Colombier			fi
154*219b2ee8SDavid du Colombier		:: ngot != 0 -> skip
155*219b2ee8SDavid du Colombier		fi;
156*219b2ee8SDavid du Colombier		if
157*219b2ee8SDavid du Colombier		:: ngot > nwant -> ngot = nwant
158*219b2ee8SDavid du Colombier		:: ngot <= nwant -> skip
159*219b2ee8SDavid du Colombier		fi;
160*219b2ee8SDavid du Colombier		/* here would take ngot elements from data, from getnext[fd] ... */
161*219b2ee8SDavid du Colombier		getnext[fd] = getnext[fd] + ngot;
162*219b2ee8SDavid du Colombier		assert(n[fd] >= ngot);
163*219b2ee8SDavid du Colombier		n[fd] = n[fd] - ngot;
164*219b2ee8SDavid du Colombier		if
165*219b2ee8SDavid du Colombier		:: ngot == 0 ->
166*219b2ee8SDavid du Colombier			assert(eof[fd]);
167*219b2ee8SDavid du Colombier			ngot = EOF
168*219b2ee8SDavid du Colombier		:: ngot != 0 -> skip
169*219b2ee8SDavid du Colombier		fi;
170*219b2ee8SDavid du Colombier		if
171*219b2ee8SDavid du Colombier		:: getnext[fd] == putnext[fd] && roomwait[fd] ->
172*219b2ee8SDavid du Colombier			getnext[fd] = 0;
173*219b2ee8SDavid du Colombier			putnext[fd] = 0;
174*219b2ee8SDavid du Colombier			roomwait[fd] = 0;
175*219b2ee8SDavid du Colombier			lock!release;
176*219b2ee8SDavid du Colombier			croom[fd]!0
177*219b2ee8SDavid du Colombier		:: getnext[fd] != putnext[fd] || !roomwait[fd] ->
178*219b2ee8SDavid du Colombier			lock!release
179*219b2ee8SDavid du Colombier		fi;
180*219b2ee8SDavid du Colombier		readans!ngot
181*219b2ee8SDavid du Colombier	fi
182*219b2ee8SDavid du Colombier    :: readkill?b -> break
183*219b2ee8SDavid du Colombier    od
184*219b2ee8SDavid du Colombier}
185*219b2ee8SDavid du Colombier
186*219b2ee8SDavid du Colombierproctype Select()
187*219b2ee8SDavid du Colombier{
188*219b2ee8SDavid du Colombier	byte num;
189*219b2ee8SDavid du Colombier	byte i;
190*219b2ee8SDavid du Colombier	byte fd;
191*219b2ee8SDavid du Colombier	byte r;
192*219b2ee8SDavid du Colombier	bit b;
193*219b2ee8SDavid du Colombier
194*219b2ee8SDavid du Colombier    do
195*219b2ee8SDavid du Colombier    :: selcall?r ->
196*219b2ee8SDavid du Colombier/* printf("Select called, r=%d\n", r); /**/
197*219b2ee8SDavid du Colombier	i = 0;
198*219b2ee8SDavid du Colombier	do
199*219b2ee8SDavid du Colombier	:: i < NBUFS ->
200*219b2ee8SDavid du Colombier		if
201*219b2ee8SDavid du Colombier		:: r & (1<<i) ->
202*219b2ee8SDavid du Colombier			if
203*219b2ee8SDavid du Colombier			:: eof[i] && n[i] == 0 ->
204*219b2ee8SDavid du Colombier/* printf("Select got eof on %d\n", i);/**/
205*219b2ee8SDavid du Colombier				num = EOF;
206*219b2ee8SDavid du Colombier				r = i;
207*219b2ee8SDavid du Colombier				goto donesel
208*219b2ee8SDavid du Colombier			:: !eof[i] || n[i] != 0 -> skip
209*219b2ee8SDavid du Colombier			fi
210*219b2ee8SDavid du Colombier		:: !(r & (1<<i)) -> skip
211*219b2ee8SDavid du Colombier		fi;
212*219b2ee8SDavid du Colombier		i = i+1
213*219b2ee8SDavid du Colombier	:: i >= NBUFS -> break
214*219b2ee8SDavid du Colombier	od;
215*219b2ee8SDavid du Colombier	num = 0;
216*219b2ee8SDavid du Colombier	lock?get;
217*219b2ee8SDavid du Colombier	rwant = 0;
218*219b2ee8SDavid du Colombier	i = 0;
219*219b2ee8SDavid du Colombier	do
220*219b2ee8SDavid du Colombier	:: i < NBUFS ->
221*219b2ee8SDavid du Colombier		if
222*219b2ee8SDavid du Colombier		:: r & (1<<i) ->
223*219b2ee8SDavid du Colombier			if
224*219b2ee8SDavid du Colombier			:: n[i] > 0 || eof[i] ->
225*219b2ee8SDavid du Colombier/* printf("Select found %d has n==%d\n", i, n[i]); /**/
226*219b2ee8SDavid du Colombier				num = num+1
227*219b2ee8SDavid du Colombier			:: n[i] == 0 && !eof[i] ->
228*219b2ee8SDavid du Colombier/* printf("Select asks to wait for %d\n", i); /**/
229*219b2ee8SDavid du Colombier				r = r &(~(1<<i));
230*219b2ee8SDavid du Colombier				rwant = rwant | (1<<i)
231*219b2ee8SDavid du Colombier			fi
232*219b2ee8SDavid du Colombier		:: !(r & (1<<i)) -> skip
233*219b2ee8SDavid du Colombier		fi;
234*219b2ee8SDavid du Colombier		i = i+1
235*219b2ee8SDavid du Colombier	:: i >= NBUFS -> break
236*219b2ee8SDavid du Colombier	od;
237*219b2ee8SDavid du Colombier	if
238*219b2ee8SDavid du Colombier	:: num > 0 || rwant == 0 ->
239*219b2ee8SDavid du Colombier		rwant = 0;
240*219b2ee8SDavid du Colombier		lock!release;
241*219b2ee8SDavid du Colombier	:: num == 0 && rwant != 0 ->
242*219b2ee8SDavid du Colombier		selwait = 1;
243*219b2ee8SDavid du Colombier		lock!release;
244*219b2ee8SDavid du Colombier/* printf("Select sleeps\n"); /**/
245*219b2ee8SDavid du Colombier		sel?fd;
246*219b2ee8SDavid du Colombier/* printf("Select wakes up, fd=%d\n", fd); /**/
247*219b2ee8SDavid du Colombier		if
248*219b2ee8SDavid du Colombier		:: fd != TIMEOUT ->
249*219b2ee8SDavid du Colombier			if
250*219b2ee8SDavid du Colombier			:: (rwant & (1<<fd)) && (n[fd] > 0) ->
251*219b2ee8SDavid du Colombier				r = r | (1<<fd);
252*219b2ee8SDavid du Colombier				num = 1
253*219b2ee8SDavid du Colombier			:: !(rwant & (1<<fd)) || (n[fd] == 0) ->
254*219b2ee8SDavid du Colombier				num = 0
255*219b2ee8SDavid du Colombier			fi
256*219b2ee8SDavid du Colombier		:: fd == TIMEOUT -> skip
257*219b2ee8SDavid du Colombier		fi;
258*219b2ee8SDavid du Colombier		rwant = 0
259*219b2ee8SDavid du Colombier	fi;
260*219b2ee8SDavid du Colombier  donesel:
261*219b2ee8SDavid du Colombier	selans!num,r
262*219b2ee8SDavid du Colombier    :: selkill?b -> break
263*219b2ee8SDavid du Colombier    od
264*219b2ee8SDavid du Colombier}
265*219b2ee8SDavid du Colombier
266*219b2ee8SDavid du Colombier/* This routine is written knowing NBUFS == 2 in several places */
267*219b2ee8SDavid du Colombierproctype User()
268*219b2ee8SDavid du Colombier{
269*219b2ee8SDavid du Colombier	byte ndone;
270*219b2ee8SDavid du Colombier	byte i;
271*219b2ee8SDavid du Colombier	byte rw;
272*219b2ee8SDavid du Colombier	byte num;
273*219b2ee8SDavid du Colombier	byte nwant;
274*219b2ee8SDavid du Colombier	byte fd;
275*219b2ee8SDavid du Colombier	bool goteof[NBUFS];
276*219b2ee8SDavid du Colombier
277*219b2ee8SDavid du Colombier	ndone = 0;
278*219b2ee8SDavid du Colombier	do
279*219b2ee8SDavid du Colombier	:: ndone == NBUFS -> break
280*219b2ee8SDavid du Colombier	:: ndone < NBUFS ->
281*219b2ee8SDavid du Colombier		if
282*219b2ee8SDavid du Colombier		:: 1->
283*219b2ee8SDavid du Colombier			/* maybe use Read */
284*219b2ee8SDavid du Colombier/* printf("User trying to read.  Current goteofs: %d %d\n", goteof[0], goteof[1]); /**/
285*219b2ee8SDavid du Colombier			/* randomly pick fd 0 or 1 from non-eof ones */
286*219b2ee8SDavid du Colombier			if
287*219b2ee8SDavid du Colombier			:: !goteof[0] -> fd = 0
288*219b2ee8SDavid du Colombier			:: !goteof[1] -> fd = 1
289*219b2ee8SDavid du Colombier			fi;
290*219b2ee8SDavid du Colombier			if
291*219b2ee8SDavid du Colombier			:: nwant = 1
292*219b2ee8SDavid du Colombier			:: nwant = READMAX
293*219b2ee8SDavid du Colombier			fi;
294*219b2ee8SDavid du Colombier			readcall!fd,nwant;
295*219b2ee8SDavid du Colombier			readans?num;
296*219b2ee8SDavid du Colombier			if
297*219b2ee8SDavid du Colombier			:: num == EOF ->
298*219b2ee8SDavid du Colombier				goteof[fd] = 1;
299*219b2ee8SDavid du Colombier				ndone = ndone + 1
300*219b2ee8SDavid du Colombier			:: num != EOF -> assert(num != 0)
301*219b2ee8SDavid du Colombier			fi
302*219b2ee8SDavid du Colombier		:: 1->
303*219b2ee8SDavid du Colombier/* printf("User trying to select.  Current goteofs: %d %d\n", goteof[0], goteof[1]); /**/
304*219b2ee8SDavid du Colombier			/* maybe use Select, then Read */
305*219b2ee8SDavid du Colombier			/* randomly set the "i want" bit for non-eof fds */
306*219b2ee8SDavid du Colombier			if
307*219b2ee8SDavid du Colombier			:: !goteof[0] && !goteof[1] -> rw = (1<<0) | (1<<1)
308*219b2ee8SDavid du Colombier			:: !goteof[0] -> rw = (1<<0)
309*219b2ee8SDavid du Colombier			:: !goteof[1] -> rw = (1<<1)
310*219b2ee8SDavid du Colombier			fi;
311*219b2ee8SDavid du Colombier			selcall!rw;
312*219b2ee8SDavid du Colombier			selans?i,rw;
313*219b2ee8SDavid du Colombier			if
314*219b2ee8SDavid du Colombier			:: i == EOF ->
315*219b2ee8SDavid du Colombier				goteof[rw] = 1;
316*219b2ee8SDavid du Colombier				ndone = ndone + 1
317*219b2ee8SDavid du Colombier			:: i != EOF ->
318*219b2ee8SDavid du Colombier				/* this next statement knows NBUFS == 2 ! */
319*219b2ee8SDavid du Colombier				if
320*219b2ee8SDavid du Colombier				:: rw & (1<<0) -> fd = 0
321*219b2ee8SDavid du Colombier				:: rw & (1<<1) -> fd = 1
322*219b2ee8SDavid du Colombier				:: rw == 0 -> fd = EOF
323*219b2ee8SDavid du Colombier				fi;
324*219b2ee8SDavid du Colombier				if
325*219b2ee8SDavid du Colombier				:: nwant = 1
326*219b2ee8SDavid du Colombier				:: nwant = READMAX
327*219b2ee8SDavid du Colombier				fi;
328*219b2ee8SDavid du Colombier				if
329*219b2ee8SDavid du Colombier				:: fd != EOF ->
330*219b2ee8SDavid du Colombier					readcall!fd,nwant;
331*219b2ee8SDavid du Colombier					readans?num;
332*219b2ee8SDavid du Colombier					assert(num != 0)
333*219b2ee8SDavid du Colombier				:: fd == EOF -> skip
334*219b2ee8SDavid du Colombier				fi
335*219b2ee8SDavid du Colombier			fi
336*219b2ee8SDavid du Colombier		fi
337*219b2ee8SDavid du Colombier	od;
338*219b2ee8SDavid du Colombier	lockkill!release;
339*219b2ee8SDavid du Colombier	selkill!release;
340*219b2ee8SDavid du Colombier	readkill!release
341*219b2ee8SDavid du Colombier}
342*219b2ee8SDavid du Colombier
343*219b2ee8SDavid du Colombierinit
344*219b2ee8SDavid du Colombier{
345*219b2ee8SDavid du Colombier	byte i;
346*219b2ee8SDavid du Colombier
347*219b2ee8SDavid du Colombier	atomic {
348*219b2ee8SDavid du Colombier		run Lockrendez();
349*219b2ee8SDavid du Colombier		i = 0;
350*219b2ee8SDavid du Colombier		do
351*219b2ee8SDavid du Colombier		:: i < NBUFS ->
352*219b2ee8SDavid du Colombier			run Copy(i);
353*219b2ee8SDavid du Colombier			i = i+1
354*219b2ee8SDavid du Colombier		:: i >= NBUFS -> break
355*219b2ee8SDavid du Colombier		od;
356*219b2ee8SDavid du Colombier		run Select();
357*219b2ee8SDavid du Colombier		run Read();
358*219b2ee8SDavid du Colombier		run User()
359*219b2ee8SDavid du Colombier	}
360*219b2ee8SDavid du Colombier}
361