aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorKen Thompson <ken@golang.org>2008-07-25 15:55:12 -0700
committerKen Thompson <ken@golang.org>2008-07-25 15:55:12 -0700
commite963cba8a13b78042d0b75840a4e7f40f294113a (patch)
tree4244bc8f8512ae2aa060102814b49b3d039d8f27 /src/runtime
parent756c63cd023478c639bed98f3afb64c4e9e7aadf (diff)
downloadgo-e963cba8a13b78042d0b75840a4e7f40f294113a.tar.xz
select
R=r APPROVED=r DELTA=147 (94 added, 14 deleted, 39 changed) OCL=13477 CL=13477
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/chan.c159
-rw-r--r--src/runtime/runtime.h5
2 files changed, 122 insertions, 42 deletions
diff --git a/src/runtime/chan.c b/src/runtime/chan.c
index ffaf55448f..e097d6ee98 100644
--- a/src/runtime/chan.c
+++ b/src/runtime/chan.c
@@ -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("\n");
+ }
+
+ 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(" p=");
- sys·printpointer((void*)p);
+ 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;
- throw("selectgo");
+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;
}
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index fe6ef5457a..9ee7534926 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -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
{