Commit 6b2ec065 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov Committed by Russ Cox

runtime: faster select

Make selectsend() accept pointer to the element,
it makes it possible to make Scase fixed-size
and allocate/free Select, all Scase's and all SudoG at once.
As a consequence SudoG freelist die out.

benchmark                       old,ns/op  new,ns/op
BenchmarkSelectUncontended	     1080        558
BenchmarkSelectUncontended-2	      675        264
BenchmarkSelectUncontended-4	      459        205
BenchmarkSelectContended	     1086        560
BenchmarkSelectContended-2	     1775       1672
BenchmarkSelectContended-4	     2668       2149
(on Intel Q6600, 4 cores, 2.4GHz)

benchmark                       old ns/op    new ns/op    delta
BenchmarkSelectUncontended         517.00       326.00  -36.94%
BenchmarkSelectUncontended-2       281.00       166.00  -40.93%
BenchmarkSelectUncontended-4       250.00        83.10  -66.76%
BenchmarkSelectUncontended-8       107.00        47.40  -55.70%
BenchmarkSelectUncontended-16       67.80        41.30  -39.09%
BenchmarkSelectContended           513.00       325.00  -36.65%
BenchmarkSelectContended-2         699.00       628.00  -10.16%
BenchmarkSelectContended-4        1085.00      1092.00   +0.65%
BenchmarkSelectContended-8        3253.00      2477.00  -23.85%
BenchmarkSelectContended-16       5313.00      5116.00   -3.71%
(on Intel E5620, 8 HT cores, 2.4 GHz)

R=rsc, ken
CC=golang-dev
https://golang.org/cl/4811041
parent 17d9093b
...@@ -76,7 +76,7 @@ char *runtimeimport = ...@@ -76,7 +76,7 @@ char *runtimeimport =
"func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n" "func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n"
"func \"\".selectnbrecv2 (elem *any, received *bool, hchan <-chan any) bool\n" "func \"\".selectnbrecv2 (elem *any, received *bool, hchan <-chan any) bool\n"
"func \"\".newselect (size int) *uint8\n" "func \"\".newselect (size int) *uint8\n"
"func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) bool\n" "func \"\".selectsend (sel *uint8, hchan chan<- any, elem *any) bool\n"
"func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n" "func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n"
"func \"\".selectrecv2 (sel *uint8, hchan <-chan any, elem *any, received *bool) bool\n" "func \"\".selectrecv2 (sel *uint8, hchan <-chan any, elem *any, received *bool) bool\n"
"func \"\".selectdefault (sel *uint8) bool\n" "func \"\".selectdefault (sel *uint8) bool\n"
......
...@@ -1137,6 +1137,7 @@ Sym* restrictlookup(char *name, Pkg *pkg); ...@@ -1137,6 +1137,7 @@ Sym* restrictlookup(char *name, Pkg *pkg);
Node* safeexpr(Node *n, NodeList **init); Node* safeexpr(Node *n, NodeList **init);
void saveerrors(void); void saveerrors(void);
Node* cheapexpr(Node *n, NodeList **init); Node* cheapexpr(Node *n, NodeList **init);
Node* localexpr(Node *n, NodeList **init);
int32 setlineno(Node *n); int32 setlineno(Node *n);
void setmaxarg(Type *t); void setmaxarg(Type *t);
Type* shallow(Type *t); Type* shallow(Type *t);
......
...@@ -103,7 +103,7 @@ func selectnbrecv(elem *any, hchan <-chan any) bool ...@@ -103,7 +103,7 @@ func selectnbrecv(elem *any, hchan <-chan any) bool
func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool
func newselect(size int) (sel *byte) func newselect(size int) (sel *byte)
func selectsend(sel *byte, hchan chan<- any, elem any) (selected bool) func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool)
func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool) func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool) func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
func selectdefault(sel *byte) (selected bool) func selectdefault(sel *byte) (selected bool)
......
...@@ -309,7 +309,12 @@ walkselect(Node *sel) ...@@ -309,7 +309,12 @@ walkselect(Node *sel)
fatal("select %O", n->op); fatal("select %O", n->op);
case OSEND: case OSEND:
// selectsend(sel *byte, hchan *chan any, elem any) (selected bool); // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
n->left = safeexpr(n->left, &r->ninit);
n->right = localexpr(n->right, &r->ninit);
n->right = nod(OADDR, n->right, N);
n->right->etype = 1; // pointer does not escape
typecheck(&n->right, Erv);
r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
&init, var, n->left, n->right); &init, var, n->left, n->right);
break; break;
......
...@@ -2750,6 +2750,20 @@ safeexpr(Node *n, NodeList **init) ...@@ -2750,6 +2750,20 @@ safeexpr(Node *n, NodeList **init)
return cheapexpr(n, init); return cheapexpr(n, init);
} }
static Node*
copyexpr(Node *n, NodeList **init)
{
Node *a, *l;
l = nod(OXXX, N, N);
tempname(l, n->type);
a = nod(OAS, l, n);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
return l;
}
/* /*
* return side-effect free and cheap n, appending side effects to init. * return side-effect free and cheap n, appending side effects to init.
* result may not be assignable. * result may not be assignable.
...@@ -2757,21 +2771,26 @@ safeexpr(Node *n, NodeList **init) ...@@ -2757,21 +2771,26 @@ safeexpr(Node *n, NodeList **init)
Node* Node*
cheapexpr(Node *n, NodeList **init) cheapexpr(Node *n, NodeList **init)
{ {
Node *a, *l;
switch(n->op) { switch(n->op) {
case ONAME: case ONAME:
case OLITERAL: case OLITERAL:
return n; return n;
} }
l = nod(OXXX, N, N); return copyexpr(n, init);
tempname(l, n->type); }
a = nod(OAS, l, n);
typecheck(&a, Etop); /*
walkexpr(&a, init); * return n in a local variable if it is not already.
*init = list(*init, a); */
return l; Node*
localexpr(Node *n, NodeList **init)
{
if(n->op == ONAME &&
(n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT))
return n;
return copyexpr(n, init);
} }
void void
......
...@@ -1422,7 +1422,6 @@ synthesizechantypes(DWDie *die) ...@@ -1422,7 +1422,6 @@ synthesizechantypes(DWDie *die)
copychildren(dwh, hchan); copychildren(dwh, hchan);
substitutetype(dwh, "recvq", dww); substitutetype(dwh, "recvq", dww);
substitutetype(dwh, "sendq", dww); substitutetype(dwh, "sendq", dww);
substitutetype(dwh, "free", defptrto(dws));
newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
getattr(hchan, DW_AT_byte_size)->value, nil); getattr(hchan, DW_AT_byte_size)->value, nil);
......
...@@ -19,8 +19,6 @@ struct SudoG ...@@ -19,8 +19,6 @@ struct SudoG
{ {
G* g; // g and selgen constitute G* g; // g and selgen constitute
uint32 selgen; // a weak pointer to g uint32 selgen; // a weak pointer to g
int16 offset; // offset of case number
int8 isfree; // offset of case number
SudoG* link; SudoG* link;
byte* elem; // data element byte* elem; // data element
}; };
...@@ -43,7 +41,6 @@ struct Hchan ...@@ -43,7 +41,6 @@ struct Hchan
uint32 recvx; // receive index uint32 recvx; // receive index
WaitQ recvq; // list of recv waiters WaitQ recvq; // list of recv waiters
WaitQ sendq; // list of send waiters WaitQ sendq; // list of send waiters
SudoG* free; // freelist
Lock; Lock;
}; };
...@@ -61,33 +58,26 @@ enum ...@@ -61,33 +58,26 @@ enum
struct Scase struct Scase
{ {
SudoG sg; // must be first member (cast to Scase)
Hchan* chan; // chan Hchan* chan; // chan
byte* pc; // return pc byte* pc; // return pc
uint16 kind; uint16 kind;
uint16 so; // vararg of selected bool uint16 so; // vararg of selected bool
union {
byte elem[2*sizeof(void*)]; // element (send)
struct {
byte* elemp; // pointer to element (recv)
bool* receivedp; // pointer to received bool (recv2) bool* receivedp; // pointer to received bool (recv2)
} recv;
} u;
}; };
struct Select struct Select
{ {
uint16 tcase; // total count of scase[] uint16 tcase; // total count of scase[]
uint16 ncase; // currently filled scase[] uint16 ncase; // currently filled scase[]
Select* link; // for freelist uint16* pollorder; // case poll order
uint16* order; Hchan** lockorder; // channel lock order
Scase* scase[1]; // one per case Scase scase[1]; // one per case (in order of appearance)
}; };
static void dequeueg(WaitQ*, Hchan*); static void dequeueg(WaitQ*);
static SudoG* dequeue(WaitQ*, Hchan*); static SudoG* dequeue(WaitQ*);
static void enqueue(WaitQ*, SudoG*); static void enqueue(WaitQ*, SudoG*);
static SudoG* allocsg(Hchan*);
static void freesg(Hchan*, SudoG*);
static void destroychan(Hchan*); static void destroychan(Hchan*);
Hchan* Hchan*
...@@ -192,7 +182,7 @@ runtime·chansend(Hchan *c, byte *ep, bool *pres) ...@@ -192,7 +182,7 @@ runtime·chansend(Hchan *c, byte *ep, bool *pres)
if(c->dataqsiz > 0) if(c->dataqsiz > 0)
goto asynch; goto asynch;
sg = dequeue(&c->recvq, c); sg = dequeue(&c->recvq);
if(sg != nil) { if(sg != nil) {
runtime·unlock(c); runtime·unlock(c);
...@@ -257,7 +247,7 @@ asynch: ...@@ -257,7 +247,7 @@ asynch:
c->sendx = 0; c->sendx = 0;
c->qcount++; c->qcount++;
sg = dequeue(&c->recvq, c); sg = dequeue(&c->recvq);
if(sg != nil) { if(sg != nil) {
gp = sg->g; gp = sg->g;
runtime·unlock(c); runtime·unlock(c);
...@@ -297,7 +287,7 @@ runtime·chanrecv(Hchan* c, byte *ep, bool *selected, bool *received) ...@@ -297,7 +287,7 @@ runtime·chanrecv(Hchan* c, byte *ep, bool *selected, bool *received)
if(c->closed) if(c->closed)
goto closed; goto closed;
sg = dequeue(&c->sendq, c); sg = dequeue(&c->sendq);
if(sg != nil) { if(sg != nil) {
runtime·unlock(c); runtime·unlock(c);
...@@ -370,7 +360,7 @@ asynch: ...@@ -370,7 +360,7 @@ asynch:
c->recvx = 0; c->recvx = 0;
c->qcount--; c->qcount--;
sg = dequeue(&c->sendq, c); sg = dequeue(&c->sendq);
if(sg != nil) { if(sg != nil) {
gp = sg->g; gp = sg->g;
runtime·unlock(c); runtime·unlock(c);
...@@ -619,57 +609,53 @@ newselect(int32 size, Select **selp) ...@@ -619,57 +609,53 @@ newselect(int32 size, Select **selp)
if(size > 1) if(size > 1)
n = size-1; n = size-1;
sel = runtime·mal(sizeof(*sel) + n*sizeof(sel->scase[0]) + size*sizeof(sel->order[0])); sel = runtime·mal(sizeof(*sel) +
n*sizeof(sel->scase[0]) +
size*sizeof(sel->lockorder[0]) +
size*sizeof(sel->pollorder[0]));
sel->tcase = size; sel->tcase = size;
sel->ncase = 0; sel->ncase = 0;
sel->order = (void*)(sel->scase + size); sel->pollorder = (void*)(sel->scase + size);
sel->lockorder = (void*)(sel->pollorder + size);
*selp = sel; *selp = sel;
if(debug) if(debug)
runtime·printf("newselect s=%p size=%d\n", sel, size); runtime·printf("newselect s=%p size=%d\n", sel, size);
} }
// cut in half to give stack a chance to split // cut in half to give stack a chance to split
static void selectsend(Select **selp, Hchan *c, void *pc); static void selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so);
// selectsend(sel *byte, hchan *chan any, elem any) (selected bool); // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
#pragma textflag 7 #pragma textflag 7
void void
runtime·selectsend(Select *sel, Hchan *c, ...) runtime·selectsend(Select *sel, Hchan *c, void *elem, bool selected)
{ {
// nil cases do not compete // nil cases do not compete
if(c == nil) if(c == nil)
return; return;
selectsend(&sel, c, runtime·getcallerpc(&sel)); selectsend(sel, c, runtime·getcallerpc(&sel), elem, (byte*)&selected - (byte*)&sel);
} }
static void static void
selectsend(Select **selp, Hchan *c, void *pc) selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so)
{ {
int32 i, eo; int32 i;
Scase *cas; Scase *cas;
byte *ae;
Select *sel;
sel = *selp;
i = sel->ncase; i = sel->ncase;
if(i >= sel->tcase) if(i >= sel->tcase)
runtime·throw("selectsend: too many cases"); runtime·throw("selectsend: too many cases");
sel->ncase = i+1; sel->ncase = i+1;
cas = runtime·mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem)); cas = &sel->scase[i];
sel->scase[i] = cas;
cas->pc = pc; cas->pc = pc;
cas->chan = c; cas->chan = c;
cas->so = so;
eo = runtime·rnd(sizeof(sel), sizeof(c));
eo = runtime·rnd(eo+sizeof(c), c->elemsize);
cas->so = runtime·rnd(eo+c->elemsize, Structrnd);
cas->kind = CaseSend; cas->kind = CaseSend;
cas->sg.elem = elem;
ae = (byte*)selp + eo;
c->elemalg->copy(c->elemsize, cas->u.elem, ae);
if(debug) if(debug)
runtime·printf("selectsend s=%p pc=%p chan=%p so=%d\n", runtime·printf("selectsend s=%p pc=%p chan=%p so=%d\n",
...@@ -713,15 +699,14 @@ selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool *received, int32 so ...@@ -713,15 +699,14 @@ selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool *received, int32 so
if(i >= sel->tcase) if(i >= sel->tcase)
runtime·throw("selectrecv: too many cases"); runtime·throw("selectrecv: too many cases");
sel->ncase = i+1; sel->ncase = i+1;
cas = runtime·mal(sizeof *cas); cas = &sel->scase[i];
sel->scase[i] = cas;
cas->pc = pc; cas->pc = pc;
cas->chan = c; cas->chan = c;
cas->so = so; cas->so = so;
cas->kind = CaseRecv; cas->kind = CaseRecv;
cas->u.recv.elemp = elem; cas->sg.elem = elem;
cas->u.recv.receivedp = received; cas->receivedp = received;
if(debug) if(debug)
runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d\n", runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d\n",
...@@ -749,8 +734,7 @@ selectdefault(Select *sel, void *callerpc, int32 so) ...@@ -749,8 +734,7 @@ selectdefault(Select *sel, void *callerpc, int32 so)
if(i >= sel->tcase) if(i >= sel->tcase)
runtime·throw("selectdefault: too many cases"); runtime·throw("selectdefault: too many cases");
sel->ncase = i+1; sel->ncase = i+1;
cas = runtime·mal(sizeof *cas); cas = &sel->scase[i];
sel->scase[i] = cas;
cas->pc = callerpc; cas->pc = callerpc;
cas->chan = nil; cas->chan = nil;
...@@ -762,26 +746,17 @@ selectdefault(Select *sel, void *callerpc, int32 so) ...@@ -762,26 +746,17 @@ selectdefault(Select *sel, void *callerpc, int32 so)
sel, cas->pc, cas->so); sel, cas->pc, cas->so);
} }
static void
freesel(Select *sel)
{
uint32 i;
for(i=0; i<sel->ncase; i++)
runtime·free(sel->scase[i]);
runtime·free(sel);
}
static void static void
sellock(Select *sel) sellock(Select *sel)
{ {
uint32 i; uint32 i;
Hchan *c; Hchan *c, *c0;
c = nil; c = nil;
for(i=0; i<sel->ncase; i++) { for(i=0; i<sel->ncase; i++) {
if(sel->scase[i]->chan != c) { c0 = sel->lockorder[i];
c = sel->scase[i]->chan; if(c0 && c0 != c) {
c = sel->lockorder[i];
runtime·lock(c); runtime·lock(c);
} }
} }
...@@ -791,12 +766,13 @@ static void ...@@ -791,12 +766,13 @@ static void
selunlock(Select *sel) selunlock(Select *sel)
{ {
uint32 i; uint32 i;
Hchan *c; Hchan *c, *c0;
c = nil; c = nil;
for(i=sel->ncase; i>0; i--) { for(i=sel->ncase; i-->0;) {
if(sel->scase[i-1]->chan && sel->scase[i-1]->chan != c) { c0 = sel->lockorder[i];
c = sel->scase[i-1]->chan; if(c0 && c0 != c) {
c = c0;
runtime·unlock(c); runtime·unlock(c);
} }
} }
...@@ -851,20 +827,20 @@ selectgo(Select **selp) ...@@ -851,20 +827,20 @@ selectgo(Select **selp)
// generate permuted order // generate permuted order
for(i=0; i<sel->ncase; i++) for(i=0; i<sel->ncase; i++)
sel->order[i] = i; sel->pollorder[i] = i;
for(i=1; i<sel->ncase; i++) { for(i=1; i<sel->ncase; i++) {
o = sel->order[i]; o = sel->pollorder[i];
j = runtime·fastrand1()%(i+1); j = runtime·fastrand1()%(i+1);
sel->order[i] = sel->order[j]; sel->pollorder[i] = sel->pollorder[j];
sel->order[j] = o; sel->pollorder[j] = o;
} }
// sort the cases by Hchan address to get the locking order. // sort the cases by Hchan address to get the locking order.
for(i=1; i<sel->ncase; i++) { for(i=0; i<sel->ncase; i++) {
cas = sel->scase[i]; c = sel->scase[i].chan;
for(j=i; j>0 && sel->scase[j-1]->chan >= cas->chan; j--) for(j=i; j>0 && sel->lockorder[j-1] >= c; j--)
sel->scase[j] = sel->scase[j-1]; sel->lockorder[j] = sel->lockorder[j-1];
sel->scase[j] = cas; sel->lockorder[j] = c;
} }
sellock(sel); sellock(sel);
...@@ -872,8 +848,8 @@ loop: ...@@ -872,8 +848,8 @@ loop:
// pass 1 - look for something already waiting // pass 1 - look for something already waiting
dfl = nil; dfl = nil;
for(i=0; i<sel->ncase; i++) { for(i=0; i<sel->ncase; i++) {
o = sel->order[i]; o = sel->pollorder[i];
cas = sel->scase[o]; cas = &sel->scase[o];
c = cas->chan; c = cas->chan;
switch(cas->kind) { switch(cas->kind) {
...@@ -882,7 +858,7 @@ loop: ...@@ -882,7 +858,7 @@ loop:
if(c->qcount > 0) if(c->qcount > 0)
goto asyncrecv; goto asyncrecv;
} else { } else {
sg = dequeue(&c->sendq, c); sg = dequeue(&c->sendq);
if(sg != nil) if(sg != nil)
goto syncrecv; goto syncrecv;
} }
...@@ -897,7 +873,7 @@ loop: ...@@ -897,7 +873,7 @@ loop:
if(c->qcount < c->dataqsiz) if(c->qcount < c->dataqsiz)
goto asyncsend; goto asyncsend;
} else { } else {
sg = dequeue(&c->recvq, c); sg = dequeue(&c->recvq);
if(sg != nil) if(sg != nil)
goto syncsend; goto syncsend;
} }
...@@ -918,20 +894,18 @@ loop: ...@@ -918,20 +894,18 @@ loop:
// pass 2 - enqueue on all chans // pass 2 - enqueue on all chans
for(i=0; i<sel->ncase; i++) { for(i=0; i<sel->ncase; i++) {
o = sel->order[i]; cas = &sel->scase[i];
cas = sel->scase[o];
c = cas->chan; c = cas->chan;
sg = allocsg(c); sg = &cas->sg;
sg->offset = o; sg->g = g;
sg->selgen = g->selgen;
switch(cas->kind) { switch(cas->kind) {
case CaseRecv: case CaseRecv:
sg->elem = cas->u.recv.elemp;
enqueue(&c->recvq, sg); enqueue(&c->recvq, sg);
break; break;
case CaseSend: case CaseSend:
sg->elem = cas->u.elem;
enqueue(&c->sendq, sg); enqueue(&c->sendq, sg);
break; break;
} }
...@@ -948,50 +922,48 @@ loop: ...@@ -948,50 +922,48 @@ loop:
// pass 3 - dequeue from unsuccessful chans // pass 3 - dequeue from unsuccessful chans
// otherwise they stack up on quiet channels // otherwise they stack up on quiet channels
for(i=0; i<sel->ncase; i++) { for(i=0; i<sel->ncase; i++) {
if(sg == nil || i != sg->offset) { cas = &sel->scase[i];
cas = sel->scase[i]; if(cas != (Scase*)sg) {
c = cas->chan; c = cas->chan;
if(cas->kind == CaseSend) if(cas->kind == CaseSend)
dequeueg(&c->sendq, c); dequeueg(&c->sendq);
else else
dequeueg(&c->recvq, c); dequeueg(&c->recvq);
} }
} }
if(sg == nil) if(sg == nil)
goto loop; goto loop;
o = sg->offset; cas = (Scase*)sg;
cas = sel->scase[o];
c = cas->chan; c = cas->chan;
if(c->dataqsiz > 0) if(c->dataqsiz > 0)
runtime·throw("selectgo: shouldnt happen"); runtime·throw("selectgo: shouldnt happen");
if(debug) if(debug)
runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d o=%d\n", runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
sel, c, cas, cas->kind, o); sel, c, cas, cas->kind);
if(cas->kind == CaseRecv) { if(cas->kind == CaseRecv) {
if(cas->u.recv.receivedp != nil) if(cas->receivedp != nil)
*cas->u.recv.receivedp = true; *cas->receivedp = true;
} }
freesg(c, sg);
selunlock(sel); selunlock(sel);
goto retc; goto retc;
asyncrecv: asyncrecv:
// can receive from buffer // can receive from buffer
if(cas->u.recv.receivedp != nil) if(cas->receivedp != nil)
*cas->u.recv.receivedp = true; *cas->receivedp = true;
if(cas->u.recv.elemp != nil) if(cas->sg.elem != nil)
c->elemalg->copy(c->elemsize, cas->u.recv.elemp, chanbuf(c, c->recvx)); c->elemalg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx));
c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil); c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
if(++c->recvx == c->dataqsiz) if(++c->recvx == c->dataqsiz)
c->recvx = 0; c->recvx = 0;
c->qcount--; c->qcount--;
sg = dequeue(&c->sendq, c); sg = dequeue(&c->sendq);
if(sg != nil) { if(sg != nil) {
gp = sg->g; gp = sg->g;
selunlock(sel); selunlock(sel);
...@@ -1003,11 +975,11 @@ asyncrecv: ...@@ -1003,11 +975,11 @@ asyncrecv:
asyncsend: asyncsend:
// can send to buffer // can send to buffer
c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), cas->u.elem); c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem);
if(++c->sendx == c->dataqsiz) if(++c->sendx == c->dataqsiz)
c->sendx = 0; c->sendx = 0;
c->qcount++; c->qcount++;
sg = dequeue(&c->recvq, c); sg = dequeue(&c->recvq);
if(sg != nil) { if(sg != nil) {
gp = sg->g; gp = sg->g;
selunlock(sel); selunlock(sel);
...@@ -1022,10 +994,10 @@ syncrecv: ...@@ -1022,10 +994,10 @@ syncrecv:
selunlock(sel); selunlock(sel);
if(debug) if(debug)
runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o); runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
if(cas->u.recv.receivedp != nil) if(cas->receivedp != nil)
*cas->u.recv.receivedp = true; *cas->receivedp = true;
if(cas->u.recv.elemp != nil) if(cas->sg.elem != nil)
c->elemalg->copy(c->elemsize, cas->u.recv.elemp, sg->elem); c->elemalg->copy(c->elemsize, cas->sg.elem, sg->elem);
gp = sg->g; gp = sg->g;
gp->param = sg; gp->param = sg;
runtime·ready(gp); runtime·ready(gp);
...@@ -1034,10 +1006,10 @@ syncrecv: ...@@ -1034,10 +1006,10 @@ syncrecv:
rclose: rclose:
// read at end of closed channel // read at end of closed channel
selunlock(sel); selunlock(sel);
if(cas->u.recv.receivedp != nil) if(cas->receivedp != nil)
*cas->u.recv.receivedp = false; *cas->receivedp = false;
if(cas->u.recv.elemp != nil) if(cas->sg.elem != nil)
c->elemalg->copy(c->elemsize, cas->u.recv.elemp, nil); c->elemalg->copy(c->elemsize, cas->sg.elem, nil);
goto retc; goto retc;
syncsend: syncsend:
...@@ -1045,8 +1017,7 @@ syncsend: ...@@ -1045,8 +1017,7 @@ syncsend:
selunlock(sel); selunlock(sel);
if(debug) if(debug)
runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o); runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
if(sg->elem != nil) c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem);
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
gp = sg->g; gp = sg->g;
gp->param = sg; gp->param = sg;
runtime·ready(gp); runtime·ready(gp);
...@@ -1055,7 +1026,7 @@ retc: ...@@ -1055,7 +1026,7 @@ retc:
// return to pc corresponding to chosen case // return to pc corresponding to chosen case
pc = cas->pc; pc = cas->pc;
as = (byte*)selp + cas->so; as = (byte*)selp + cas->so;
freesel(sel); runtime·free(sel);
*as = true; *as = true;
return pc; return pc;
...@@ -1086,7 +1057,7 @@ runtime·closechan(Hchan *c) ...@@ -1086,7 +1057,7 @@ runtime·closechan(Hchan *c)
// release all readers // release all readers
for(;;) { for(;;) {
sg = dequeue(&c->recvq, c); sg = dequeue(&c->recvq);
if(sg == nil) if(sg == nil)
break; break;
gp = sg->g; gp = sg->g;
...@@ -1096,7 +1067,7 @@ runtime·closechan(Hchan *c) ...@@ -1096,7 +1067,7 @@ runtime·closechan(Hchan *c)
// release all writers // release all writers
for(;;) { for(;;) {
sg = dequeue(&c->sendq, c); sg = dequeue(&c->sendq);
if(sg == nil) if(sg == nil)
break; break;
gp = sg->g; gp = sg->g;
...@@ -1140,7 +1111,7 @@ reflect·chancap(Hchan *c, int32 cap) ...@@ -1140,7 +1111,7 @@ reflect·chancap(Hchan *c, int32 cap)
} }
static SudoG* static SudoG*
dequeue(WaitQ *q, Hchan *c) dequeue(WaitQ *q)
{ {
SudoG *sgp; SudoG *sgp;
...@@ -1155,7 +1126,6 @@ loop: ...@@ -1155,7 +1126,6 @@ loop:
(sgp->selgen != sgp->g->selgen || (sgp->selgen != sgp->g->selgen ||
!runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) { !runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) {
//prints("INVALID PSEUDOG POINTER\n"); //prints("INVALID PSEUDOG POINTER\n");
freesg(c, sgp);
goto loop; goto loop;
} }
...@@ -1163,7 +1133,7 @@ loop: ...@@ -1163,7 +1133,7 @@ loop:
} }
static void static void
dequeueg(WaitQ *q, Hchan *c) dequeueg(WaitQ *q)
{ {
SudoG **l, *sgp, *prevsgp; SudoG **l, *sgp, *prevsgp;
...@@ -1171,7 +1141,6 @@ dequeueg(WaitQ *q, Hchan *c) ...@@ -1171,7 +1141,6 @@ dequeueg(WaitQ *q, Hchan *c)
for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) { for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) {
if(sgp->g == g) { if(sgp->g == g) {
*l = sgp->link; *l = sgp->link;
freesg(c, sgp);
if(q->last == sgp) if(q->last == sgp)
q->last = prevsgp; q->last = prevsgp;
break; break;
...@@ -1191,34 +1160,3 @@ enqueue(WaitQ *q, SudoG *sgp) ...@@ -1191,34 +1160,3 @@ enqueue(WaitQ *q, SudoG *sgp)
q->last->link = sgp; q->last->link = sgp;
q->last = sgp; q->last = sgp;
} }
static SudoG*
allocsg(Hchan *c)
{
SudoG* sg;
sg = c->free;
if(sg != nil) {
c->free = sg->link;
} else
sg = runtime·mal(sizeof(*sg));
sg->selgen = g->selgen;
sg->g = g;
sg->offset = 0;
sg->isfree = 0;
return sg;
}
static void
freesg(Hchan *c, SudoG *sg)
{
if(sg != nil) {
if(sg->isfree)
runtime·throw("chan.freesg: already free");
sg->isfree = 1;
sg->link = c->free;
sg->elem = nil;
c->free = sg;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment