#include "lib9.h"#include "isa.h"#include "interp.h"#include "raise.h" #define OP(fn) void fn(void)#define W(p) *((WORD*)(p)) #define CANGET(c) ((c)->size > 0)#define CANPUT(c) ((c)->buf != H && (c)->size < (c)->buf->len) extern OP(isend);extern OP(irecv); /* * Count the number of ready channels in an array of channels * Set each channel's alt pointer to the owning prog */static intaltmark(Channel *c, Prog *p){ int nrdy; Array *a; Channel **ca, **ec; nrdy = 0; a = (Array*)c; ca = (Channel**)a->data; ec = ca + a->len; while(ca < ec) { c = *ca; if(c != H) { if(c->send->prog || CANGET(c)) nrdy++; cqadd(&c->recv, p); } ca++; } return nrdy;} /* * Remove alt references to an array of channels */static voidaltunmark(Channel *c, WORD *ptr, Prog *p, int sr, Channel **sel, int dn){ int n; Array *a; Channel **ca, **ec; n = 0; a = (Array*)c; ca = (Channel**)a->data; ec = ca + a->len; while(ca < ec) { c = *ca; if(c != H && c->recv->prog) cqdelp(&c->recv, p); if(sr == 1 && *sel == c) { W(p->R.d) = dn; p->ptr = ptr + 1; ptr[0] = n; *sel = nil; } ca++; n++; }} /* * ALT Pass 1 - Count the number of ready channels and mark * each channel as ALT by this prog */static intaltrdy(Alt *a, Prog *p){ char *e; Type *t; int nrdy; Channel *c; Altc *ac, *eac; e = nil; nrdy = 0; ac = a->ac + a->nsend; eac = ac + a->nrecv; while(ac < eac) { c = ac->c; ac++; if(c == H) { e = exNilref; continue; } t = D2H(c)->t; if(t == &Tarray) nrdy += altmark(c, p); else { if(c->send->prog || CANGET(c)) nrdy++; cqadd(&c->recv, p); } } ac = a->ac; eac = ac + a->nsend; while(ac < eac) { c = ac->c; ac++; if(c == H) { e = exNilref; continue; } if(c->recv->prog || CANPUT(c)) { if(c->recv->prog == p) { e = exAlt; continue; } nrdy++; } cqadd(&c->send, p); } if(e != nil) { altdone(a, p, nil, -1); error(e); } return nrdy;} /* * ALT Pass 3 - Pull out of an ALT cancelling the channel pointers in each item */voidaltdone(Alt *a, Prog *p, Channel *sel, int sr){ int n; Type *t; Channel *c; Altc *ac, *eac; n = 0; ac = a->ac; eac = a->ac + a->nsend; while(ac < eac) { c = ac->c; if(c != H) { if(c->send->prog) cqdelp(&c->send, p); if(sr == 0 && c == sel) { p->ptr = ac->ptr; W(p->R.d) = n; sel = nil; } } ac++; n++; } eac = a->ac + a->nsend + a->nrecv; while(ac < eac) { c = ac->c; if(c != H) { t = D2H(c)->t; if(t == &Tarray) altunmark(c, ac->ptr, p, sr, &sel, n); else { if(c->recv->prog) cqdelp(&c->recv, p); if(sr == 1 && c == sel) { p->ptr = ac->ptr; W(p->R.d) = n; sel = nil; } } } ac++; n++; }} /* * ALT Pass 2 - Perform the communication on the chosen channel */static voidaltcomm(Alt *a, int which){ Type *t; Array *r; int n, an; WORD *ptr; Altc *ac, *eac; Channel *c, **ca, **ec; n = 0; ac = a->ac; eac = ac + a->nsend; while(ac < eac) { c = ac->c; if((c->recv->prog != nil || CANPUT(c)) && which-- == 0) { W(R.d) = n; R.s = ac->ptr; R.d = &c; isend(); return; } ac++; n++; } eac = eac + a->nrecv; while(ac < eac) { c = ac->c; t = D2H(c)->t; if(t == &Tarray) { an = 0; r = (Array*)c; ca = (Channel**)r->data; ec = ca + r->len; while(ca < ec) { c = *ca; if(c != H && (c->send->prog != nil || CANGET(c)) && which-- == 0) { W(R.d) = n; R.s = &c; ptr = ac->ptr; R.d = ptr + 1; ptr[0] = an; irecv(); return; } ca++; an++; } } else if((c->send->prog != nil || CANGET(c)) && which-- == 0) { W(R.d) = n; R.s = &c; R.d = ac->ptr; irecv(); return; } ac++; n++; } return;} voidaltgone(Prog *p){ Alt *a; if (p->state == Palt) { a = p->R.s; altdone(a, p, nil, -1); p->kill = "alt channel hungup"; addrun(p); }} voidxecalt(int block){ Alt *a; Prog *p; int nrdy; static ulong xrand = 0x20342; p = currun(); a = R.s; nrdy = altrdy(a, p); if(nrdy == 0) { if(block) { delrun(Palt); p->R.s = R.s; p->R.d = R.d; R.IC = 1; R.t = 1; return; } W(R.d) = a->nsend + a->nrecv; altdone(a, p, nil, -1); return; } xrand = xrand*1103515245 + 12345; altcomm(a, (xrand>>8)%nrdy); altdone(a, p, nil, -1);}
#include "lib9.h"
#include "isa.h"
#include "interp.h"
#include "raise.h"
#define OP(fn) void fn(void)
#define W(p) *((WORD*)(p))
#define CANGET(c) ((c)->size > 0)
#define CANPUT(c) ((c)->buf != H && (c)->size < (c)->buf->len)
extern OP(isend);
extern OP(irecv);
/*
* Count the number of ready channels in an array of channels
* Set each channel's alt pointer to the owning prog
*/
static int
altmark(Channel *c, Prog *p)
{
int nrdy;
Array *a;
Channel **ca, **ec;
nrdy = 0;
a = (Array*)c;
ca = (Channel**)a->data;
ec = ca + a->len;
while(ca < ec) {
c = *ca;
if(c != H) {
if(c->send->prog || CANGET(c))
nrdy++;
cqadd(&c->recv, p);
}
ca++;
}
return nrdy;
}
/*
* Remove alt references to an array of channels
*/
static void
altunmark(Channel *c, WORD *ptr, Prog *p, int sr, Channel **sel, int dn)
{
int n;
Array *a;
Channel **ca, **ec;
n = 0;
a = (Array*)c;
ca = (Channel**)a->data;
ec = ca + a->len;
while(ca < ec) {
c = *ca;
if(c != H && c->recv->prog)
cqdelp(&c->recv, p);
if(sr == 1 && *sel == c) {
W(p->R.d) = dn;
p->ptr = ptr + 1;
ptr[0] = n;
*sel = nil;
}
ca++;
n++;
}
}
/*
* ALT Pass 1 - Count the number of ready channels and mark
* each channel as ALT by this prog
*/
static int
altrdy(Alt *a, Prog *p)
{
char *e;
Type *t;
int nrdy;
Channel *c;
Altc *ac, *eac;
e = nil;
nrdy = 0;
ac = a->ac + a->nsend;
eac = ac + a->nrecv;
while(ac < eac) {
c = ac->c;
ac++;
if(c == H) {
e = exNilref;
continue;
}
t = D2H(c)->t;
if(t == &Tarray)
nrdy += altmark(c, p);
else {
if(c->send->prog || CANGET(c))
nrdy++;
cqadd(&c->recv, p);
}
}
ac = a->ac;
eac = ac + a->nsend;
while(ac < eac) {
c = ac->c;
ac++;
if(c == H) {
e = exNilref;
continue;
}
if(c->recv->prog || CANPUT(c)) {
if(c->recv->prog == p) {
e = exAlt;
continue;
}
nrdy++;
}
cqadd(&c->send, p);
}
if(e != nil) {
altdone(a, p, nil, -1);
error(e);
}
return nrdy;
}
/*
* ALT Pass 3 - Pull out of an ALT cancelling the channel pointers in each item
*/
void
altdone(Alt *a, Prog *p, Channel *sel, int sr)
{
int n;
Type *t;
Channel *c;
Altc *ac, *eac;
n = 0;
ac = a->ac;
eac = a->ac + a->nsend;
while(ac < eac) {
c = ac->c;
if(c != H) {
if(c->send->prog)
cqdelp(&c->send, p);
if(sr == 0 && c == sel) {
p->ptr = ac->ptr;
W(p->R.d) = n;
sel = nil;
}
}
ac++;
n++;
}
eac = a->ac + a->nsend + a->nrecv;
while(ac < eac) {
c = ac->c;
if(c != H) {
t = D2H(c)->t;
if(t == &Tarray)
altunmark(c, ac->ptr, p, sr, &sel, n);
else {
if(c->recv->prog)
cqdelp(&c->recv, p);
if(sr == 1 && c == sel) {
p->ptr = ac->ptr;
W(p->R.d) = n;
sel = nil;
}
}
}
ac++;
n++;
}
}
/*
* ALT Pass 2 - Perform the communication on the chosen channel
*/
static void
altcomm(Alt *a, int which)
{
Type *t;
Array *r;
int n, an;
WORD *ptr;
Altc *ac, *eac;
Channel *c, **ca, **ec;
n = 0;
ac = a->ac;
eac = ac + a->nsend;
while(ac < eac) {
c = ac->c;
if((c->recv->prog != nil || CANPUT(c)) && which-- == 0) {
W(R.d) = n;
R.s = ac->ptr;
R.d = &c;
isend();
return;
}
ac++;
n++;
}
eac = eac + a->nrecv;
while(ac < eac) {
c = ac->c;
t = D2H(c)->t;
if(t == &Tarray) {
an = 0;
r = (Array*)c;
ca = (Channel**)r->data;
ec = ca + r->len;
while(ca < ec) {
c = *ca;
if(c != H && (c->send->prog != nil || CANGET(c)) && which-- == 0) {
W(R.d) = n;
R.s = &c;
ptr = ac->ptr;
R.d = ptr + 1;
ptr[0] = an;
irecv();
return;
}
ca++;
an++;
}
}
else
if((c->send->prog != nil || CANGET(c)) && which-- == 0) {
W(R.d) = n;
R.s = &c;
R.d = ac->ptr;
irecv();
return;
}
ac++;
n++;
}
return;
}
void
altgone(Prog *p)
{
Alt *a;
if (p->state == Palt) {
a = p->R.s;
altdone(a, p, nil, -1);
p->kill = "alt channel hungup";
addrun(p);
}
}
void
xecalt(int block)
{
Alt *a;
Prog *p;
int nrdy;
static ulong xrand = 0x20342;
p = currun();
a = R.s;
nrdy = altrdy(a, p);
if(nrdy == 0) {
if(block) {
delrun(Palt);
p->R.s = R.s;
p->R.d = R.d;
R.IC = 1;
R.t = 1;
return;
}
W(R.d) = a->nsend + a->nrecv;
altdone(a, p, nil, -1);
return;
}
xrand = xrand*1103515245 + 12345;
altcomm(a, (xrand>>8)%nrdy);
altdone(a, p, nil, -1);
}