@@ -373,32 +373,35 @@ type workType struct {
373
373
374
374
// Number of roots of various root types. Set by gcPrepareMarkRoots.
375
375
//
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
378
378
// to examine, and nStackRoots == len(stackRoots), which include goroutines that are
379
379
// unmarked / not runnable
380
380
nDataRoots , nBSSRoots , nSpanRoots , nStackRoots , nLiveStackRoots int
381
381
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
391
394
392
395
// Base indexes of each root type. Set by gcPrepareMarkRoots.
393
396
baseData , baseBSS , baseSpans , baseStacks , baseEnd uint32
394
397
395
398
// 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
397
400
// is partitioned into two sets; to the left of nLiveStackRoots are stackRoots
398
401
// of running / runnable goroutines and to the right of nLiveStackRoots are
399
402
// stackRoots of unmarked / not runnable goroutines
400
403
// gcDiscoverMoreStackRoots modifies the stackRoots array to redo the partition
401
- // after each marking phase
404
+ // after each marking phase iteration.
402
405
stackRoots []* g
403
406
404
407
// Each type of GC state transition is protected by a lock.
@@ -565,25 +568,25 @@ func GC() {
565
568
releasem (mp )
566
569
}
567
570
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 .
570
573
//
571
- // Only operates if deadlockgc is enabled in GOEXPERIMENT.
574
+ // Only operates if golfgc is enabled in GOEXPERIMENT.
572
575
// Otherwise, it just runs runtime.GC().
573
- func DetectDeadlocks () {
574
- if ! goexperiment .DeadlockGC {
576
+ func FindGoLeaks () {
577
+ if ! goexperiment .GolfGC {
575
578
GC ()
576
579
return
577
580
}
578
581
579
582
// 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
581
584
// of the GC cycle that picks it up.
582
- work .pendingDeadlockDetection = true
585
+ work .pendingGoleakDetection = true
583
586
584
587
// This read should be thread-safe for the same reason as the write above above.
585
588
// At most, we trigger the GC an additional time.
586
- for work .pendingDeadlockDetection {
589
+ for work .pendingGoleakDetection {
587
590
GC ()
588
591
}
589
592
}
@@ -733,8 +736,8 @@ func gcStart(trigger gcTrigger) {
733
736
mode = gcForceMode
734
737
} else if debug .gcstoptheworld == 2 {
735
738
mode = gcForceBlockMode
736
- } else if goexperiment .DeadlockGC {
737
- if work .pendingDeadlockDetection {
739
+ } else if goexperiment .GolfGC {
740
+ if work .pendingGoleakDetection {
738
741
// Fully stop the world if running deadlock detection.
739
742
mode = gcForceBlockMode
740
743
}
@@ -800,7 +803,7 @@ func gcStart(trigger gcTrigger) {
800
803
clearpools ()
801
804
802
805
work .cycles .Add (1 )
803
- work .detectedDeadlocks = false
806
+ work .detectedGoleaks = false
804
807
805
808
// Assists and workers can start the moment we start
806
809
// the world.
@@ -832,11 +835,11 @@ func gcStart(trigger gcTrigger) {
832
835
// possible.
833
836
setGCPhase (_GCmark )
834
837
835
- if goexperiment .DeadlockGC {
836
- if work .pendingDeadlockDetection {
838
+ if goexperiment .GolfGC {
839
+ if work .pendingGoleakDetection {
837
840
// 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
840
843
}
841
844
}
842
845
@@ -940,8 +943,8 @@ func gcMarkDone() {
940
943
// Ensure only one thread is running the ragged barrier at a
941
944
// time.
942
945
semacquire (& work .markDoneSema )
943
- if goexperiment .DeadlockGC {
944
- if work .deadlockDetectionMode {
946
+ if goexperiment .GolfGC {
947
+ if work .detectingGoleaks {
945
948
gcDiscoverMoreStackRoots ()
946
949
}
947
950
}
@@ -1050,11 +1053,13 @@ top:
1050
1053
})
1051
1054
semrelease (& worldsema )
1052
1055
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 ()
1058
1063
1059
1064
getg ().m .preemptoff = ""
1060
1065
systemstack (func () {
@@ -1243,12 +1248,12 @@ func gcDiscoverMoreStackRoots() {
1243
1248
}
1244
1249
}
1245
1250
1246
- // detectDeadlocks scans the remaining stackRoots and marks any which are
1251
+ // findGoleaks scans the remaining stackRoots and marks any which are
1247
1252
// 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
1252
1257
// we still need to mark these unreachable *g structs as they
1253
1258
// get reused, but their stack won't get scanned
1254
1259
if work .nLiveStackRoots == work .nStackRoots {
@@ -1281,10 +1286,10 @@ func detectDeadlocks() bool {
1281
1286
return false
1282
1287
}
1283
1288
1284
- // For the remaining goroutines, mark them as unreachable and deadlocking .
1289
+ // For the remaining goroutines, mark them as unreachable and leaked .
1285
1290
for i := work .nLiveStackRoots ; i < work .nStackRoots ; i ++ {
1286
1291
gp := work .stackRoots [i ].unmask ()
1287
- casgstatus (gp , _Gwaiting , _Gdeadlocked )
1292
+ casgstatus (gp , _Gwaiting , _Gleaked )
1288
1293
fn := findfunc (gp .startpc )
1289
1294
if fn .valid () {
1290
1295
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) {
1454
1459
}
1455
1460
1456
1461
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.
1459
1464
// Write is thread-safe because the world is stopped, and only one
1460
1465
// GC cycle can run at a time.
1461
- work .deadlockDetectionMode = false
1466
+ work .detectingGoleaks = false
1462
1467
}
1463
1468
1464
1469
// The memstats updated above must be updated with the world
@@ -1888,7 +1893,7 @@ func gcMarkWorkAvailable(p *p) bool {
1888
1893
if ! work .full .empty () || ! work .spanq .empty () {
1889
1894
return true // global work available
1890
1895
}
1891
- if ! work .deadlockDetectionMode {
1896
+ if ! work .detectingGoleaks {
1892
1897
return work .markrootNext < work .markrootJobs
1893
1898
}
1894
1899
rootNext := atomic .Load (& work .markrootNext )
0 commit comments