diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-01-17 12:40:45 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-01-17 12:40:45 +0100 |
commit | 3e45412327a2654a77944249962b3652e6142299 (patch) | |
tree | bc3bf69452afa055423cbe0c5cfa8ca357df6ccf /src/pkg/runtime/chan.c | |
parent | c533680039762cacbc37db8dc7eed074c3e497be (diff) | |
download | golang-3e45412327a2654a77944249962b3652e6142299.tar.gz |
Imported Upstream version 2011.01.12upstream/2011.01.12
Diffstat (limited to 'src/pkg/runtime/chan.c')
-rw-r--r-- | src/pkg/runtime/chan.c | 294 |
1 files changed, 157 insertions, 137 deletions
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c index 08cd75a6e..94ea513e7 100644 --- a/src/pkg/runtime/chan.c +++ b/src/pkg/runtime/chan.c @@ -90,24 +90,24 @@ static uint32 fastrand2(void); static void destroychan(Hchan*); Hchan* -makechan(Type *elem, int64 hint) +runtime·makechan_c(Type *elem, int64 hint) { Hchan *c; int32 i; if(hint < 0 || (int32)hint != hint || hint > ((uintptr)-1) / elem->size) - panicstring("makechan: size out of range"); + runtime·panicstring("makechan: size out of range"); - if(elem->alg >= nelem(algarray)) { - printf("chan(alg=%d)\n", elem->alg); - throw("runtime.makechan: unsupported elem type"); + if(elem->alg >= nelem(runtime·algarray)) { + runtime·printf("chan(alg=%d)\n", elem->alg); + runtime·throw("runtime.makechan: unsupported elem type"); } - c = mal(sizeof(*c)); - addfinalizer(c, destroychan, 0); + c = runtime·mal(sizeof(*c)); + runtime·addfinalizer(c, destroychan, 0); c->elemsize = elem->size; - c->elemalg = &algarray[elem->alg]; + c->elemalg = &runtime·algarray[elem->alg]; c->elemalign = elem->align; if(hint > 0) { @@ -117,7 +117,7 @@ makechan(Type *elem, int64 hint) b = nil; e = nil; for(i=0; i<hint; i++) { - d = mal(sizeof(*d) + c->elemsize - sizeof(d->elem)); + d = runtime·mal(sizeof(*d) + c->elemsize - sizeof(d->elem)); if(e == nil) e = d; d->link = b; @@ -131,7 +131,7 @@ makechan(Type *elem, int64 hint) } if(debug) - printf("makechan: chan=%p; elemsize=%D; elemalg=%d; elemalign=%d; dataqsiz=%d\n", + runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%d; elemalign=%d; dataqsiz=%d\n", c, (int64)elem->size, elem->alg, elem->align, c->dataqsiz); return c; @@ -140,15 +140,15 @@ makechan(Type *elem, int64 hint) static void destroychan(Hchan *c) { - destroylock(&c->Lock); + runtime·destroylock(&c->Lock); } // makechan(elem *Type, hint int64) (hchan *chan any); void -·makechan(Type *elem, int64 hint, Hchan *ret) +runtime·makechan(Type *elem, int64 hint, Hchan *ret) { - ret = makechan(elem, hint); + ret = runtime·makechan_c(elem, hint); FLUSH(&ret); } @@ -158,7 +158,7 @@ incerr(Hchan* c) c->closed += Eincr; if(c->closed & Emax) { // Note that channel locks may still be held at this point. - throw("too many operations on a closed channel"); + runtime·throw("too many operations on a closed channel"); } } @@ -177,21 +177,24 @@ incerr(Hchan* c) * the operation; we'll see that it's now closed. */ void -chansend(Hchan *c, byte *ep, bool *pres) +runtime·chansend(Hchan *c, byte *ep, bool *pres) { SudoG *sg; G* gp; - if(gcwaiting) - gosched(); + if(c == nil) + runtime·panicstring("send to nil channel"); + + if(runtime·gcwaiting) + runtime·gosched(); if(debug) { - printf("chansend: chan=%p; elem=", c); + runtime·printf("chansend: chan=%p; elem=", c); c->elemalg->print(c->elemsize, ep); - prints("\n"); + runtime·prints("\n"); } - lock(c); + runtime·lock(c); loop: if(c->closed & Wclosed) goto closed; @@ -206,8 +209,8 @@ loop: gp = sg->g; gp->param = sg; - unlock(c); - ready(gp); + runtime·unlock(c); + runtime·ready(gp); if(pres != nil) *pres = true; @@ -215,7 +218,7 @@ loop: } if(pres != nil) { - unlock(c); + runtime·unlock(c); *pres = false; return; } @@ -226,15 +229,15 @@ loop: g->param = nil; g->status = Gwaiting; enqueue(&c->sendq, sg); - unlock(c); - gosched(); + runtime·unlock(c); + runtime·gosched(); - lock(c); + runtime·lock(c); sg = g->param; if(sg == nil) goto loop; freesg(c, sg); - unlock(c); + runtime·unlock(c); return; asynch: @@ -243,17 +246,17 @@ asynch: if(c->qcount >= c->dataqsiz) { if(pres != nil) { - unlock(c); + runtime·unlock(c); *pres = false; return; } sg = allocsg(c); g->status = Gwaiting; enqueue(&c->sendq, sg); - unlock(c); - gosched(); + runtime·unlock(c); + runtime·gosched(); - lock(c); + runtime·lock(c); goto asynch; } if(ep != nil) @@ -265,10 +268,10 @@ asynch: if(sg != nil) { gp = sg->g; freesg(c, sg); - unlock(c); - ready(gp); + runtime·unlock(c); + runtime·ready(gp); } else - unlock(c); + runtime·unlock(c); if(pres != nil) *pres = true; return; @@ -277,22 +280,25 @@ closed: incerr(c); if(pres != nil) *pres = true; - unlock(c); + runtime·unlock(c); } void -chanrecv(Hchan* c, byte *ep, bool* pres) +runtime·chanrecv(Hchan* c, byte *ep, bool* pres) { SudoG *sg; G *gp; - if(gcwaiting) - gosched(); + if(c == nil) + runtime·panicstring("receive from nil channel"); + + if(runtime·gcwaiting) + runtime·gosched(); if(debug) - printf("chanrecv: chan=%p\n", c); + runtime·printf("chanrecv: chan=%p\n", c); - lock(c); + runtime·lock(c); loop: if(c->dataqsiz > 0) goto asynch; @@ -307,8 +313,8 @@ loop: gp = sg->g; gp->param = sg; - unlock(c); - ready(gp); + runtime·unlock(c); + runtime·ready(gp); if(pres != nil) *pres = true; @@ -316,7 +322,7 @@ loop: } if(pres != nil) { - unlock(c); + runtime·unlock(c); c->elemalg->copy(c->elemsize, ep, nil); *pres = false; return; @@ -326,10 +332,10 @@ loop: g->param = nil; g->status = Gwaiting; enqueue(&c->recvq, sg); - unlock(c); - gosched(); + runtime·unlock(c); + runtime·gosched(); - lock(c); + runtime·lock(c); sg = g->param; if(sg == nil) goto loop; @@ -337,7 +343,7 @@ loop: c->elemalg->copy(c->elemsize, ep, sg->elem); c->elemalg->copy(c->elemsize, sg->elem, nil); freesg(c, sg); - unlock(c); + runtime·unlock(c); return; asynch: @@ -346,7 +352,7 @@ asynch: goto closed; if(pres != nil) { - unlock(c); + runtime·unlock(c); c->elemalg->copy(c->elemsize, ep, nil); *pres = false; return; @@ -354,10 +360,10 @@ asynch: sg = allocsg(c); g->status = Gwaiting; enqueue(&c->recvq, sg); - unlock(c); - gosched(); + runtime·unlock(c); + runtime·gosched(); - lock(c); + runtime·lock(c); goto asynch; } c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem); @@ -368,14 +374,14 @@ asynch: if(sg != nil) { gp = sg->g; freesg(c, sg); - unlock(c); - ready(gp); + runtime·unlock(c); + runtime·ready(gp); if(pres != nil) *pres = true; return; } - unlock(c); + runtime·unlock(c); if(pres != nil) *pres = true; return; @@ -386,96 +392,102 @@ closed: incerr(c); if(pres != nil) *pres = true; - unlock(c); + runtime·unlock(c); } // chansend1(hchan *chan any, elem any); #pragma textflag 7 void -·chansend1(Hchan* c, ...) +runtime·chansend1(Hchan* c, ...) { int32 o; byte *ae; - o = rnd(sizeof(c), c->elemalign); + if(c == nil) + runtime·panicstring("send to nil channel"); + + o = runtime·rnd(sizeof(c), c->elemalign); ae = (byte*)&c + o; - chansend(c, ae, nil); + runtime·chansend(c, ae, nil); } // chansend2(hchan *chan any, elem any) (pres bool); #pragma textflag 7 void -·chansend2(Hchan* c, ...) +runtime·chansend2(Hchan* c, ...) { int32 o; byte *ae, *ap; - o = rnd(sizeof(c), c->elemalign); + if(c == nil) + runtime·panicstring("send to nil channel"); + + o = runtime·rnd(sizeof(c), c->elemalign); ae = (byte*)&c + o; - o = rnd(o+c->elemsize, Structrnd); + o = runtime·rnd(o+c->elemsize, Structrnd); ap = (byte*)&c + o; - chansend(c, ae, ap); + runtime·chansend(c, ae, ap); } // chanrecv1(hchan *chan any) (elem any); #pragma textflag 7 void -·chanrecv1(Hchan* c, ...) +runtime·chanrecv1(Hchan* c, ...) { int32 o; byte *ae; - o = rnd(sizeof(c), Structrnd); + o = runtime·rnd(sizeof(c), Structrnd); ae = (byte*)&c + o; - chanrecv(c, ae, nil); + runtime·chanrecv(c, ae, nil); } // chanrecv2(hchan *chan any) (elem any, pres bool); #pragma textflag 7 void -·chanrecv2(Hchan* c, ...) +runtime·chanrecv2(Hchan* c, ...) { int32 o; byte *ae, *ap; - o = rnd(sizeof(c), Structrnd); + o = runtime·rnd(sizeof(c), Structrnd); ae = (byte*)&c + o; - o = rnd(o+c->elemsize, 1); + o = runtime·rnd(o+c->elemsize, 1); ap = (byte*)&c + o; - chanrecv(c, ae, ap); + runtime·chanrecv(c, ae, ap); } // newselect(size uint32) (sel *byte); #pragma textflag 7 void -·newselect(int32 size, ...) +runtime·newselect(int32 size, ...) { int32 n, o; Select **selp; Select *sel; - o = rnd(sizeof(size), Structrnd); + o = runtime·rnd(sizeof(size), Structrnd); selp = (Select**)((byte*)&size + o); n = 0; if(size > 1) n = size-1; - sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0])); + sel = runtime·mal(sizeof(*sel) + n*sizeof(sel->scase[0])); sel->tcase = size; sel->ncase = 0; *selp = sel; if(debug) - printf("newselect s=%p size=%d\n", sel, size); + runtime·printf("newselect s=%p size=%d\n", sel, size); } // selectsend(sel *byte, hchan *chan any, elem any) (selected bool); #pragma textflag 7 void -·selectsend(Select *sel, Hchan *c, ...) +runtime·selectsend(Select *sel, Hchan *c, ...) { int32 i, eo; Scase *cas; @@ -487,31 +499,31 @@ void i = sel->ncase; if(i >= sel->tcase) - throw("selectsend: too many cases"); + runtime·throw("selectsend: too many cases"); sel->ncase = i+1; - cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem)); + cas = runtime·mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem)); sel->scase[i] = cas; - cas->pc = ·getcallerpc(&sel); + cas->pc = runtime·getcallerpc(&sel); cas->chan = c; - eo = rnd(sizeof(sel), sizeof(c)); - eo = rnd(eo+sizeof(c), c->elemsize); - cas->so = rnd(eo+c->elemsize, Structrnd); + eo = runtime·rnd(sizeof(sel), sizeof(c)); + eo = runtime·rnd(eo+sizeof(c), c->elemsize); + cas->so = runtime·rnd(eo+c->elemsize, Structrnd); cas->send = 1; ae = (byte*)&sel + eo; c->elemalg->copy(c->elemsize, cas->u.elem, ae); if(debug) - printf("selectsend s=%p pc=%p chan=%p so=%d send=%d\n", + runtime·printf("selectsend s=%p pc=%p chan=%p so=%d send=%d\n", sel, cas->pc, cas->chan, cas->so, cas->send); } // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); #pragma textflag 7 void -·selectrecv(Select *sel, Hchan *c, ...) +runtime·selectrecv(Select *sel, Hchan *c, ...) { int32 i, eo; Scase *cas; @@ -522,21 +534,21 @@ void i = sel->ncase; if(i >= sel->tcase) - throw("selectrecv: too many cases"); + runtime·throw("selectrecv: too many cases"); sel->ncase = i+1; - cas = mal(sizeof *cas); + cas = runtime·mal(sizeof *cas); sel->scase[i] = cas; - cas->pc = ·getcallerpc(&sel); + cas->pc = runtime·getcallerpc(&sel); cas->chan = c; - eo = rnd(sizeof(sel), sizeof(c)); - eo = rnd(eo+sizeof(c), sizeof(byte*)); - cas->so = rnd(eo+sizeof(byte*), Structrnd); + eo = runtime·rnd(sizeof(sel), sizeof(c)); + eo = runtime·rnd(eo+sizeof(c), sizeof(byte*)); + cas->so = runtime·rnd(eo+sizeof(byte*), Structrnd); cas->send = 0; cas->u.elemp = *(byte**)((byte*)&sel + eo); if(debug) - printf("selectrecv s=%p pc=%p chan=%p so=%d send=%d\n", + runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d send=%d\n", sel, cas->pc, cas->chan, cas->so, cas->send); } @@ -544,26 +556,26 @@ void // selectdefaul(sel *byte) (selected bool); #pragma textflag 7 void -·selectdefault(Select *sel, ...) +runtime·selectdefault(Select *sel, ...) { int32 i; Scase *cas; i = sel->ncase; if(i >= sel->tcase) - throw("selectdefault: too many cases"); + runtime·throw("selectdefault: too many cases"); sel->ncase = i+1; - cas = mal(sizeof *cas); + cas = runtime·mal(sizeof *cas); sel->scase[i] = cas; - cas->pc = ·getcallerpc(&sel); + cas->pc = runtime·getcallerpc(&sel); cas->chan = nil; - cas->so = rnd(sizeof(sel), Structrnd); + cas->so = runtime·rnd(sizeof(sel), Structrnd); cas->send = 2; cas->u.elemp = nil; if(debug) - printf("selectdefault s=%p pc=%p so=%d send=%d\n", + runtime·printf("selectdefault s=%p pc=%p so=%d send=%d\n", sel, cas->pc, cas->so, cas->send); } @@ -573,8 +585,8 @@ freesel(Select *sel) uint32 i; for(i=0; i<sel->ncase; i++) - free(sel->scase[i]); - free(sel); + runtime·free(sel->scase[i]); + runtime·free(sel); } static void @@ -587,7 +599,7 @@ sellock(Select *sel) for(i=0; i<sel->ncase; i++) { if(sel->scase[i]->chan != c) { c = sel->scase[i]->chan; - lock(c); + runtime·lock(c); } } } @@ -602,14 +614,20 @@ selunlock(Select *sel) 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); + runtime·unlock(c); } } } // selectgo(sel *byte); +// +// overwrites return pc on stack to signal which case of the select +// to run, so cannot appear at the top of a split stack. +// frame has 6 pointers and 4 int32 so 64 bytes max. +// that's less than StackGuard-StackSmall, so okay. +#pragma textflag 7 void -·selectgo(Select *sel) +runtime·selectgo(Select *sel) { uint32 p, o, i, j; Scase *cas, *dfl; @@ -618,16 +636,18 @@ void G *gp; byte *as; - if(gcwaiting) - gosched(); + if(runtime·gcwaiting) + runtime·gosched(); if(debug) - printf("select: sel=%p\n", sel); + runtime·printf("select: sel=%p\n", sel); if(sel->ncase < 2) { - if(sel->ncase < 1) - throw("select: no cases"); - // make special case of one. + if(sel->ncase < 1) { + g->status = Gwaiting; // forever + runtime·gosched(); + } + // TODO: make special case of one. } // select a (relative) prime @@ -636,7 +656,7 @@ void if(gcd(p, sel->ncase) == 1) break; if(i > 1000) - throw("select: failed to select prime"); + runtime·throw("select: failed to select prime"); } // select an initial offset @@ -716,10 +736,10 @@ loop: case 0: // recv if(c->dataqsiz > 0) { if(c->qcount > 0) - throw("select: pass 2 async recv"); + runtime·throw("select: pass 2 async recv"); } else { if(dequeue(&c->sendq, c)) - throw("select: pass 2 sync recv"); + runtime·throw("select: pass 2 sync recv"); } enqueue(&c->recvq, sg); break; @@ -727,10 +747,10 @@ loop: case 1: // send if(c->dataqsiz > 0) { if(c->qcount < c->dataqsiz) - throw("select: pass 2 async send"); + runtime·throw("select: pass 2 async send"); } else { if(dequeue(&c->recvq, c)) - throw("select: pass 2 sync send"); + runtime·throw("select: pass 2 sync send"); c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); } enqueue(&c->sendq, sg); @@ -745,7 +765,7 @@ loop: g->param = nil; g->status = Gwaiting; selunlock(sel); - gosched(); + runtime·gosched(); sellock(sel); sg = g->param; @@ -780,7 +800,7 @@ loop: } if(debug) - printf("wait-return: sel=%p c=%p cas=%p send=%d o=%d\n", + runtime·printf("wait-return: sel=%p c=%p cas=%p send=%d o=%d\n", sel, c, cas, cas->send, o); if(!cas->send) { @@ -803,7 +823,7 @@ asyncrecv: if(sg != nil) { gp = sg->g; freesg(c, sg); - ready(gp); + runtime·ready(gp); } goto retc; @@ -817,20 +837,20 @@ asyncsend: if(sg != nil) { gp = sg->g; freesg(c, sg); - ready(gp); + runtime·ready(gp); } goto retc; syncrecv: // can receive from sleeping sender (sg) if(debug) - 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.elemp != nil) c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem); c->elemalg->copy(c->elemsize, sg->elem, nil); gp = sg->g; gp->param = sg; - ready(gp); + runtime·ready(gp); goto retc; rclose: @@ -844,13 +864,13 @@ rclose: syncsend: // can send to sleeping receiver (sg) if(debug) - 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(c->closed & Wclosed) goto sclose; c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); gp = sg->g; gp->param = sg; - ready(gp); + runtime·ready(gp); goto retc; sclose: @@ -862,7 +882,7 @@ retc: selunlock(sel); // return to pc corresponding to chosen case - ·setcallerpc(&sel, cas->pc); + runtime·setcallerpc(&sel, cas->pc); as = (byte*)&sel + cas->so; freesel(sel); *as = true; @@ -870,15 +890,15 @@ retc: // closechan(sel *byte); void -·closechan(Hchan *c) +runtime·closechan(Hchan *c) { SudoG *sg; G* gp; - if(gcwaiting) - gosched(); + if(runtime·gcwaiting) + runtime·gosched(); - lock(c); + runtime·lock(c); incerr(c); c->closed |= Wclosed; @@ -890,7 +910,7 @@ void gp = sg->g; gp->param = nil; freesg(c, sg); - ready(gp); + runtime·ready(gp); } // release all writers @@ -901,32 +921,32 @@ void gp = sg->g; gp->param = nil; freesg(c, sg); - ready(gp); + runtime·ready(gp); } - unlock(c); + runtime·unlock(c); } void -chanclose(Hchan *c) +runtime·chanclose(Hchan *c) { - ·closechan(c); + runtime·closechan(c); } bool -chanclosed(Hchan *c) +runtime·chanclosed(Hchan *c) { return (c->closed & Rclosed) != 0; } int32 -chanlen(Hchan *c) +runtime·chanlen(Hchan *c) { return c->qcount; } int32 -chancap(Hchan *c) +runtime·chancap(Hchan *c) { return c->dataqsiz; } @@ -934,9 +954,9 @@ chancap(Hchan *c) // closedchan(sel *byte) bool; void -·closedchan(Hchan *c, bool closed) +runtime·closedchan(Hchan *c, bool closed) { - closed = chanclosed(c); + closed = runtime·chanclosed(c); FLUSH(&closed); } @@ -952,7 +972,7 @@ loop: q->first = sgp->link; // if sgp is stale, ignore it - if(!cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 1)) { + if(!runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 1)) { //prints("INVALID PSEUDOG POINTER\n"); freesg(c, sgp); goto loop; @@ -997,7 +1017,7 @@ allocsg(Hchan *c) if(sg != nil) { c->free = sg->link; } else - sg = mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem)); + sg = runtime·mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem)); sg->selgen = g->selgen; sg->g = g; sg->offset = 0; @@ -1011,7 +1031,7 @@ freesg(Hchan *c, SudoG *sg) { if(sg != nil) { if(sg->isfree) - throw("chan.freesg: already free"); + runtime·throw("chan.freesg: already free"); sg->isfree = 1; sg->link = c->free; c->free = sg; |