diff options
| author | Dmitriy Vyukov <dvyukov@google.com> | 2014-03-07 20:52:29 +0400 |
|---|---|---|
| committer | Dmitriy Vyukov <dvyukov@google.com> | 2014-03-07 20:52:29 +0400 |
| commit | 1a89e6388c3f1994da17a1d91a45920663db2af5 (patch) | |
| tree | b17c5bed1b1bee0e888c4f1e803019a22960c4a2 /src/pkg/runtime/proc.c | |
| parent | f946a7ca0971027a71e057c2650fdf63d54543e8 (diff) | |
| download | go-1a89e6388c3f1994da17a1d91a45920663db2af5.tar.xz | |
runtime: refactor and fix stack management code
There are at least 3 bugs:
1. g->stacksize accounting is broken during copystack/shrinkstack
2. stktop->free is not properly maintained during copystack/shrinkstack
3. stktop->free logic is broken:
we can have stktop->free==FixedStack,
and we will free it into stack cache,
but it actually comes from heap as the result of non-copying segment shrink
This shows as at least spurious races on race builders (maybe something else as well I don't know).
The idea behind the refactoring is to consolidate stacksize and
segment origin logic in stackalloc/stackfree.
Fixes #7490.
LGTM=rsc, khr
R=golang-codereviews, rsc, khr
CC=golang-codereviews
https://golang.org/cl/72440043
Diffstat (limited to 'src/pkg/runtime/proc.c')
| -rw-r--r-- | src/pkg/runtime/proc.c | 34 |
1 files changed, 22 insertions, 12 deletions
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index a99e56dde2..bf55912783 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -1727,7 +1727,13 @@ syscall·runtime_AfterFork(void) static void mstackalloc(G *gp) { - gp->param = runtime·stackalloc((uintptr)gp->param); + G *newg; + uintptr size; + + newg = (G*)gp->param; + size = newg->stacksize; + newg->stacksize = 0; + gp->param = runtime·stackalloc(newg, size); runtime·gogo(&gp->sched); } @@ -1747,20 +1753,19 @@ runtime·malg(int32 stacksize) if(stacksize >= 0) { if(g == m->g0) { // running on scheduler stack already. - stk = runtime·stackalloc(StackSystem + stacksize); + stk = runtime·stackalloc(newg, StackSystem + stacksize); } else { // have to call stackalloc on scheduler stack. - g->param = (void*)(StackSystem + stacksize); + newg->stacksize = StackSystem + stacksize; + g->param = newg; runtime·mcall(mstackalloc); stk = g->param; g->param = nil; } - newg->stacksize = StackSystem + stacksize; newg->stack0 = (uintptr)stk; newg->stackguard = (uintptr)stk + StackGuard; newg->stackguard0 = newg->stackguard; newg->stackbase = (uintptr)stk + StackSystem + stacksize - sizeof(Stktop); - runtime·memclr((byte*)newg->stackbase, sizeof(Stktop)); } return newg; } @@ -1883,14 +1888,20 @@ static void gfput(P *p, G *gp) { uintptr stksize; + Stktop *top; if(gp->stackguard - StackGuard != gp->stack0) runtime·throw("invalid stack in gfput"); stksize = gp->stackbase + sizeof(Stktop) - gp->stack0; - if(stksize != FixedStack) { + if(stksize != gp->stacksize) { + runtime·printf("runtime: bad stacksize, goroutine %D, remain=%d, last=%d\n", + gp->goid, (int32)gp->stacksize, (int32)stksize); + runtime·throw("gfput: bad stacksize"); + } + top = (Stktop*)gp->stackbase; + if(top->malloced) { // non-standard stack size - free it. - runtime·stackfree((void*)gp->stack0, stksize); - gp->stacksize = 0; + runtime·stackfree(gp, (void*)gp->stack0, top); gp->stack0 = 0; gp->stackguard = 0; gp->stackguard0 = 0; @@ -1941,19 +1952,18 @@ retry: if(gp->stack0 == 0) { // Stack was deallocated in gfput. Allocate a new one. if(g == m->g0) { - stk = runtime·stackalloc(FixedStack); + stk = runtime·stackalloc(gp, FixedStack); } else { - g->param = (void*)FixedStack; + gp->stacksize = FixedStack; + g->param = gp; runtime·mcall(mstackalloc); stk = g->param; g->param = nil; } - gp->stacksize = FixedStack; gp->stack0 = (uintptr)stk; gp->stackbase = (uintptr)stk + FixedStack - sizeof(Stktop); gp->stackguard = (uintptr)stk + StackGuard; gp->stackguard0 = gp->stackguard; - runtime·memclr((byte*)gp->stackbase, sizeof(Stktop)); } } return gp; |
