}
Node*
-selcase(Node *c, Node *var)
+selcase(Node *n, Node *var)
{
- Node *a, *r, *on;
+ Node *a, *r, *on, *c;
Type *t;
+ c = n->left;
+ if(c->op == ORECV)
+ goto recv;
+
walktype(c->left, Erv); // chan
walktype(c->right, Erv); // elem
+
t = fixchan(c->left->type);
if(t == T)
return;
argtype(on, t->type);
argtype(on, t->type);
- a = c->right; // elem
+ a = c->right; // elem
r = a;
- a = c->left; // chan
+ a = c->left; // chan
r = list(a, r);
- a = var; // sel-var
+ a = var; // sel-var
+ r = list(a, r);
+
+ a = nod(OCALL, on, r);
+ r = nod(OIF, N, N);
+ r->ntest = a;
+
+ return r;
+
+recv:
+ walktype(c->left, Elv); // elem
+ walktype(c->right, Erv); // chan
+
+ t = fixchan(c->right->type);
+ if(t == T)
+ return;
+
+ convlit(c->left, t->type);
+ if(!ascompat(t->type, c->left->type)) {
+ badtype(c->op, t->type, c->left->type);
+ return;
+ }
+
+ // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+ on = syslook("selectrecv", 1);
+ argtype(on, t->type);
+ argtype(on, t->type);
+
+ a = c->left; // elem
+ a = nod(OADDR, a, N);
+ r = a;
+ a = c->right; // chan
+ r = list(a, r);
+ a = var; // sel-var
r = list(a, r);
a = nod(OCALL, on, r);
break;
case OSEND:
+ case ORECV:
if(oc != N) {
bod = list(bod, nod(OBREAK, N, N));
oc->nbody = rev(bod);
}
- oc = selcase(n->left, var);
+ oc = selcase(n, var);
res = list(res, oc);
break;
}
walktype(sel->ninit, Etop);
walktype(sel->nbody, Etop);
+dump("sel", sel);
+
lineno = lno;
}
byte* pc; // return pc
uint16 send; // 0-recv 1-send
uint16 so; // vararg of selected bool
- byte elem[8]; // element
+ union {
+ byte elem[8]; // element (send)
+ byte* elemp; // pointer to element (recv)
+ } u;
};
struct Select
cas->send = 1;
ae = (byte*)&sel + eo;
- c->elemalg->copy(c->elemsize, cas->elem, ae);
+ c->elemalg->copy(c->elemsize, cas->u.elem, ae);
as = (byte*)&sel + cas->so;
*as = false;
void
sys·selectrecv(Select *sel, Hchan *c, ...)
{
- throw("selectrecv");
+ int32 i, epo;
+ Scase *cas;
+ byte *as;
+
+ // return val, selected, is preset to false
+ if(c == nil)
+ return;
+
+ i = sel->ncase;
+ if(i >= sel->tcase)
+ throw("selectsend: too many cases");
+ sel->ncase = i+1;
+ cas = &sel->scase[i];
+
+ cas->pc = sys·getcallerpc(&sel);
+ cas->chan = c;
+
+ epo = rnd(sizeof(sel), sizeof(c));
+ epo = rnd(epo+sizeof(c), sizeof(byte*));
+ cas->so = rnd(epo+sizeof(byte*), 1);
+ cas->send = 0;
+ cas->u.elemp = *(byte**)((byte*)&sel + epo);
+
+ as = (byte*)&sel + cas->so;
+ *as = false;
+
+ if(debug) {
+ prints("newselect s=");
+ sys·printpointer(sel);
+ prints(" pc=");
+ sys·printpointer(cas->pc);
+ prints(" chan=");
+ sys·printpointer(cas->chan);
+ prints(" so=");
+ sys·printint(cas->so);
+ prints(" send=");
+ sys·printint(cas->send);
+ prints("\n");
+ }
}
// selectgo(sel *byte);
SudoG *sgr;
G *gr;
+ SudoG *sgs;
+ G *gs;
+
if(sel->ncase < 1) {
throw("selectgo: no cases");
}
c = cas->chan;
if(cas->send) {
if(c->dataqsiz > 0) {
- throw("selectgo: asynch");
+ throw("selectgo: send asynch");
}
sgr = dequeue(&c->recvq, c);
if(sgr == nil)
continue;
- c->elemalg->copy(c->elemsize, sgr->elem, cas->elem);
+ c->elemalg->copy(c->elemsize, sgr->elem, cas->u.elem);
gr = sgr->g;
gr->status = Grunnable;
+ goto retc;
+ } else {
+ if(c->dataqsiz > 0) {
+ throw("selectgo: recv asynch");
+ }
+ sgs = dequeue(&c->sendq, c);
+ if(sgs == nil)
+ continue;
+
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, sgs->elem);
+
+ gs = sgs->g;
+ gs->status = Grunnable;
+
+ freesg(c, sgs);
+
goto retc;
}