#include "type.h"
static int32 debug = 0;
-static Lock chanlock;
enum
{
WaitQ recvq; // list of recv waiters
WaitQ sendq; // list of send waiters
SudoG* free; // freelist
+ Lock;
};
struct Link
{
c->closed += Eincr;
if(c->closed & Emax) {
- unlock(&chanlock);
+ // Note that channel locks may still be held at this point.
throw("too many operations on a closed channel");
}
}
prints("\n");
}
- lock(&chanlock);
+ lock(c);
loop:
if(c->closed & Wclosed)
goto closed;
gp = sg->g;
gp->param = sg;
- unlock(&chanlock);
+ unlock(c);
ready(gp);
if(pres != nil)
}
if(pres != nil) {
- unlock(&chanlock);
+ unlock(c);
*pres = false;
return;
}
g->param = nil;
g->status = Gwaiting;
enqueue(&c->sendq, sg);
- unlock(&chanlock);
+ unlock(c);
gosched();
- lock(&chanlock);
+ lock(c);
sg = g->param;
if(sg == nil)
goto loop;
freesg(c, sg);
- unlock(&chanlock);
+ unlock(c);
return;
asynch:
if(c->qcount >= c->dataqsiz) {
if(pres != nil) {
- unlock(&chanlock);
+ unlock(c);
*pres = false;
return;
}
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->sendq, sg);
- unlock(&chanlock);
+ unlock(c);
gosched();
- lock(&chanlock);
+ lock(c);
goto asynch;
}
if(ep != nil)
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- unlock(&chanlock);
+ unlock(c);
ready(gp);
} else
- unlock(&chanlock);
+ unlock(c);
if(pres != nil)
*pres = true;
return;
incerr(c);
if(pres != nil)
*pres = true;
- unlock(&chanlock);
+ unlock(c);
}
void
prints("\n");
}
- lock(&chanlock);
+ lock(c);
loop:
if(c->dataqsiz > 0)
goto asynch;
gp = sg->g;
gp->param = sg;
- unlock(&chanlock);
+ unlock(c);
ready(gp);
if(pres != nil)
}
if(pres != nil) {
- unlock(&chanlock);
+ unlock(c);
*pres = false;
return;
}
g->param = nil;
g->status = Gwaiting;
enqueue(&c->recvq, sg);
- unlock(&chanlock);
+ unlock(c);
gosched();
- lock(&chanlock);
+ lock(c);
sg = g->param;
if(sg == nil)
goto loop;
c->elemalg->copy(c->elemsize, ep, sg->elem);
freesg(c, sg);
- unlock(&chanlock);
+ unlock(c);
return;
asynch:
goto closed;
if(pres != nil) {
- unlock(&chanlock);
+ unlock(c);
*pres = false;
return;
}
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->recvq, sg);
- unlock(&chanlock);
+ unlock(c);
gosched();
- lock(&chanlock);
+ lock(c);
goto asynch;
}
c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- unlock(&chanlock);
+ unlock(c);
ready(gp);
if(pres != nil)
*pres = true;
return;
}
- unlock(&chanlock);
+ unlock(c);
if(pres != nil)
*pres = true;
return;
incerr(c);
if(pres != nil)
*pres = true;
- unlock(&chanlock);
+ unlock(c);
}
// chansend1(hchan *chan any, elem any);
free(sel);
}
+static void
+sellock(Select *sel)
+{
+ uint32 i;
+ Hchan *c;
+
+ c = nil;
+ for(i=0; i<sel->ncase; i++) {
+ if(sel->scase[i]->chan != c) {
+ c = sel->scase[i]->chan;
+ lock(c);
+ }
+ }
+}
+
+static void
+selunlock(Select *sel)
+{
+ uint32 i;
+ Hchan *c;
+
+ c = nil;
+ for(i=sel->ncase; i>0; i--) {
+ if(sel->scase[i-1]->chan && sel->scase[i-1]->chan != c) {
+ c = sel->scase[i-1]->chan;
+ unlock(c);
+ }
+ }
+}
+
// selectgo(sel *byte);
void
runtime·selectgo(Select *sel)
{
- uint32 p, o, i;
+ uint32 p, o, i, j;
Scase *cas, *dfl;
Hchan *c;
SudoG *sg;
p %= sel->ncase;
o %= sel->ncase;
- lock(&chanlock);
+ // sort the cases by Hchan address to get the locking order.
+ for(i=1; i<sel->ncase; i++) {
+ cas = sel->scase[i];
+ for(j=i-1; j<i && sel->scase[j]->chan >= cas->chan; j--)
+ sel->scase[j+1] = sel->scase[j];
+ // careful: j might be (unsigned)-1
+ // 6c trips on sel->scase[j+1] in that case by rewriting it to
+ // sel->scase[j] + 8.
+ j++;
+ sel->scase[j] = cas;
+ }
+
+ sellock(sel);
loop:
// pass 1 - look for something already waiting
g->param = nil;
g->status = Gwaiting;
- unlock(&chanlock);
+ selunlock(sel);
gosched();
- lock(&chanlock);
+ sellock(sel);
sg = g->param;
if(sg == nil)
goto loop;
goto retc;
retc:
- unlock(&chanlock);
+ selunlock(sel);
runtime·setcallerpc(&sel, cas->pc);
as = (byte*)&sel + cas->so;
SudoG *sg;
G* gp;
- lock(&chanlock);
+ lock(c);
incerr(c);
c->closed |= Wclosed;
ready(gp);
}
- unlock(&chanlock);
+ unlock(c);
}
void