xref: /inferno-os/libinterp/alt.c (revision 2a409d9c503f875c5ba694c0c601b287876c3536)
137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "isa.h"
337da2899SCharles.Forsyth #include "interp.h"
437da2899SCharles.Forsyth #include "raise.h"
537da2899SCharles.Forsyth 
637da2899SCharles.Forsyth #define OP(fn)	void fn(void)
737da2899SCharles.Forsyth #define W(p)	*((WORD*)(p))
837da2899SCharles.Forsyth 
937da2899SCharles.Forsyth #define CANGET(c)	((c)->size > 0)
1037da2899SCharles.Forsyth #define CANPUT(c)	((c)->buf != H && (c)->size < (c)->buf->len)
1137da2899SCharles.Forsyth 
1237da2899SCharles.Forsyth extern	OP(isend);
1337da2899SCharles.Forsyth extern	OP(irecv);
1437da2899SCharles.Forsyth 
1537da2899SCharles.Forsyth /*
1637da2899SCharles.Forsyth  * Count the number of ready channels in an array of channels
1737da2899SCharles.Forsyth  * Set each channel's alt pointer to the owning prog
1837da2899SCharles.Forsyth  */
1937da2899SCharles.Forsyth static int
altmark(Channel * c,Prog * p)2037da2899SCharles.Forsyth altmark(Channel *c, Prog *p)
2137da2899SCharles.Forsyth {
2237da2899SCharles.Forsyth 	int nrdy;
2337da2899SCharles.Forsyth 	Array *a;
2437da2899SCharles.Forsyth 	Channel **ca, **ec;
2537da2899SCharles.Forsyth 
2637da2899SCharles.Forsyth 	nrdy = 0;
2737da2899SCharles.Forsyth 	a = (Array*)c;
2837da2899SCharles.Forsyth 	ca = (Channel**)a->data;
2937da2899SCharles.Forsyth 	ec = ca + a->len;
3037da2899SCharles.Forsyth 	while(ca < ec) {
3137da2899SCharles.Forsyth 		c = *ca;
3237da2899SCharles.Forsyth 		if(c != H) {
3337da2899SCharles.Forsyth 			if(c->send->prog || CANGET(c))
3437da2899SCharles.Forsyth 				nrdy++;
3537da2899SCharles.Forsyth 			cqadd(&c->recv, p);
3637da2899SCharles.Forsyth 		}
3737da2899SCharles.Forsyth 		ca++;
3837da2899SCharles.Forsyth 	}
3937da2899SCharles.Forsyth 
4037da2899SCharles.Forsyth 	return nrdy;
4137da2899SCharles.Forsyth }
4237da2899SCharles.Forsyth 
4337da2899SCharles.Forsyth /*
4437da2899SCharles.Forsyth  * Remove alt references to an array of channels
4537da2899SCharles.Forsyth  */
4637da2899SCharles.Forsyth static void
altunmark(Channel * c,WORD * ptr,Prog * p,int sr,Channel ** sel,int dn)4737da2899SCharles.Forsyth altunmark(Channel *c, WORD *ptr, Prog *p, int sr, Channel **sel, int dn)
4837da2899SCharles.Forsyth {
4937da2899SCharles.Forsyth 	int n;
5037da2899SCharles.Forsyth 	Array *a;
5137da2899SCharles.Forsyth 	Channel **ca, **ec;
5237da2899SCharles.Forsyth 
5337da2899SCharles.Forsyth 	n = 0;
5437da2899SCharles.Forsyth 	a = (Array*)c;
5537da2899SCharles.Forsyth 	ca = (Channel**)a->data;
5637da2899SCharles.Forsyth 	ec = ca + a->len;
5737da2899SCharles.Forsyth 	while(ca < ec) {
5837da2899SCharles.Forsyth 		c = *ca;
5937da2899SCharles.Forsyth 		if(c != H && c->recv->prog)
6037da2899SCharles.Forsyth 			cqdelp(&c->recv, p);
6137da2899SCharles.Forsyth 		if(sr == 1 && *sel == c) {
6237da2899SCharles.Forsyth 			W(p->R.d) = dn;
6337da2899SCharles.Forsyth 			p->ptr = ptr + 1;
6437da2899SCharles.Forsyth 			ptr[0] = n;
6537da2899SCharles.Forsyth 			*sel = nil;
6637da2899SCharles.Forsyth 		}
6737da2899SCharles.Forsyth 		ca++;
6837da2899SCharles.Forsyth 		n++;
6937da2899SCharles.Forsyth 	}
7037da2899SCharles.Forsyth }
7137da2899SCharles.Forsyth 
7237da2899SCharles.Forsyth /*
7337da2899SCharles.Forsyth  * ALT Pass 1 - Count the number of ready channels and mark
7437da2899SCharles.Forsyth  * each channel as ALT by this prog
7537da2899SCharles.Forsyth  */
7637da2899SCharles.Forsyth static int
altrdy(Alt * a,Prog * p)7737da2899SCharles.Forsyth altrdy(Alt *a, Prog *p)
7837da2899SCharles.Forsyth {
7937da2899SCharles.Forsyth 	char *e;
8037da2899SCharles.Forsyth 	Type *t;
8137da2899SCharles.Forsyth 	int nrdy;
8237da2899SCharles.Forsyth 	Channel *c;
8337da2899SCharles.Forsyth 	Altc *ac, *eac;
8437da2899SCharles.Forsyth 
8537da2899SCharles.Forsyth 	e = nil;
8637da2899SCharles.Forsyth 	nrdy = 0;
8737da2899SCharles.Forsyth 
8837da2899SCharles.Forsyth 	ac = a->ac + a->nsend;
8937da2899SCharles.Forsyth 	eac = ac + a->nrecv;
9037da2899SCharles.Forsyth 	while(ac < eac) {
9137da2899SCharles.Forsyth 		c = ac->c;
9237da2899SCharles.Forsyth 		ac++;
9337da2899SCharles.Forsyth 		if(c == H) {
9437da2899SCharles.Forsyth 			e = exNilref;
9537da2899SCharles.Forsyth 			continue;
9637da2899SCharles.Forsyth 		}
9737da2899SCharles.Forsyth 		t = D2H(c)->t;
9837da2899SCharles.Forsyth 		if(t == &Tarray)
9937da2899SCharles.Forsyth 			nrdy += altmark(c, p);
10037da2899SCharles.Forsyth 		else {
10137da2899SCharles.Forsyth 			if(c->send->prog || CANGET(c))
10237da2899SCharles.Forsyth 				nrdy++;
10337da2899SCharles.Forsyth 			cqadd(&c->recv, p);
10437da2899SCharles.Forsyth 		}
10537da2899SCharles.Forsyth 	}
10637da2899SCharles.Forsyth 
10737da2899SCharles.Forsyth 	ac = a->ac;
10837da2899SCharles.Forsyth 	eac = ac + a->nsend;
10937da2899SCharles.Forsyth 	while(ac < eac) {
11037da2899SCharles.Forsyth 		c = ac->c;
11137da2899SCharles.Forsyth 		ac++;
11237da2899SCharles.Forsyth 		if(c == H) {
11337da2899SCharles.Forsyth 			e = exNilref;
11437da2899SCharles.Forsyth 			continue;
11537da2899SCharles.Forsyth 		}
11637da2899SCharles.Forsyth 		if(c->recv->prog || CANPUT(c)) {
11737da2899SCharles.Forsyth 			if(c->recv->prog == p) {
11837da2899SCharles.Forsyth 				e = exAlt;
11937da2899SCharles.Forsyth 				continue;
12037da2899SCharles.Forsyth 			}
12137da2899SCharles.Forsyth 			nrdy++;
12237da2899SCharles.Forsyth 		}
12337da2899SCharles.Forsyth 		cqadd(&c->send, p);
12437da2899SCharles.Forsyth 	}
12537da2899SCharles.Forsyth 
12637da2899SCharles.Forsyth 	if(e != nil) {
12737da2899SCharles.Forsyth 		altdone(a, p, nil, -1);
12837da2899SCharles.Forsyth 		error(e);
12937da2899SCharles.Forsyth 	}
13037da2899SCharles.Forsyth 
13137da2899SCharles.Forsyth 	return nrdy;
13237da2899SCharles.Forsyth }
13337da2899SCharles.Forsyth 
13437da2899SCharles.Forsyth /*
13537da2899SCharles.Forsyth  * ALT Pass 3 - Pull out of an ALT cancelling the channel pointers in each item
13637da2899SCharles.Forsyth  */
13737da2899SCharles.Forsyth void
altdone(Alt * a,Prog * p,Channel * sel,int sr)13837da2899SCharles.Forsyth altdone(Alt *a, Prog *p, Channel *sel, int sr)
13937da2899SCharles.Forsyth {
14037da2899SCharles.Forsyth 	int n;
14137da2899SCharles.Forsyth 	Type *t;
14237da2899SCharles.Forsyth 	Channel *c;
14337da2899SCharles.Forsyth 	Altc *ac, *eac;
14437da2899SCharles.Forsyth 
14537da2899SCharles.Forsyth 	n = 0;
14637da2899SCharles.Forsyth 	ac = a->ac;
14737da2899SCharles.Forsyth 	eac = a->ac + a->nsend;
14837da2899SCharles.Forsyth 	while(ac < eac) {
14937da2899SCharles.Forsyth 		c = ac->c;
15037da2899SCharles.Forsyth 		if(c != H) {
15137da2899SCharles.Forsyth 			if(c->send->prog)
15237da2899SCharles.Forsyth 				cqdelp(&c->send, p);
15337da2899SCharles.Forsyth 			if(sr == 0 && c == sel) {
15437da2899SCharles.Forsyth 				p->ptr = ac->ptr;
15537da2899SCharles.Forsyth 				W(p->R.d) = n;
15637da2899SCharles.Forsyth 				sel = nil;
15737da2899SCharles.Forsyth 			}
15837da2899SCharles.Forsyth 		}
15937da2899SCharles.Forsyth 		ac++;
16037da2899SCharles.Forsyth 		n++;
16137da2899SCharles.Forsyth 	}
16237da2899SCharles.Forsyth 
16337da2899SCharles.Forsyth 	eac = a->ac + a->nsend + a->nrecv;
16437da2899SCharles.Forsyth 	while(ac < eac) {
16537da2899SCharles.Forsyth 		c = ac->c;
16637da2899SCharles.Forsyth 		if(c != H) {
16737da2899SCharles.Forsyth 			t = D2H(c)->t;
16837da2899SCharles.Forsyth 			if(t == &Tarray)
16937da2899SCharles.Forsyth 				altunmark(c, ac->ptr, p, sr, &sel, n);
17037da2899SCharles.Forsyth 			else {
17137da2899SCharles.Forsyth 				if(c->recv->prog)
17237da2899SCharles.Forsyth 					cqdelp(&c->recv, p);
17337da2899SCharles.Forsyth 				if(sr == 1 && c == sel) {
17437da2899SCharles.Forsyth 					p->ptr = ac->ptr;
17537da2899SCharles.Forsyth 					W(p->R.d) = n;
17637da2899SCharles.Forsyth 					sel = nil;
17737da2899SCharles.Forsyth 				}
17837da2899SCharles.Forsyth 			}
17937da2899SCharles.Forsyth 		}
18037da2899SCharles.Forsyth 		ac++;
18137da2899SCharles.Forsyth 		n++;
18237da2899SCharles.Forsyth 	}
18337da2899SCharles.Forsyth }
18437da2899SCharles.Forsyth 
18537da2899SCharles.Forsyth /*
18637da2899SCharles.Forsyth  * ALT Pass 2 - Perform the communication on the chosen channel
18737da2899SCharles.Forsyth  */
18837da2899SCharles.Forsyth static void
altcomm(Alt * a,int which)18937da2899SCharles.Forsyth altcomm(Alt *a, int which)
19037da2899SCharles.Forsyth {
19137da2899SCharles.Forsyth 	Type *t;
19237da2899SCharles.Forsyth 	Array *r;
19337da2899SCharles.Forsyth 	int n, an;
19437da2899SCharles.Forsyth 	WORD *ptr;
19537da2899SCharles.Forsyth 	Altc *ac, *eac;
19637da2899SCharles.Forsyth 	Channel *c, **ca, **ec;
19737da2899SCharles.Forsyth 
19837da2899SCharles.Forsyth 	n = 0;
19937da2899SCharles.Forsyth 	ac = a->ac;
20037da2899SCharles.Forsyth 	eac = ac + a->nsend;
20137da2899SCharles.Forsyth 	while(ac < eac) {
20237da2899SCharles.Forsyth 		c = ac->c;
20337da2899SCharles.Forsyth 		if((c->recv->prog != nil || CANPUT(c)) && which-- == 0) {
20437da2899SCharles.Forsyth 			W(R.d) = n;
20537da2899SCharles.Forsyth 			R.s = ac->ptr;
20637da2899SCharles.Forsyth 			R.d = &c;
20737da2899SCharles.Forsyth 			isend();
20837da2899SCharles.Forsyth 			return;
20937da2899SCharles.Forsyth 		}
21037da2899SCharles.Forsyth 		ac++;
21137da2899SCharles.Forsyth 		n++;
21237da2899SCharles.Forsyth 	}
21337da2899SCharles.Forsyth 
21437da2899SCharles.Forsyth 	eac = eac + a->nrecv;
21537da2899SCharles.Forsyth 	while(ac < eac) {
21637da2899SCharles.Forsyth 		c = ac->c;
21737da2899SCharles.Forsyth 		t = D2H(c)->t;
21837da2899SCharles.Forsyth 		if(t == &Tarray) {
21937da2899SCharles.Forsyth 			an = 0;
22037da2899SCharles.Forsyth 			r = (Array*)c;
22137da2899SCharles.Forsyth 			ca = (Channel**)r->data;
22237da2899SCharles.Forsyth 			ec = ca + r->len;
22337da2899SCharles.Forsyth 			while(ca < ec) {
22437da2899SCharles.Forsyth 				c = *ca;
22537da2899SCharles.Forsyth 				if(c != H && (c->send->prog != nil || CANGET(c)) && which-- == 0) {
22637da2899SCharles.Forsyth 					W(R.d) = n;
22737da2899SCharles.Forsyth 					R.s = &c;
22837da2899SCharles.Forsyth 					ptr = ac->ptr;
22937da2899SCharles.Forsyth 					R.d = ptr + 1;
23037da2899SCharles.Forsyth 					ptr[0] = an;
23137da2899SCharles.Forsyth 					irecv();
23237da2899SCharles.Forsyth 					return;
23337da2899SCharles.Forsyth 				}
23437da2899SCharles.Forsyth 				ca++;
23537da2899SCharles.Forsyth 				an++;
23637da2899SCharles.Forsyth 			}
23737da2899SCharles.Forsyth 		}
23837da2899SCharles.Forsyth 		else
23937da2899SCharles.Forsyth 		if((c->send->prog != nil || CANGET(c)) && which-- == 0) {
24037da2899SCharles.Forsyth 			W(R.d) = n;
24137da2899SCharles.Forsyth 			R.s = &c;
24237da2899SCharles.Forsyth 			R.d = ac->ptr;
24337da2899SCharles.Forsyth 			irecv();
24437da2899SCharles.Forsyth 			return;
24537da2899SCharles.Forsyth 		}
24637da2899SCharles.Forsyth 		ac++;
24737da2899SCharles.Forsyth 		n++;
24837da2899SCharles.Forsyth 	}
24937da2899SCharles.Forsyth 	return;
25037da2899SCharles.Forsyth }
25137da2899SCharles.Forsyth 
25237da2899SCharles.Forsyth void
altgone(Prog * p)25337da2899SCharles.Forsyth altgone(Prog *p)
25437da2899SCharles.Forsyth {
25537da2899SCharles.Forsyth 	Alt *a;
25637da2899SCharles.Forsyth 
25737da2899SCharles.Forsyth 	if (p->state == Palt) {
25837da2899SCharles.Forsyth 		a = p->R.s;
25937da2899SCharles.Forsyth 		altdone(a, p, nil, -1);
26037da2899SCharles.Forsyth 		p->kill = "alt channel hungup";
26137da2899SCharles.Forsyth 		addrun(p);
26237da2899SCharles.Forsyth 	}
26337da2899SCharles.Forsyth }
26437da2899SCharles.Forsyth 
26537da2899SCharles.Forsyth void
xecalt(int block)26637da2899SCharles.Forsyth xecalt(int block)
26737da2899SCharles.Forsyth {
26837da2899SCharles.Forsyth 	Alt *a;
26937da2899SCharles.Forsyth 	Prog *p;
27037da2899SCharles.Forsyth 	int nrdy;
271*2a409d9cSCharles.Forsyth 	static ulong xrand = 0x20342;
27237da2899SCharles.Forsyth 
27337da2899SCharles.Forsyth 	p = currun();
27437da2899SCharles.Forsyth 
27537da2899SCharles.Forsyth 	a = R.s;
27637da2899SCharles.Forsyth 	nrdy = altrdy(a, p);
27737da2899SCharles.Forsyth 	if(nrdy == 0) {
27837da2899SCharles.Forsyth 		if(block) {
27937da2899SCharles.Forsyth 			delrun(Palt);
28037da2899SCharles.Forsyth 			p->R.s = R.s;
28137da2899SCharles.Forsyth 			p->R.d = R.d;
28237da2899SCharles.Forsyth 			R.IC = 1;
28337da2899SCharles.Forsyth 			R.t = 1;
28437da2899SCharles.Forsyth 			return;
28537da2899SCharles.Forsyth 		}
28637da2899SCharles.Forsyth 		W(R.d) = a->nsend + a->nrecv;
28737da2899SCharles.Forsyth 		altdone(a, p, nil, -1);
28837da2899SCharles.Forsyth 		return;
28937da2899SCharles.Forsyth 	}
29037da2899SCharles.Forsyth 
291*2a409d9cSCharles.Forsyth 	xrand = xrand*1103515245 + 12345;
292*2a409d9cSCharles.Forsyth 	altcomm(a, (xrand>>8)%nrdy);
29337da2899SCharles.Forsyth 	altdone(a, p, nil, -1);
29437da2899SCharles.Forsyth }
295