@@ -591,6 +591,7 @@ func schedinit() {
591
591
parsedebugvars ()
592
592
gcinit ()
593
593
594
+ lock (& sched .lock )
594
595
sched .lastpoll = uint64 (nanotime ())
595
596
procs := ncpu
596
597
if n , ok := atoi32 (gogetenv ("GOMAXPROCS" )); ok && n > 0 {
@@ -599,6 +600,7 @@ func schedinit() {
599
600
if procresize (procs ) != nil {
600
601
throw ("unknown runnable goroutine during bootstrap" )
601
602
}
603
+ unlock (& sched .lock )
602
604
603
605
// For cgocheck > 1, we turn on the write barrier at all times
604
606
// and check all pointer writes. We can't do this until after
@@ -629,8 +631,10 @@ func dumpgstatus(gp *g) {
629
631
print ("runtime: g: g=" , _g_ , ", goid=" , _g_ .goid , ", g->atomicstatus=" , readgstatus (_g_ ), "\n " )
630
632
}
631
633
634
+ // sched.lock must be held.
632
635
func checkmcount () {
633
- // sched lock is held
636
+ assertLockHeld (& sched .lock )
637
+
634
638
if mcount () > sched .maxmcount {
635
639
print ("runtime: program exceeds " , sched .maxmcount , "-thread limit\n " )
636
640
throw ("thread exhaustion" )
@@ -642,6 +646,8 @@ func checkmcount() {
642
646
//
643
647
// sched.lock must be held.
644
648
func mReserveID () int64 {
649
+ assertLockHeld (& sched .lock )
650
+
645
651
if sched .mnext + 1 < sched .mnext {
646
652
throw ("runtime: thread ID overflow" )
647
653
}
@@ -2545,7 +2551,7 @@ func resetspinning() {
2545
2551
// Otherwise, for each idle P, this adds a G to the global queue
2546
2552
// and starts an M. Any remaining G's are added to the current P's
2547
2553
// local run queue.
2548
- // This may temporarily acquire the scheduler lock.
2554
+ // This may temporarily acquire sched. lock.
2549
2555
// Can run concurrently with GC.
2550
2556
func injectglist (glist * gList ) {
2551
2557
if glist .empty () {
@@ -4242,6 +4248,8 @@ func (pp *p) init(id int32) {
4242
4248
//
4243
4249
// sched.lock must be held and the world must be stopped.
4244
4250
func (pp * p ) destroy () {
4251
+ assertLockHeld (& sched .lock )
4252
+
4245
4253
// Move all runnable goroutines to the global queue
4246
4254
for pp .runqhead != pp .runqtail {
4247
4255
// Pop from tail of local queue
@@ -4333,11 +4341,17 @@ func (pp *p) destroy() {
4333
4341
pp .status = _Pdead
4334
4342
}
4335
4343
4336
- // Change number of processors. The world is stopped, sched is locked.
4337
- // gcworkbufs are not being modified by either the GC or
4338
- // the write barrier code.
4344
+ // Change number of processors.
4345
+ //
4346
+ // sched.lock must be held, and the world must be stopped.
4347
+ //
4348
+ // gcworkbufs must not be being modified by either the GC or the write barrier
4349
+ // code, so the GC must not be running if the number of Ps actually changes.
4350
+ //
4339
4351
// Returns list of Ps with local work, they need to be scheduled by the caller.
4340
4352
func procresize (nprocs int32 ) * p {
4353
+ assertLockHeld (& sched .lock )
4354
+
4341
4355
old := gomaxprocs
4342
4356
if old < 0 || nprocs <= 0 {
4343
4357
throw ("procresize: invalid arg" )
@@ -4529,6 +4543,8 @@ func incidlelocked(v int32) {
4529
4543
// The check is based on number of running M's, if 0 -> deadlock.
4530
4544
// sched.lock must be held.
4531
4545
func checkdead () {
4546
+ assertLockHeld (& sched .lock )
4547
+
4532
4548
// For -buildmode=c-shared or -buildmode=c-archive it's OK if
4533
4549
// there are no running goroutines. The calling program is
4534
4550
// assumed to be running.
@@ -5003,29 +5019,37 @@ func schedEnableUser(enable bool) {
5003
5019
5004
5020
// schedEnabled reports whether gp should be scheduled. It returns
5005
5021
// false is scheduling of gp is disabled.
5022
+ //
5023
+ // sched.lock must be held.
5006
5024
func schedEnabled (gp * g ) bool {
5025
+ assertLockHeld (& sched .lock )
5026
+
5007
5027
if sched .disable .user {
5008
5028
return isSystemGoroutine (gp , true )
5009
5029
}
5010
5030
return true
5011
5031
}
5012
5032
5013
5033
// Put mp on midle list.
5014
- // Sched must be locked .
5034
+ // sched.lock must be held .
5015
5035
// May run during STW, so write barriers are not allowed.
5016
5036
//go:nowritebarrierrec
5017
5037
func mput (mp * m ) {
5038
+ assertLockHeld (& sched .lock )
5039
+
5018
5040
mp .schedlink = sched .midle
5019
5041
sched .midle .set (mp )
5020
5042
sched .nmidle ++
5021
5043
checkdead ()
5022
5044
}
5023
5045
5024
5046
// Try to get an m from midle list.
5025
- // Sched must be locked .
5047
+ // sched.lock must be held .
5026
5048
// May run during STW, so write barriers are not allowed.
5027
5049
//go:nowritebarrierrec
5028
5050
func mget () * m {
5051
+ assertLockHeld (& sched .lock )
5052
+
5029
5053
mp := sched .midle .ptr ()
5030
5054
if mp != nil {
5031
5055
sched .midle = mp .schedlink
@@ -5035,35 +5059,43 @@ func mget() *m {
5035
5059
}
5036
5060
5037
5061
// Put gp on the global runnable queue.
5038
- // Sched must be locked .
5062
+ // sched.lock must be held .
5039
5063
// May run during STW, so write barriers are not allowed.
5040
5064
//go:nowritebarrierrec
5041
5065
func globrunqput (gp * g ) {
5066
+ assertLockHeld (& sched .lock )
5067
+
5042
5068
sched .runq .pushBack (gp )
5043
5069
sched .runqsize ++
5044
5070
}
5045
5071
5046
5072
// Put gp at the head of the global runnable queue.
5047
- // Sched must be locked .
5073
+ // sched.lock must be held .
5048
5074
// May run during STW, so write barriers are not allowed.
5049
5075
//go:nowritebarrierrec
5050
5076
func globrunqputhead (gp * g ) {
5077
+ assertLockHeld (& sched .lock )
5078
+
5051
5079
sched .runq .push (gp )
5052
5080
sched .runqsize ++
5053
5081
}
5054
5082
5055
5083
// Put a batch of runnable goroutines on the global runnable queue.
5056
5084
// This clears *batch.
5057
- // Sched must be locked .
5085
+ // sched.lock must be held .
5058
5086
func globrunqputbatch (batch * gQueue , n int32 ) {
5087
+ assertLockHeld (& sched .lock )
5088
+
5059
5089
sched .runq .pushBackAll (* batch )
5060
5090
sched .runqsize += n
5061
5091
* batch = gQueue {}
5062
5092
}
5063
5093
5064
5094
// Try get a batch of G's from the global runnable queue.
5065
- // Sched must be locked .
5095
+ // sched.lock must be held .
5066
5096
func globrunqget (_p_ * p , max int32 ) * g {
5097
+ assertLockHeld (& sched .lock )
5098
+
5067
5099
if sched .runqsize == 0 {
5068
5100
return nil
5069
5101
}
@@ -5091,10 +5123,12 @@ func globrunqget(_p_ *p, max int32) *g {
5091
5123
}
5092
5124
5093
5125
// Put p to on _Pidle list.
5094
- // Sched must be locked .
5126
+ // sched.lock must be held .
5095
5127
// May run during STW, so write barriers are not allowed.
5096
5128
//go:nowritebarrierrec
5097
5129
func pidleput (_p_ * p ) {
5130
+ assertLockHeld (& sched .lock )
5131
+
5098
5132
if ! runqempty (_p_ ) {
5099
5133
throw ("pidleput: P has non-empty run queue" )
5100
5134
}
@@ -5104,10 +5138,12 @@ func pidleput(_p_ *p) {
5104
5138
}
5105
5139
5106
5140
// Try get a p from _Pidle list.
5107
- // Sched must be locked .
5141
+ // sched.lock must be held .
5108
5142
// May run during STW, so write barriers are not allowed.
5109
5143
//go:nowritebarrierrec
5110
5144
func pidleget () * p {
5145
+ assertLockHeld (& sched .lock )
5146
+
5111
5147
_p_ := sched .pidle .ptr ()
5112
5148
if _p_ != nil {
5113
5149
sched .pidle = _p_ .link
0 commit comments