ret = runtime·mal(n);
}
-// Stack allocator uses malloc/free most of the time,
-// but if we're in the middle of malloc and need stack,
-// we have to do something else to avoid deadlock.
-// In that case, we fall back on a fixed-size free-list
-// allocator, assuming that inside malloc all the stack
-// frames are small, so that all the stack allocations
-// will be a single size, the minimum (right now, 5k).
-static struct {
- Lock;
- FixAlloc;
-} stacks;
-
-enum {
- FixedStack = StackMin,
-};
-
void*
runtime·stackalloc(uint32 n)
{
void *v;
+ uintptr sys0;
// Stackalloc must be called on scheduler stack, so that we
// never try to grow the stack during the code that stackalloc runs.
if(g != m->g0)
runtime·throw("stackalloc not on scheduler stack");
+ // Stack allocator uses malloc/free most of the time,
+ // but if we're in the middle of malloc and need stack,
+ // we have to do something else to avoid deadlock.
+ // In that case, we fall back on a fixed-size free-list
+ // allocator, assuming that inside malloc all the stack
+ // frames are small, so that all the stack allocations
+ // will be a single size, the minimum (right now, 5k).
if(m->mallocing || m->gcing || n == FixedStack) {
- runtime·lock(&stacks);
- if(stacks.size == 0)
- runtime·FixAlloc_Init(&stacks, n, runtime·SysAlloc, nil, nil);
- if(stacks.size != n) {
- runtime·printf("stackalloc: in malloc, size=%D want %d", (uint64)stacks.size, n);
+ if(n != FixedStack) {
+ runtime·printf("stackalloc: in malloc, size=%d want %d", FixedStack, n);
runtime·throw("stackalloc");
}
- v = runtime·FixAlloc_Alloc(&stacks);
- mstats.stacks_inuse = stacks.inuse;
- mstats.stacks_sys = stacks.sys;
- runtime·unlock(&stacks);
+ sys0 = m->stackalloc->sys;
+ v = runtime·FixAlloc_Alloc(m->stackalloc);
+ mstats.stacks_inuse += FixedStack;
+ mstats.stacks_sys += m->stackalloc->sys - sys0;
return v;
}
return runtime·mallocgc(n, FlagNoProfiling|FlagNoGC, 0, 0);
void
runtime·stackfree(void *v, uintptr n)
{
+ uintptr sys0;
+
if(m->mallocing || m->gcing || n == FixedStack) {
- runtime·lock(&stacks);
- runtime·FixAlloc_Free(&stacks, v);
- mstats.stacks_inuse = stacks.inuse;
- mstats.stacks_sys = stacks.sys;
- runtime·unlock(&stacks);
+ sys0 = m->stackalloc->sys;
+ runtime·FixAlloc_Free(m->stackalloc, v);
+ mstats.stacks_inuse -= FixedStack;
+ mstats.stacks_sys += m->stackalloc->sys - sys0;
return;
}
runtime·free(v);
static void matchmg(void); // match ms to gs
static void readylocked(G*); // ready, but sched is locked
static void mnextg(M*, G*);
+static void mcommoninit(M*);
// The bootstrap sequence is:
//
int32 n;
byte *p;
- runtime·allm = m;
m->nomemprof++;
- m->fastrand = 0x49f6428aUL + m->id;
-
runtime·mallocinit();
+ mcommoninit(m);
+
runtime·goargs();
runtime·goenvs();
if(p != nil && (n = runtime·atoi(p)) != 0)
runtime·gomaxprocs = n;
runtime·sched.mcpumax = runtime·gomaxprocs;
- runtime·sched.mcount = 1;
runtime·sched.predawn = 1;
m->nomemprof--;
g->idlem = m;
}
+static void
+mcommoninit(M *m)
+{
+ m->alllink = runtime·allm;
+ runtime·allm = m;
+ m->id = runtime·sched.mcount++;
+ m->fastrand = 0x49f6428aUL + m->id;
+ m->stackalloc = runtime·malloc(sizeof(*m->stackalloc));
+ runtime·FixAlloc_Init(m->stackalloc, FixedStack, runtime·SysAlloc, nil, nil);
+}
+
// Put on `g' queue. Sched must be locked.
static void
gput(G *g)
m = runtime·malloc(sizeof(M));
// Add to runtime·allm so garbage collector doesn't free m
// when it is just in a register or thread-local storage.
- m->alllink = runtime·allm;
- runtime·allm = m;
- m->id = runtime·sched.mcount++;
- m->fastrand = 0x49f6428aUL + m->id;
+ mcommoninit(m);
if(runtime·iscgo) {
CgoThreadStart ts;
import (
"runtime"
+ "sync/atomic"
"testing"
)
stop <- true
runtime.GOMAXPROCS(maxprocs)
}
+
+func stackGrowthRecursive(i int) {
+ var pad [128]uint64
+ if i != 0 && pad[0] == 0 {
+ stackGrowthRecursive(i - 1)
+ }
+}
+
+func BenchmarkStackGrowth(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ stackGrowthRecursive(10)
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}