]> Cypherpunks repositories - gostls13.git/commitdiff
select
authorKen Thompson <ken@golang.org>
Fri, 25 Jul 2008 22:55:12 +0000 (15:55 -0700)
committerKen Thompson <ken@golang.org>
Fri, 25 Jul 2008 22:55:12 +0000 (15:55 -0700)
R=r
APPROVED=r
DELTA=147  (94 added, 14 deleted, 39 changed)
OCL=13477
CL=13477

src/cmd/gc/walk.c
src/runtime/chan.c
src/runtime/runtime.h

index dcc4fa077034652f43e0a34e2f4148235404abda..dc37c8c5d3c9ecf6ced636187d415def2822faa7 100644 (file)
@@ -1069,7 +1069,7 @@ walkselect(Node *sel)
        walktype(sel->ninit, Etop);
        walktype(sel->nbody, Etop);
 
-dump("sel", sel);
+//dump("sel", sel);
 
        lineno = lno;
 }
index ffaf55448fbd39b8ac0a4bb157e8f9d843a048ac..e097d6ee98ad41a93fee7b73b68ae815df6d22f3 100644 (file)
@@ -17,7 +17,8 @@ struct        SudoG
 {
        G*      g;              // g and selgen constitute
        byte    elem[8];        // synch data element
-       int64   selgen;         // a weak pointer to g
+       int16   offset;         // offset of case number
+       int32   selgen;         // a weak pointer to g
        SudoG*  link;
 };
 
@@ -162,6 +163,7 @@ sys·chansend1(Hchan* c, ...)
                c->elemalg->copy(c->elemsize, sgr->elem, ae);
 
                gr = sgr->g;
+               gr->param = sgr;
                gr->status = Grunnable;
                return;
        }
@@ -217,6 +219,7 @@ sys·chansend2(Hchan* c, ...)
                gr = sgr->g;
                c->elemalg->copy(c->elemsize, sgr->elem, ae);
 
+               gr->param = sgr;
                gr->status = Grunnable;
                *ap = true;
                return;
@@ -263,6 +266,7 @@ sys·chanrecv1(Hchan* c, ...)
                c->elemalg->copy(c->elemsize, ae, sgs->elem);
 
                gs = sgs->g;
+               gs->param = sgs;
                gs->status = Grunnable;
 
                freesg(c, sgs);
@@ -319,6 +323,7 @@ sys·chanrecv2(Hchan* c, ...)
                c->elemalg->copy(c->elemsize, ae, sgs->elem);
 
                gs = sgs->g;
+               gs->param = sgs;
                gs->status = Grunnable;
 
                freesg(c, sgs);
@@ -374,7 +379,7 @@ sys·selectsend(Select *sel, Hchan *c, ...)
        Scase *cas;
        byte *as, *ae;
 
-       // return val, selected, is preset to false
+       // nil cases do not compete
        if(c == nil)
                return;
 
@@ -421,7 +426,7 @@ sys·selectrecv(Select *sel, Hchan *c, ...)
        Scase *cas;
        byte *as;
 
-       // return val, selected, is preset to false
+       // nil cases do not compete
        if(c == nil)
                return;
 
@@ -465,16 +470,21 @@ sys·selectgo(Select *sel)
        uint32 p, o, i;
        Scase *cas;
        Hchan *c;
+       SudoG *sg;
+       G *gp;
 
        byte *ae, *as;
-       SudoG *sgr;
-       G *gr;
 
-       SudoG *sgs;
-       G *gs;
+       if(0) {
+               prints("selectgo: sel=");
+               sys·printpointer(sel);
+               prints("\n");
+       }
 
-       if(sel->ncase < 1) {
-               throw("selectgo: no cases");
+       if(sel->ncase < 2) {
+               if(sel->ncase < 1)
+                       throw("selectgo: no cases");
+               // make special case of one.
        }
 
        // select a (relative) prime
@@ -486,45 +496,60 @@ sys·selectgo(Select *sel)
                        throw("selectgo: failed to select prime");
                }
        }
+
+       // select an initial offset
        o = fastrand2();
 
        p %= sel->ncase;
        o %= sel->ncase;
 
-       // pass 1 - look for something that can go
+       // pass 1 - look for something already waiting
        for(i=0; i<sel->ncase; i++) {
                cas = &sel->scase[o];
                c = cas->chan;
-               if(cas->send) {
-                       if(c->dataqsiz > 0) {
-                               throw("selectgo: send asynch");
-                       }
-                       sgr = dequeue(&c->recvq, c);
-                       if(sgr == nil)
-                               continue;
-
-                       c->elemalg->copy(c->elemsize, sgr->elem, cas->u.elem);
-                       gr = sgr->g;
-                       gr->status = Grunnable;
 
-                       goto retc;
-               } else {
-                       if(c->dataqsiz > 0) {
+               if(c->dataqsiz > 0) {
+                       if(cas->send)
+                               throw("selectgo: send asynch");
+                       else
                                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);
+               if(cas->send) {
+                       sg = dequeue(&c->recvq, c);
+                       if(sg != nil)
+                               goto gotr;
+               } else {
+                       sg = dequeue(&c->sendq, c);
+                       if(sg != nil)
+                               goto gots;
+               }
 
-                       gs = sgs->g;
-                       gs->status = Grunnable;
+               o += p;
+               if(o >= sel->ncase)
+                       o -= sel->ncase;
+       }
 
-                       freesg(c, sgs);
+       // pass 2 - enqueue on all chans
+       for(i=0; i<sel->ncase; i++) {
+               cas = &sel->scase[o];
+               c = cas->chan;
+               if(cas->send) {
+                       sg = dequeue(&c->recvq, c);
+                       if(sg != nil)
+                               goto gotr;      // probably an error
+                       sg = allocsg(c);
+                       sg->offset = o;
+                       c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
+                       enqueue(&c->sendq, sg);
+               } else {
+                       sg = dequeue(&c->sendq, c);
+                       if(sg != nil)
+                               goto gots;      // probably an error
 
-                       goto retc;
+                       sg = allocsg(c);
+                       sg->offset = o;
+                       enqueue(&c->recvq, sg);
                }
 
                o += p;
@@ -532,15 +557,69 @@ sys·selectgo(Select *sel)
                        o -= sel->ncase;
        }
 
-       if(debug) {
-               prints("selectgo s=");
+       if(0) {
+               prints("wait: sel=");
+               sys·printpointer(sel);
+               prints("\n");
+       }
+       g->status = Gwaiting;
+       sys·gosched();
+
+       if(0) {
+               prints("wait-return: sel=");
                sys·printpointer(sel);
-               prints(" p=");
-               sys·printpointer((void*)p);
                prints("\n");
        }
 
-       throw("selectgo");
+       sg = g->param;
+       o = sg->offset;
+       cas = &sel->scase[o];
+       c = cas->chan;
+
+       if(0) {
+               prints("wake: sel=");
+               sys·printpointer(sel);
+               prints(" c=");
+               sys·printpointer(c);
+               prints(" o=");
+               sys·printint(o);
+               prints("\n");
+       }
+       if(cas->send)
+               goto gots;
+
+gotr:
+       if(0) {
+               prints("gotr: sel=");
+               sys·printpointer(sel);
+               prints(" c=");
+               sys·printpointer(c);
+               prints(" o=");
+               sys·printint(o);
+               prints("\n");
+       }
+       c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
+       gp = sg->g;
+       gp->param = sg;
+       gp->status = Grunnable;
+       goto retc;
+
+gots:
+       if(0) {
+               prints("gots: sel=");
+               sys·printpointer(sel);
+               prints(" c=");
+               sys·printpointer(c);
+               prints(" o=");
+               sys·printint(o);
+               prints("\n");
+       }
+       if(cas->u.elemp != nil)
+               c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
+       gp = sg->g;
+       gp->param = sg;
+       gp->status = Grunnable;
+       freesg(c, sg);
 
 retc:
        sys·setcallerpc(&sel, cas->pc);
@@ -561,7 +640,7 @@ loop:
 
        // if sgp is stale, ignore it
        if(sgp->selgen != sgp->g->selgen) {
-prints("INVALID PSEUDOG POINTER\n");
+               //prints("INVALID PSEUDOG POINTER\n");
                freesg(c, sgp);
                goto loop;
        }
index fe6ef5457a5ab51b028956db74a91bdb60fd3f3e..9ee75349267aecabe02978cca881e757947a1059 100644 (file)
@@ -107,9 +107,10 @@ struct     G
        byte*   stack0;         // first stack segment
        Gobuf   sched;
        G*      alllink;        // on allq
-       int32   status;
+       void*   param;          // passed parameter on wakeup
+       int16   status;
        int32   goid;
-       int64   selgen;         // valid sudog pointer
+       int32   selgen;         // valid sudog pointer
 };
 struct M
 {