Skip to content

Commit f266cce

Browse files
committed
runtime: avoid potential deadlock when tracing memory code
In reclaimChunk, the runtime is calling traceGCSweepDone() while holding the mheap lock. traceGCSweepDone() can call traceEvent() and traceFlush(). These functions not only can get various trace locks, but they may also do memory allocations (runtime.newobject) that may end up getting the mheap lock. So, there may be either a self-deadlock or a possible deadlock between multiple threads. It seems better to release the mheap lock before calling traceGCSweepDone(). It is fine to release the lock, since the operations to get the index of the chunk of work to do are atomic. We already release the lock to call sweep, so there is no new behavior for any of the callers of reclaimChunk. With this change, mheap is a leaf lock (no other lock is ever acquired while it is held). Testing: besides normal all.bash, also ran all.bash with --long enabled, since it does longer tests of runtime/trace. Change-Id: I4f8cb66c24bb8d424f24d6c2305b4b8387409248 Reviewed-on: https://go-review.googlesource.com/c/go/+/207846 Reviewed-by: Austin Clements <[email protected]> Reviewed-by: Michael Knyszek <[email protected]>
1 parent 6b1a3f7 commit f266cce

File tree

1 file changed

+5
-1
lines changed

1 file changed

+5
-1
lines changed

src/runtime/mheap.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,9 @@ func (h *mheap) reclaim(npage uintptr) {
786786
// reclaimChunk sweeps unmarked spans that start at page indexes [pageIdx, pageIdx+n).
787787
// It returns the number of pages returned to the heap.
788788
//
789-
// h.lock must be held and the caller must be non-preemptible.
789+
// h.lock must be held and the caller must be non-preemptible. Note: h.lock may be
790+
// temporarily unlocked and re-locked in order to do sweeping or if tracing is
791+
// enabled.
790792
func (h *mheap) reclaimChunk(arenas []arenaIdx, pageIdx, n uintptr) uintptr {
791793
// The heap lock must be held because this accesses the
792794
// heapArena.spans arrays using potentially non-live pointers.
@@ -842,8 +844,10 @@ func (h *mheap) reclaimChunk(arenas []arenaIdx, pageIdx, n uintptr) uintptr {
842844
n -= uintptr(len(inUse) * 8)
843845
}
844846
if trace.enabled {
847+
unlock(&h.lock)
845848
// Account for pages scanned but not reclaimed.
846849
traceGCSweepSpan((n0 - nFreed) * pageSize)
850+
lock(&h.lock)
847851
}
848852
return nFreed
849853
}

0 commit comments

Comments
 (0)