diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 36d48d2561..9d21dc4fa0 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1434,6 +1434,7 @@ top: if debugCachedWork { b := &_p_.wbBuf b.end = uintptr(unsafe.Pointer(&b.buf[wbBufEntryPointers])) + b.debugGen = gcWorkPauseGen } // Flush the gcWork, since this may create global work // and set the flushedWork flag. diff --git a/src/runtime/mwbbuf.go b/src/runtime/mwbbuf.go index 78ce54452d..f444452bab 100644 --- a/src/runtime/mwbbuf.go +++ b/src/runtime/mwbbuf.go @@ -23,6 +23,7 @@ package runtime import ( + "runtime/internal/atomic" "runtime/internal/sys" "unsafe" ) @@ -56,6 +57,12 @@ type wbBuf struct { // on. This must be a multiple of wbBufEntryPointers because // the write barrier only checks for overflow once per entry. buf [wbBufEntryPointers * wbBufEntries]uintptr + + // debugGen causes the write barrier buffer to flush after + // every write barrier if equal to gcWorkPauseGen. This is for + // debugging #27993. This is only set if debugCachedWork is + // set. + debugGen uint32 } const ( @@ -79,7 +86,7 @@ const ( func (b *wbBuf) reset() { start := uintptr(unsafe.Pointer(&b.buf[0])) b.next = start - if writeBarrier.cgo || (debugCachedWork && throwOnGCWork) { + if writeBarrier.cgo || (debugCachedWork && (throwOnGCWork || b.debugGen == atomic.Load(&gcWorkPauseGen))) { // Effectively disable the buffer by forcing a flush // on every barrier. b.end = uintptr(unsafe.Pointer(&b.buf[wbBufEntryPointers]))