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
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 6325aad..78ea2aa 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -737,11 +737,11 @@
 		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 @@
 	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 @@
 	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 7a81591..5f396b4 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -126,6 +126,7 @@
 
 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·gomaxprocs = n;
 	}
 	setmcpumax(runtime·gomaxprocs);
+	runtime·singleproc = runtime·gomaxprocs == 1;
 	runtime·sched.predawn = 1;
 
 	m->nomemprof--;
@@ -585,6 +587,7 @@
 		runtime·notesleep(&runtime·sched.stopped);
 		schedlock();
 	}
+	runtime·singleproc = runtime·gomaxprocs == 1;
 	schedunlock();
 }
 
@@ -1416,6 +1419,8 @@
 	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 00be565..3c503e4 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -383,6 +383,7 @@
 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;