aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
authorDmitriy Vyukov <dvyukov@google.com>2014-06-28 19:20:46 -0700
committerDmitriy Vyukov <dvyukov@google.com>2014-06-28 19:20:46 -0700
commit5bfe8adee5100444cdde78d4897d1673df96c813 (patch)
treea699f127993996488d3c1a6906b34d6d736db9a7 /src/pkg/runtime
parent94935cb5c1fa5f5e002aa7286f5496a4dad36b5c (diff)
downloadgo-5bfe8adee5100444cdde78d4897d1673df96c813.tar.xz
runtime: fix GC bitmap corruption
Fixes #8299. R=golang-codereviews CC=golang-codereviews, khr, rsc https://golang.org/cl/103640044
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/mgc0.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 3eda4f4b9e..4ad8f3b08f 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -2731,7 +2731,7 @@ runtime·markscan(void *v)
void
runtime·markfreed(void *v)
{
- uintptr *b, off, shift;
+ uintptr *b, off, shift, xbits;
if(0)
runtime·printf("markfreed %p\n", v);
@@ -2742,7 +2742,18 @@ runtime·markfreed(void *v)
off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset
b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
- *b = (*b & ~(bitMask<<shift)) | (bitAllocated<<shift);
+ if(!g->m->gcing || work.nproc == 1) {
+ // During normal operation (not GC), the span bitmap is not updated concurrently,
+ // because either the span is cached or accesses are protected with MCentral lock.
+ *b = (*b & ~(bitMask<<shift)) | (bitAllocated<<shift);
+ } else {
+ // During GC other threads concurrently mark heap.
+ for(;;) {
+ xbits = *b;
+ if(runtime·casp((void**)b, (void*)xbits, (void*)((xbits & ~(bitMask<<shift)) | (bitAllocated<<shift))))
+ break;
+ }
+ }
}
// check that the block at v of size n is marked freed.