aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime/proc.c
diff options
context:
space:
mode:
authorDmitriy Vyukov <dvyukov@google.com>2014-03-07 20:52:29 +0400
committerDmitriy Vyukov <dvyukov@google.com>2014-03-07 20:52:29 +0400
commit1a89e6388c3f1994da17a1d91a45920663db2af5 (patch)
treeb17c5bed1b1bee0e888c4f1e803019a22960c4a2 /src/pkg/runtime/proc.c
parentf946a7ca0971027a71e057c2650fdf63d54543e8 (diff)
downloadgo-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.c34
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;