Commit a2677cf3 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov Committed by Russ Cox

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
parent 01dd57b3
...@@ -737,11 +737,11 @@ runtime·markallocated(void *v, uintptr n, bool noptr) ...@@ -737,11 +737,11 @@ runtime·markallocated(void *v, uintptr n, bool noptr)
bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift); bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift);
if(noptr) if(noptr)
bits |= bitNoPointers<<shift; bits |= bitNoPointers<<shift;
if(runtime·gomaxprocs == 1) { if(runtime·singleproc) {
*b = bits; *b = bits;
break; break;
} else { } 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)) if(runtime·casp((void**)b, (void*)obits, (void*)bits))
break; break;
} }
...@@ -767,11 +767,11 @@ runtime·markfreed(void *v, uintptr n) ...@@ -767,11 +767,11 @@ runtime·markfreed(void *v, uintptr n)
for(;;) { for(;;) {
obits = *b; obits = *b;
bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift); bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
if(runtime·gomaxprocs == 1) { if(runtime·singleproc) {
*b = bits; *b = bits;
break; break;
} else { } 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)) if(runtime·casp((void**)b, (void*)obits, (void*)bits))
break; break;
} }
...@@ -878,11 +878,11 @@ runtime·setblockspecial(void *v) ...@@ -878,11 +878,11 @@ runtime·setblockspecial(void *v)
for(;;) { for(;;) {
obits = *b; obits = *b;
bits = obits | (bitSpecial<<shift); bits = obits | (bitSpecial<<shift);
if(runtime·gomaxprocs == 1) { if(runtime·singleproc) {
*b = bits; *b = bits;
break; break;
} else { } 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)) if(runtime·casp((void**)b, (void*)obits, (void*)bits))
break; break;
} }
......
...@@ -126,6 +126,7 @@ enum { ...@@ -126,6 +126,7 @@ enum {
Sched runtime·sched; Sched runtime·sched;
int32 runtime·gomaxprocs; int32 runtime·gomaxprocs;
bool runtime·singleproc;
// An m that is waiting for notewakeup(&m->havenextg). This may be // 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 // only be accessed while the scheduler lock is held. This is used to
...@@ -199,6 +200,7 @@ runtime·schedinit(void) ...@@ -199,6 +200,7 @@ runtime·schedinit(void)
runtime·gomaxprocs = n; runtime·gomaxprocs = n;
} }
setmcpumax(runtime·gomaxprocs); setmcpumax(runtime·gomaxprocs);
runtime·singleproc = runtime·gomaxprocs == 1;
runtime·sched.predawn = 1; runtime·sched.predawn = 1;
m->nomemprof--; m->nomemprof--;
...@@ -585,6 +587,7 @@ runtime·stoptheworld(void) ...@@ -585,6 +587,7 @@ runtime·stoptheworld(void)
runtime·notesleep(&runtime·sched.stopped); runtime·notesleep(&runtime·sched.stopped);
schedlock(); schedlock();
} }
runtime·singleproc = runtime·gomaxprocs == 1;
schedunlock(); schedunlock();
} }
...@@ -1416,6 +1419,8 @@ runtime·gomaxprocsfunc(int32 n) ...@@ -1416,6 +1419,8 @@ runtime·gomaxprocsfunc(int32 n)
if(n > maxgomaxprocs) if(n > maxgomaxprocs)
n = maxgomaxprocs; n = maxgomaxprocs;
runtime·gomaxprocs = n; runtime·gomaxprocs = n;
if(runtime·gomaxprocs > 1)
runtime·singleproc = false;
if(runtime·gcwaiting != 0) { if(runtime·gcwaiting != 0) {
if(atomic_mcpumax(runtime·sched.atomic) != 1) if(atomic_mcpumax(runtime·sched.atomic) != 1)
runtime·throw("invalid mcpumax during gc"); runtime·throw("invalid mcpumax during gc");
......
...@@ -383,6 +383,7 @@ extern String runtime·emptystring; ...@@ -383,6 +383,7 @@ extern String runtime·emptystring;
G* runtime·allg; G* runtime·allg;
M* runtime·allm; M* runtime·allm;
extern int32 runtime·gomaxprocs; extern int32 runtime·gomaxprocs;
extern bool runtime·singleproc;
extern uint32 runtime·panicking; extern uint32 runtime·panicking;
extern int32 runtime·gcwaiting; // gc is waiting to run extern int32 runtime·gcwaiting; // gc is waiting to run
int8* runtime·goos; int8* runtime·goos;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment