diff options
author | Dmitriy Vyukov <dvyukov@google.com> | 2011-08-16 16:53:02 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2011-08-16 16:53:02 -0400 |
commit | a2677cf363f9d17b416795c621c6bd7de5dcd642 (patch) | |
tree | 919b438578afdce8d26a1e9e1fb2b5328761dd75 | |
parent | 01dd57b3125892e0dc2054436f29cafb38b0a3ef (diff) | |
download | go-a2677cf363f9d17b416795c621c6bd7de5dcd642.tar.gz go-a2677cf363f9d17b416795c621c6bd7de5dcd642.zip |
runtime: fix GC bitmap corruption
The corruption can occur when GOMAXPROCS
is changed from >1 to 1, since GOMAXPROCS=1
does not imply there is only 1 goroutine running,
other goroutines can still be not parked after
the change.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/4873050
-rw-r--r-- | src/pkg/runtime/mgc0.c | 12 | ||||
-rw-r--r-- | src/pkg/runtime/proc.c | 5 | ||||
-rw-r--r-- | src/pkg/runtime/runtime.h | 1 |
3 files changed, 12 insertions, 6 deletions
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 6325aadc67..78ea2aa2b9 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -737,11 +737,11 @@ runtime·markallocated(void *v, uintptr n, bool noptr) bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift); if(noptr) bits |= bitNoPointers<<shift; - if(runtime·gomaxprocs == 1) { + if(runtime·singleproc) { *b = bits; break; } else { - // gomaxprocs > 1: use atomic op + // more than one goroutine is potentially running: use atomic op if(runtime·casp((void**)b, (void*)obits, (void*)bits)) break; } @@ -767,11 +767,11 @@ runtime·markfreed(void *v, uintptr n) for(;;) { obits = *b; bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift); - if(runtime·gomaxprocs == 1) { + if(runtime·singleproc) { *b = bits; break; } else { - // gomaxprocs > 1: use atomic op + // more than one goroutine is potentially running: use atomic op if(runtime·casp((void**)b, (void*)obits, (void*)bits)) break; } @@ -878,11 +878,11 @@ runtime·setblockspecial(void *v) for(;;) { obits = *b; bits = obits | (bitSpecial<<shift); - if(runtime·gomaxprocs == 1) { + if(runtime·singleproc) { *b = bits; break; } else { - // gomaxprocs > 1: use atomic op + // more than one goroutine is potentially running: use atomic op if(runtime·casp((void**)b, (void*)obits, (void*)bits)) break; } diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 7a81591007..5f396b49f3 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -126,6 +126,7 @@ enum { Sched runtime·sched; int32 runtime·gomaxprocs; +bool runtime·singleproc; // An m that is waiting for notewakeup(&m->havenextg). This may be // only be accessed while the scheduler lock is held. This is used to @@ -199,6 +200,7 @@ runtime·schedinit(void) runtime·gomaxprocs = n; } setmcpumax(runtime·gomaxprocs); + runtime·singleproc = runtime·gomaxprocs == 1; runtime·sched.predawn = 1; m->nomemprof--; @@ -585,6 +587,7 @@ runtime·stoptheworld(void) runtime·notesleep(&runtime·sched.stopped); schedlock(); } + runtime·singleproc = runtime·gomaxprocs == 1; schedunlock(); } @@ -1416,6 +1419,8 @@ runtime·gomaxprocsfunc(int32 n) if(n > maxgomaxprocs) n = maxgomaxprocs; runtime·gomaxprocs = n; + if(runtime·gomaxprocs > 1) + runtime·singleproc = false; if(runtime·gcwaiting != 0) { if(atomic_mcpumax(runtime·sched.atomic) != 1) runtime·throw("invalid mcpumax during gc"); diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 00be565ce0..3c503e430b 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -383,6 +383,7 @@ extern String runtime·emptystring; G* runtime·allg; M* runtime·allm; extern int32 runtime·gomaxprocs; +extern bool runtime·singleproc; extern uint32 runtime·panicking; extern int32 runtime·gcwaiting; // gc is waiting to run int8* runtime·goos; |