summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/chan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/chan.c')
-rw-r--r--src/pkg/runtime/chan.c116
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)