diff options
Diffstat (limited to 'src/pkg/runtime/chan.c')
-rw-r--r-- | src/pkg/runtime/chan.c | 116 |
1 files changed, 66 insertions, 50 deletions
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c index fba36a4c3..48cc41e20 100644 --- a/src/pkg/runtime/chan.c +++ b/src/pkg/runtime/chan.c @@ -7,12 +7,11 @@ #include "type.h" #include "race.h" #include "malloc.h" +#include "../../cmd/ld/textflag.h" -#define MAXALIGN 7 +#define MAXALIGN 8 #define NOSELGEN 1 -static int32 debug = 0; - typedef struct WaitQ WaitQ; typedef struct SudoG SudoG; typedef struct Select Select; @@ -40,8 +39,8 @@ struct Hchan uintgo qcount; // total data in the q uintgo dataqsiz; // size of the circular q uint16 elemsize; + uint16 pad; // ensures proper alignment of the buffer that follows Hchan in memory bool closed; - uint8 elemalign; Alg* elemalg; // interface for element type uintgo sendx; // send index uintgo recvx; // receive index @@ -58,6 +57,8 @@ uint32 runtime·Hchansize = sizeof(Hchan); enum { + debug = 0, + // Scase.kind CaseRecv, CaseSend, @@ -93,7 +94,6 @@ Hchan* runtime·makechan_c(ChanType *t, int64 hint) { Hchan *c; - uintptr n; Type *elem; elem = t->elem; @@ -101,26 +101,21 @@ runtime·makechan_c(ChanType *t, int64 hint) // compiler checks this but be safe. if(elem->size >= (1<<16)) runtime·throw("makechan: invalid channel element type"); + if((sizeof(*c)%MAXALIGN) != 0 || elem->align > MAXALIGN) + runtime·throw("makechan: bad alignment"); if(hint < 0 || (intgo)hint != hint || (elem->size > 0 && hint > MaxMem / elem->size)) runtime·panicstring("makechan: size out of range"); - // calculate rounded size of Hchan - n = sizeof(*c); - while(n & MAXALIGN) - n++; - // allocate memory in one call - c = (Hchan*)runtime·mal(n + hint*elem->size); + c = (Hchan*)runtime·mallocgc(sizeof(*c) + hint*elem->size, (uintptr)t | TypeInfo_Chan, 0); c->elemsize = elem->size; c->elemalg = elem->alg; - c->elemalign = elem->align; c->dataqsiz = hint; - runtime·settype(c, (uintptr)t | TypeInfo_Chan); if(debug) - runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; elemalign=%d; dataqsiz=%D\n", - c, (int64)elem->size, elem->alg, elem->align, (int64)c->dataqsiz); + runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; dataqsiz=%D\n", + c, (int64)elem->size, elem->alg, (int64)c->dataqsiz); return c; } @@ -174,9 +169,6 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc) return; // not reached } - if(runtime·gcwaiting) - runtime·gosched(); - if(debug) { runtime·printf("chansend: chan=%p; elem=", c); c->elemalg->print(c->elemsize, ep); @@ -191,7 +183,6 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc) } runtime·lock(c); - // TODO(dvyukov): add similar instrumentation to select. if(raceenabled) runtime·racereadpc(c, pc, runtime·chansend); if(c->closed) @@ -301,9 +292,6 @@ runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *receive G *gp; int64 t0; - if(runtime·gcwaiting) - runtime·gosched(); - if(debug) runtime·printf("chanrecv: chan=%p\n", c); @@ -443,7 +431,7 @@ closed: } // chansend1(hchan *chan any, elem any); -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·chansend1(ChanType *t, Hchan* c, ...) { @@ -451,7 +439,7 @@ runtime·chansend1(ChanType *t, Hchan* c, ...) } // chanrecv1(hchan *chan any) (elem any); -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·chanrecv1(ChanType *t, Hchan* c, ...) { @@ -459,7 +447,7 @@ runtime·chanrecv1(ChanType *t, Hchan* c, ...) } // chanrecv2(hchan *chan any) (elem any, received bool); -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·chanrecv2(ChanType *t, Hchan* c, ...) { @@ -489,7 +477,7 @@ runtime·chanrecv2(ChanType *t, Hchan* c, ...) // ... bar // } // -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·selectnbsend(ChanType *t, Hchan *c, ...) { @@ -519,7 +507,7 @@ runtime·selectnbsend(ChanType *t, Hchan *c, ...) // ... bar // } // -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·selectnbrecv(ChanType *t, byte *v, Hchan *c, bool selected) { @@ -545,7 +533,7 @@ runtime·selectnbrecv(ChanType *t, byte *v, Hchan *c, bool selected) // ... bar // } // -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·selectnbrecv2(ChanType *t, byte *v, bool *received, Hchan *c, bool selected) { @@ -559,7 +547,7 @@ runtime·selectnbrecv2(ChanType *t, byte *v, bool *received, Hchan *c, bool sele // // The "uintptr selected" is really "bool selected" but saying // uintptr gets us the right alignment for the output parameter block. -#pragma textflag 7 +#pragma textflag NOSPLIT void reflect·chansend(ChanType *t, Hchan *c, uintptr val, bool nb, uintptr selected) { @@ -615,7 +603,7 @@ reflect·chanrecv(ChanType *t, Hchan *c, bool nb, uintptr val, bool selected, bo static void newselect(int32, Select**); // newselect(size uint32) (sel *byte); -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·newselect(int32 size, ...) { @@ -660,7 +648,7 @@ newselect(int32 size, Select **selp) static void selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so); // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·selectsend(Select *sel, Hchan *c, void *elem, bool selected) { @@ -701,7 +689,7 @@ selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so) static void selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool*, int32 so); // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·selectrecv(Select *sel, Hchan *c, void *elem, bool selected) { @@ -716,7 +704,7 @@ runtime·selectrecv(Select *sel, Hchan *c, void *elem, bool selected) } // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool); -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, bool selected) { @@ -758,7 +746,7 @@ selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool *received, int32 so static void selectdefault(Select*, void*, int32); // selectdefault(sel *byte) (selected bool); -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·selectdefault(Select *sel, bool selected) { @@ -845,7 +833,7 @@ static void* selectgo(Select**); // // overwrites return pc on stack to signal which case of the select // to run, so cannot appear at the top of a split stack. -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·selectgo(Select *sel) { @@ -857,6 +845,7 @@ selectgo(Select **selp) { Select *sel; uint32 o, i, j, k; + int64 t0; Scase *cas, *dfl; Hchan *c; SudoG *sg; @@ -865,12 +854,17 @@ selectgo(Select **selp) void *pc; sel = *selp; - if(runtime·gcwaiting) - runtime·gosched(); if(debug) runtime·printf("select: sel=%p\n", sel); + t0 = 0; + if(runtime·blockprofilerate > 0) { + t0 = runtime·cputicks(); + for(i=0; i<sel->ncase; i++) + sel->scase[i].sg.releasetime = -1; + } + // The compiler rewrites selects that statically have // only 0 or 1 cases plus default into simpler constructs. // The only way we can end up with such small sel->ncase @@ -951,6 +945,8 @@ loop: break; case CaseSend: + if(raceenabled) + runtime·racereadpc(c, cas->pc, runtime·chansend); if(c->closed) goto sclose; if(c->dataqsiz > 0) { @@ -1052,6 +1048,8 @@ asyncrecv: if(sg != nil) { gp = sg->g; selunlock(sel); + if(sg->releasetime) + sg->releasetime = runtime·cputicks(); runtime·ready(gp); } else { selunlock(sel); @@ -1070,6 +1068,8 @@ asyncsend: if(sg != nil) { gp = sg->g; selunlock(sel); + if(sg->releasetime) + sg->releasetime = runtime·cputicks(); runtime·ready(gp); } else { selunlock(sel); @@ -1089,6 +1089,8 @@ syncrecv: c->elemalg->copy(c->elemsize, cas->sg.elem, sg->elem); gp = sg->g; gp->param = sg; + if(sg->releasetime) + sg->releasetime = runtime·cputicks(); runtime·ready(gp); goto retc; @@ -1114,6 +1116,8 @@ syncsend: c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem); gp = sg->g; gp->param = sg; + if(sg->releasetime) + sg->releasetime = runtime·cputicks(); runtime·ready(gp); retc: @@ -1127,6 +1131,8 @@ retc: as = (byte*)selp + cas->so; *as = true; } + if(cas->sg.releasetime > 0) + runtime·blockevent(cas->sg.releasetime - t0, 2); runtime·free(sel); return pc; @@ -1218,20 +1224,34 @@ reflect·rselect(Slice cases, intgo chosen, uintptr word, bool recvOK) FLUSH(&recvOK); } +static void closechan(Hchan *c, void *pc); + // closechan(sel *byte); -#pragma textflag 7 +#pragma textflag NOSPLIT void runtime·closechan(Hchan *c) { + closechan(c, runtime·getcallerpc(&c)); +} + +// For reflect +// func chanclose(c chan) +#pragma textflag NOSPLIT +void +reflect·chanclose(Hchan *c) +{ + closechan(c, runtime·getcallerpc(&c)); +} + +static void +closechan(Hchan *c, void *pc) +{ SudoG *sg; G* gp; if(c == nil) runtime·panicstring("close of nil channel"); - if(runtime·gcwaiting) - runtime·gosched(); - runtime·lock(c); if(c->closed) { runtime·unlock(c); @@ -1239,7 +1259,7 @@ runtime·closechan(Hchan *c) } if(raceenabled) { - runtime·racewritepc(c, runtime·getcallerpc(&c), runtime·closechan); + runtime·racewritepc(c, pc, runtime·closechan); runtime·racerelease(c); } @@ -1252,6 +1272,8 @@ runtime·closechan(Hchan *c) break; gp = sg->g; gp->param = nil; + if(sg->releasetime) + sg->releasetime = runtime·cputicks(); runtime·ready(gp); } @@ -1262,6 +1284,8 @@ runtime·closechan(Hchan *c) break; gp = sg->g; gp->param = nil; + if(sg->releasetime) + sg->releasetime = runtime·cputicks(); runtime·ready(gp); } @@ -1269,14 +1293,6 @@ runtime·closechan(Hchan *c) } // For reflect -// func chanclose(c chan) -void -reflect·chanclose(Hchan *c) -{ - runtime·closechan(c); -} - -// For reflect // func chanlen(c chan) (len int) void reflect·chanlen(Hchan *c, intgo len) |