Skip to content

Commit 8dfad3c

Browse files
committed
Renamed deadlockgc to golfgc and deadlocks to goroutine leaks to avoid confusion with global deadlock.
1 parent e4ab163 commit 8dfad3c

File tree

13 files changed

+104
-100
lines changed

13 files changed

+104
-100
lines changed

src/internal/goexperiment/exp_deadlockgc_off.go

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/internal/goexperiment/exp_deadlockgc_on.go

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/internal/goexperiment/exp_golfgc_off.go

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/internal/goexperiment/exp_golfgc_on.go

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/internal/goexperiment/flags.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,6 @@ type Flags struct {
134134
// platforms.
135135
RandomizedHeapBase64 bool
136136

137-
// DeadlockGC enables the Deadlock GC implementation.
138-
DeadlockGC bool
137+
// GolfGC enables the Deadlock GC implementation.
138+
GolfGC bool
139139
}

src/runtime/mgc.go

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -373,32 +373,35 @@ type workType struct {
373373

374374
// Number of roots of various root types. Set by gcPrepareMarkRoots.
375375
//
376-
// During normal GC cycle, nStackRoots == nLiveStackRoots == len(stackRoots)
377-
// during deadlock detection GC, nLiveStackRoots is the number of stackRoots
376+
// During normal GC cycle, nStackRoots == nLiveStackRoots == len(stackRoots);
377+
// during goroutine leak detection, nLiveStackRoots is the number of stackRoots
378378
// to examine, and nStackRoots == len(stackRoots), which include goroutines that are
379379
// unmarked / not runnable
380380
nDataRoots, nBSSRoots, nSpanRoots, nStackRoots, nLiveStackRoots int
381381

382-
// The GC has performed deadlock detection during this GC cycle.
383-
detectedDeadlocks bool
384-
385-
// Is set to true by DetectDeadlocks(), instructing the next GC cycle to perform deadlock detection.
386-
pendingDeadlockDetection bool
387-
388-
// When set, the GC is running in deadlock detection mode.
389-
// This can be triggered with a runtime flag.
390-
deadlockDetectionMode bool
382+
// The following fields monitor the GC phase of the current cycle during
383+
// goroutine leak detection.
384+
//
385+
// - pendingGoleakDetection: The GC has been instructed to perform goroutine leak
386+
// detection during the next GC cycle; it is set by DetectGoroutineLeaks()
387+
// and unset during gcStart().
388+
// - detectingGoleaks: The GC is running in goroutine leak detection mode; it is set
389+
// during gcStart() and unset during gcMarkTermination().
390+
// - detectedGoleaks: The GC has performed goroutine leak detection during the current
391+
// GC cycle; it is set during gcMarkDone(), right after goroutine leak detection has concluded,
392+
// and unset during gcStart().
393+
pendingGoleakDetection, detectingGoleaks, detectedGoleaks bool
391394

392395
// Base indexes of each root type. Set by gcPrepareMarkRoots.
393396
baseData, baseBSS, baseSpans, baseStacks, baseEnd uint32
394397

395398
// stackRoots is a snapshot of all of the Gs that existed before the
396-
// beginning of concurrent marking. During deadlock detection GC, stackRoots
399+
// beginning of concurrent marking. During goroutine leak detection, stackRoots
397400
// is partitioned into two sets; to the left of nLiveStackRoots are stackRoots
398401
// of running / runnable goroutines and to the right of nLiveStackRoots are
399402
// stackRoots of unmarked / not runnable goroutines
400403
// gcDiscoverMoreStackRoots modifies the stackRoots array to redo the partition
401-
// after each marking phase
404+
// after each marking phase iteration.
402405
stackRoots []*g
403406

404407
// Each type of GC state transition is protected by a lock.
@@ -565,25 +568,25 @@ func GC() {
565568
releasem(mp)
566569
}
567570

568-
// DetectDeadlocks instructs the Go garbage collector to attempt
569-
// partial deadlock detection.
571+
// FindGoleaks instructs the Go garbage collector to attempt
572+
// goroutine leak detection during the next GC cycle.
570573
//
571-
// Only operates if deadlockgc is enabled in GOEXPERIMENT.
574+
// Only operates if golfgc is enabled in GOEXPERIMENT.
572575
// Otherwise, it just runs runtime.GC().
573-
func DetectDeadlocks() {
574-
if !goexperiment.DeadlockGC {
576+
func FindGoLeaks() {
577+
if !goexperiment.GolfGC {
575578
GC()
576579
return
577580
}
578581

579582
// This write should be thread-safe, as the overwritten value is true.
580-
// pendingDeadlockDetection is only set to false under STW at the start
583+
// pendingGoleakDetection is only set to false under STW at the start
581584
// of the GC cycle that picks it up.
582-
work.pendingDeadlockDetection = true
585+
work.pendingGoleakDetection = true
583586

584587
// This read should be thread-safe for the same reason as the write above above.
585588
// At most, we trigger the GC an additional time.
586-
for work.pendingDeadlockDetection {
589+
for work.pendingGoleakDetection {
587590
GC()
588591
}
589592
}
@@ -733,8 +736,8 @@ func gcStart(trigger gcTrigger) {
733736
mode = gcForceMode
734737
} else if debug.gcstoptheworld == 2 {
735738
mode = gcForceBlockMode
736-
} else if goexperiment.DeadlockGC {
737-
if work.pendingDeadlockDetection {
739+
} else if goexperiment.GolfGC {
740+
if work.pendingGoleakDetection {
738741
// Fully stop the world if running deadlock detection.
739742
mode = gcForceBlockMode
740743
}
@@ -800,7 +803,7 @@ func gcStart(trigger gcTrigger) {
800803
clearpools()
801804

802805
work.cycles.Add(1)
803-
work.detectedDeadlocks = false
806+
work.detectedGoleaks = false
804807

805808
// Assists and workers can start the moment we start
806809
// the world.
@@ -832,11 +835,11 @@ func gcStart(trigger gcTrigger) {
832835
// possible.
833836
setGCPhase(_GCmark)
834837

835-
if goexperiment.DeadlockGC {
836-
if work.pendingDeadlockDetection {
838+
if goexperiment.GolfGC {
839+
if work.pendingGoleakDetection {
837840
// Write is thread-safe because the world is stopped
838-
work.deadlockDetectionMode = true
839-
work.pendingDeadlockDetection = false
841+
work.detectingGoleaks = true
842+
work.pendingGoleakDetection = false
840843
}
841844
}
842845

@@ -940,8 +943,8 @@ func gcMarkDone() {
940943
// Ensure only one thread is running the ragged barrier at a
941944
// time.
942945
semacquire(&work.markDoneSema)
943-
if goexperiment.DeadlockGC {
944-
if work.deadlockDetectionMode {
946+
if goexperiment.GolfGC {
947+
if work.detectingGoleaks {
945948
gcDiscoverMoreStackRoots()
946949
}
947950
}
@@ -1050,11 +1053,13 @@ top:
10501053
})
10511054
semrelease(&worldsema)
10521055
goto top
1053-
} else if goexperiment.DeadlockGC {
1054-
// Otherwise, do a deadlock detection round.
1055-
// Only do one deadlock detection round per GC cycle.
1056-
if work.deadlockDetectionMode && !work.detectedDeadlocks {
1057-
work.detectedDeadlocks = detectDeadlocks()
1056+
} else if goexperiment.GolfGC {
1057+
// If we are detecting goroutine leaks, do so now.
1058+
if work.detectingGoleaks && !work.detectedGoleaks {
1059+
// Detect goroutine leaks. If the returned value is true, then
1060+
// detection was performed during this cycle. Otherwise, more mark work is needed,
1061+
// or live goroutines were found.
1062+
work.detectedGoleaks = findGoleaks()
10581063

10591064
getg().m.preemptoff = ""
10601065
systemstack(func() {
@@ -1243,12 +1248,12 @@ func gcDiscoverMoreStackRoots() {
12431248
}
12441249
}
12451250

1246-
// detectDeadlocks scans the remaining stackRoots and marks any which are
1251+
// findGoleaks scans the remaining stackRoots and marks any which are
12471252
// blocked over exclusively unreachable concurrency primitives as leaked (deadlocked).
1248-
// Returns true if goroutine leak was performed (or unnecessary).
1249-
// Returns false if the GC cycle has not yet reached a fix point for reachable goroutines.
1250-
func detectDeadlocks() bool {
1251-
// Report deadlocks and mark them unreachable, and resume marking
1253+
// Returns true if the goroutine leak check was performed (or unnecessary).
1254+
// Returns false if the GC cycle has not yet computed all (maybe-)live goroutines.
1255+
func findGoleaks() bool {
1256+
// Report goroutine leaks and mark them unreachable, and resume marking
12521257
// we still need to mark these unreachable *g structs as they
12531258
// get reused, but their stack won't get scanned
12541259
if work.nLiveStackRoots == work.nStackRoots {
@@ -1281,10 +1286,10 @@ func detectDeadlocks() bool {
12811286
return false
12821287
}
12831288

1284-
// For the remaining goroutines, mark them as unreachable and deadlocking.
1289+
// For the remaining goroutines, mark them as unreachable and leaked.
12851290
for i := work.nLiveStackRoots; i < work.nStackRoots; i++ {
12861291
gp := work.stackRoots[i].unmask()
1287-
casgstatus(gp, _Gwaiting, _Gdeadlocked)
1292+
casgstatus(gp, _Gwaiting, _Gleaked)
12881293
fn := findfunc(gp.startpc)
12891294
if fn.valid() {
12901295
print("goroutine leak! goroutine ", gp.goid, ": ", funcname(fn), " Stack size: ", gp.stack.hi-gp.stack.lo, " bytes\n")
@@ -1454,11 +1459,11 @@ func gcMarkTermination(stw worldStop) {
14541459
}
14551460

14561461
systemstack(func() {
1457-
if goexperiment.DeadlockGC {
1458-
// Pull the GC out of deadlock detection mode.
1462+
if goexperiment.GolfGC {
1463+
// Pull the GC out of goroutine leak detection mode.
14591464
// Write is thread-safe because the world is stopped, and only one
14601465
// GC cycle can run at a time.
1461-
work.deadlockDetectionMode = false
1466+
work.detectingGoleaks = false
14621467
}
14631468

14641469
// The memstats updated above must be updated with the world
@@ -1888,7 +1893,7 @@ func gcMarkWorkAvailable(p *p) bool {
18881893
if !work.full.empty() || !work.spanq.empty() {
18891894
return true // global work available
18901895
}
1891-
if !work.deadlockDetectionMode {
1896+
if !work.detectingGoleaks {
18921897
return work.markrootNext < work.markrootJobs
18931898
}
18941899
rootNext := atomic.Load(&work.markrootNext)

src/runtime/mgcmark.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const (
6060
//
6161
//go:nosplit
6262
func gcMask(p unsafe.Pointer) unsafe.Pointer {
63-
if goexperiment.DeadlockGC {
63+
if goexperiment.GolfGC {
6464
return unsafe.Pointer(uintptr(p) | gcBitMask)
6565
}
6666
return p
@@ -70,15 +70,15 @@ func gcMask(p unsafe.Pointer) unsafe.Pointer {
7070
//
7171
//go:nosplit
7272
func gcUnmask(p unsafe.Pointer) unsafe.Pointer {
73-
if goexperiment.DeadlockGC {
73+
if goexperiment.GolfGC {
7474
return unsafe.Pointer(uintptr(p) & gcUndoBitMask)
7575
}
7676
return p
7777
}
7878

79-
// internalBlocked returns true if the goroutine is blocked due to a
80-
// non-deadlocking waitReason, e.g. waiting for the netpoller or garbage collector.
81-
// Such goroutines should never be considered for deadlock detection.
79+
// internalBlocked returns true if the goroutine is blocked due to an
80+
// internal (non-leaking) waitReason, e.g. waiting for the netpoller or garbage collector.
81+
// Such goroutines are never leak detection candidates according to the GC.
8282
//
8383
//go:nosplit
8484
func (gp *g) internalBlocked() bool {
@@ -170,8 +170,8 @@ func gcPrepareMarkRoots() {
170170
// ignore them because they begin life without any roots, so
171171
// there's nothing to scan, and any roots they create during
172172
// the concurrent phase will be caught by the write barrier.
173-
if goexperiment.DeadlockGC {
174-
if work.deadlockDetectionMode {
173+
if goexperiment.GolfGC {
174+
if work.detectingGoleaks {
175175
work.stackRoots, work.nLiveStackRoots = allGsSnapshotSortedForGC()
176176
} else {
177177
// regular GC --- scan every go routine
@@ -950,7 +950,7 @@ func scanstack(gp *g, gcw *gcWork) int64 {
950950
case _Grunning:
951951
print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
952952
throw("scanstack: goroutine not stopped")
953-
case _Grunnable, _Gsyscall, _Gwaiting, _Gdeadlocked:
953+
case _Grunnable, _Gsyscall, _Gwaiting, _Gleaked:
954954
// ok
955955
}
956956

@@ -1307,8 +1307,6 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
13071307
if rootNext < rootJobs {
13081308
// Stop if we're preemptible, if someone wants to STW, or if
13091309
// someone is calling forEachP.
1310-
//
1311-
// Continue unconditionally if we're draining partial deadlocks.
13121310
for !(gp.preempt && (preemptible || sched.gcwaiting.Load() || pp.runSafePointFn != 0)) {
13131311
job, success := gcUpdateMarkrootNext()
13141312
if !success {
@@ -1623,9 +1621,9 @@ func scanobject(b uintptr, gcw *gcWork) {
16231621

16241622
// At this point we have extracted the next potential pointer.
16251623
// Quickly filter out nil and pointers back to the current object.
1626-
// The GC will skip masked addresses if DeadlockGC is enabled.
1624+
// The GC will skip masked addresses if GolfGC is enabled.
16271625
if obj != 0 && obj-b >= n &&
1628-
(!goexperiment.DeadlockGC || obj <= gcUndoBitMask) {
1626+
(!goexperiment.GolfGC || obj <= gcUndoBitMask) {
16291627
// Test if obj points into the Go heap and, if so,
16301628
// mark the object.
16311629
//

src/runtime/preempt.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func suspendG(gp *g) suspendGState {
160160
s = _Gwaiting
161161
fallthrough
162162

163-
case _Grunnable, _Gsyscall, _Gwaiting, _Gdeadlocked:
163+
case _Grunnable, _Gsyscall, _Gwaiting, _Gleaked:
164164
// Claim goroutine by setting scan bit.
165165
// This may race with execution or readying of gp.
166166
// The scan bit keeps it from transition state.
@@ -269,7 +269,7 @@ func resumeG(state suspendGState) {
269269

270270
case _Grunnable | _Gscan,
271271
_Gwaiting | _Gscan,
272-
_Gdeadlocked | _Gscan,
272+
_Gleaked | _Gscan,
273273
_Gsyscall | _Gscan:
274274
casfrom_Gscanstatus(gp, s, s&^_Gscan)
275275
}

src/runtime/proc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ func allGsSnapshot() []*g {
709709
// monotonically and existing entries never change, so we can
710710
// simply return a copy of the slice header. For added safety,
711711
// we trim everything past len because that can still change.
712-
if goexperiment.DeadlockGC {
712+
if goexperiment.GolfGC {
713713
for i, gp := range allgs {
714714
allgs[i] = gp.unmask()
715715
}

src/runtime/runtime2.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ const (
8787
// ready()ing this G.
8888
_Gpreempted // 9
8989

90-
// _Gdeadlocked represents a deadlocked goroutine caught by the GC.
91-
_Gdeadlocked // 10
90+
// _Gleaked represents a deadlocked goroutine caught by the GC.
91+
_Gleaked // 10
9292

9393
// _Gscan combined with one of the above states other than
9494
// _Grunning indicates that GC is scanning the stack. The
@@ -108,7 +108,7 @@ const (
108108
_Gscanwaiting = _Gscan + _Gwaiting // 0x1004
109109
_Gscanpreempted = _Gscan + _Gpreempted // 0x1009
110110

111-
_Gscandeadlocked = _Gscan + _Gdeadlocked // 0x100a
111+
_Gscandeadlocked = _Gscan + _Gleaked // 0x100a
112112
)
113113

114114
const (

0 commit comments

Comments
 (0)