@@ -2799,86 +2799,42 @@ top:
2799
2799
}
2800
2800
}
2801
2801
2802
- // check all runqueues once again
2803
- for id , _p_ := range allpSnapshot {
2804
- if ! idlepMaskSnapshot .read (uint32 (id )) && ! runqempty (_p_ ) {
2805
- lock (& sched .lock )
2806
- _p_ = pidleget ()
2807
- unlock (& sched .lock )
2808
- if _p_ != nil {
2809
- acquirep (_p_ )
2810
- if wasSpinning {
2811
- _g_ .m .spinning = true
2812
- atomic .Xadd (& sched .nmspinning , 1 )
2813
- }
2814
- goto top
2815
- }
2816
- break
2802
+ // Check all runqueues once again.
2803
+ _p_ = checkRunqsNoP (allpSnapshot , idlepMaskSnapshot )
2804
+ if _p_ != nil {
2805
+ acquirep (_p_ )
2806
+ if wasSpinning {
2807
+ _g_ .m .spinning = true
2808
+ atomic .Xadd (& sched .nmspinning , 1 )
2817
2809
}
2810
+ goto top
2818
2811
}
2819
2812
2820
2813
// Similar to above, check for timer creation or expiry concurrently with
2821
2814
// transitioning from spinning to non-spinning. Note that we cannot use
2822
2815
// checkTimers here because it calls adjusttimers which may need to allocate
2823
2816
// memory, and that isn't allowed when we don't have an active P.
2824
- for id , _p_ := range allpSnapshot {
2825
- if timerpMaskSnapshot .read (uint32 (id )) {
2826
- w := nobarrierWakeTime (_p_ )
2827
- if w != 0 && (pollUntil == 0 || w < pollUntil ) {
2828
- pollUntil = w
2829
- }
2830
- }
2831
- }
2817
+ pollUntil = checkTimersNoP (allpSnapshot , timerpMaskSnapshot , pollUntil )
2832
2818
2833
- // Check for idle-priority GC work again.
2834
- //
2835
- // N.B. Since we have no P, gcBlackenEnabled may change at any time; we
2836
- // must check again after acquiring a P.
2837
- if atomic .Load (& gcBlackenEnabled ) != 0 && gcMarkWorkAvailable (nil ) {
2838
- // Work is available; we can start an idle GC worker only if
2839
- // there is an available P and available worker G.
2840
- //
2841
- // We can attempt to acquire these in either order. Workers are
2842
- // almost always available (see comment in findRunnableGCWorker
2843
- // for the one case there may be none). Since we're slightly
2844
- // less likely to find a P, check for that first.
2845
- lock (& sched .lock )
2846
- var node * gcBgMarkWorkerNode
2847
- _p_ = pidleget ()
2848
- if _p_ != nil {
2849
- // Now that we own a P, gcBlackenEnabled can't change
2850
- // (as it requires STW).
2851
- if gcBlackenEnabled != 0 {
2852
- node = (* gcBgMarkWorkerNode )(gcBgMarkWorkerPool .pop ())
2853
- if node == nil {
2854
- pidleput (_p_ )
2855
- _p_ = nil
2856
- }
2857
- } else {
2858
- pidleput (_p_ )
2859
- _p_ = nil
2860
- }
2819
+ // Finally, check for idle-priority GC work.
2820
+ _p_ , gp = checkIdleGCNoP ()
2821
+ if _p_ != nil {
2822
+ acquirep (_p_ )
2823
+ if wasSpinning {
2824
+ _g_ .m .spinning = true
2825
+ atomic .Xadd (& sched .nmspinning , 1 )
2861
2826
}
2862
- unlock (& sched .lock )
2863
- if _p_ != nil {
2864
- acquirep (_p_ )
2865
- if wasSpinning {
2866
- _g_ .m .spinning = true
2867
- atomic .Xadd (& sched .nmspinning , 1 )
2868
- }
2869
2827
2870
- // Run the idle worker.
2871
- _p_ .gcMarkWorkerMode = gcMarkWorkerIdleMode
2872
- gp := node .gp .ptr ()
2873
- casgstatus (gp , _Gwaiting , _Grunnable )
2874
- if trace .enabled {
2875
- traceGoUnpark (gp , 0 )
2876
- }
2877
- return gp , false
2828
+ // Run the idle worker.
2829
+ _p_ .gcMarkWorkerMode = gcMarkWorkerIdleMode
2830
+ casgstatus (gp , _Gwaiting , _Grunnable )
2831
+ if trace .enabled {
2832
+ traceGoUnpark (gp , 0 )
2878
2833
}
2834
+ return gp , false
2879
2835
}
2880
2836
2881
- // poll network
2837
+ // Poll network until next timer.
2882
2838
if netpollinited () && (atomic .Load (& netpollWaiters ) > 0 || pollUntil != 0 ) && atomic .Xchg64 (& sched .lastpoll , 0 ) != 0 {
2883
2839
atomic .Store64 (& sched .pollUntil , uint64 (pollUntil ))
2884
2840
if _g_ .m .p != 0 {
@@ -3038,6 +2994,93 @@ func stealWork(now int64) (gp *g, inheritTime bool, rnow, pollUntil int64, newWo
3038
2994
return nil , false , now , pollUntil , ranTimer
3039
2995
}
3040
2996
2997
+ // Check all Ps for a runnable G to steal.
2998
+ //
2999
+ // On entry we have no P. If a G is available to steal and a P is available,
3000
+ // the P is returned which the caller should acquire and attempt to steal the
3001
+ // work to.
3002
+ func checkRunqsNoP (allpSnapshot []* p , idlepMaskSnapshot pMask ) * p {
3003
+ for id , p2 := range allpSnapshot {
3004
+ if ! idlepMaskSnapshot .read (uint32 (id )) && ! runqempty (p2 ) {
3005
+ lock (& sched .lock )
3006
+ pp := pidleget ()
3007
+ unlock (& sched .lock )
3008
+ if pp != nil {
3009
+ return pp
3010
+ }
3011
+
3012
+ // Can't get a P, don't bother checking remaining Ps.
3013
+ break
3014
+ }
3015
+ }
3016
+
3017
+ return nil
3018
+ }
3019
+
3020
+ // Check all Ps for a timer expiring sooner than pollUntil.
3021
+ //
3022
+ // Returns updated pollUntil value.
3023
+ func checkTimersNoP (allpSnapshot []* p , timerpMaskSnapshot pMask , pollUntil int64 ) int64 {
3024
+ for id , p2 := range allpSnapshot {
3025
+ if timerpMaskSnapshot .read (uint32 (id )) {
3026
+ w := nobarrierWakeTime (p2 )
3027
+ if w != 0 && (pollUntil == 0 || w < pollUntil ) {
3028
+ pollUntil = w
3029
+ }
3030
+ }
3031
+ }
3032
+
3033
+ return pollUntil
3034
+ }
3035
+
3036
+ // Check for idle-priority GC, without a P on entry.
3037
+ //
3038
+ // If some GC work, a P, and a worker G are all available, the P and G will be
3039
+ // returned. The returned P has not been wired yet.
3040
+ func checkIdleGCNoP () (* p , * g ) {
3041
+ // N.B. Since we have no P, gcBlackenEnabled may change at any time; we
3042
+ // must check again after acquiring a P.
3043
+ if atomic .Load (& gcBlackenEnabled ) == 0 {
3044
+ return nil , nil
3045
+ }
3046
+ if ! gcMarkWorkAvailable (nil ) {
3047
+ return nil , nil
3048
+ }
3049
+
3050
+ // Work is available; we can start an idle GC worker only if
3051
+ // there is an available P and available worker G.
3052
+ //
3053
+ // We can attempt to acquire these in either order. Workers are
3054
+ // almost always available (see comment in findRunnableGCWorker
3055
+ // for the one case there may be none). Since we're slightly
3056
+ // less likely to find a P, check for that first.
3057
+ lock (& sched .lock )
3058
+ pp := pidleget ()
3059
+ unlock (& sched .lock )
3060
+ if pp == nil {
3061
+ return nil , nil
3062
+ }
3063
+
3064
+ // Now that we own a P, gcBlackenEnabled can't change
3065
+ // (as it requires STW).
3066
+ if gcBlackenEnabled == 0 {
3067
+ lock (& sched .lock )
3068
+ pidleput (pp )
3069
+ unlock (& sched .lock )
3070
+ return nil , nil
3071
+ }
3072
+
3073
+ node := (* gcBgMarkWorkerNode )(gcBgMarkWorkerPool .pop ())
3074
+ if node == nil {
3075
+ lock (& sched .lock )
3076
+ pidleput (pp )
3077
+ unlock (& sched .lock )
3078
+ return nil , nil
3079
+ }
3080
+
3081
+ return pp , node .gp .ptr ()
3082
+ }
3083
+
3041
3084
// wakeNetPoller wakes up the thread sleeping in the network poller if it isn't
3042
3085
// going to wake up before the when argument; or it wakes an idle P to service
3043
3086
// timers and the network poller if there isn't one already.
0 commit comments