aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriy Vyukov <dvyukov@google.com>2011-08-16 16:53:02 -0400
committerRuss Cox <rsc@golang.org>2011-08-16 16:53:02 -0400
commita2677cf363f9d17b416795c621c6bd7de5dcd642 (patch)
tree919b438578afdce8d26a1e9e1fb2b5328761dd75
parent01dd57b3125892e0dc2054436f29cafb38b0a3ef (diff)
downloadgo-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.c12
-rw-r--r--src/pkg/runtime/proc.c5
-rw-r--r--src/pkg/runtime/runtime.h1
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;