@@ -169,6 +169,10 @@ const (
169
169
// maxWhen is the maximum value for timer's when field.
170
170
const maxWhen = 1 << 63 - 1
171
171
172
+ // verifyTimers can be set to true to add debugging checks that the
173
+ // timer heaps are valid.
174
+ const verifyTimers = false
175
+
172
176
// Package time APIs.
173
177
// Godoc uses the comments in package time, not these.
174
178
@@ -295,7 +299,9 @@ func deltimer(t *timer) bool {
295
299
for {
296
300
switch s := atomic .Load (& t .status ); s {
297
301
case timerWaiting , timerModifiedLater :
302
+ tpp := t .pp .ptr ()
298
303
if atomic .Cas (& t .status , s , timerDeleted ) {
304
+ atomic .Xadd (& tpp .deletedTimers , 1 )
299
305
// Timer was not yet run.
300
306
return true
301
307
}
@@ -306,6 +312,7 @@ func deltimer(t *timer) bool {
306
312
if ! atomic .Cas (& t .status , timerModifying , timerDeleted ) {
307
313
badTimer ()
308
314
}
315
+ atomic .Xadd (& tpp .deletedTimers , 1 )
309
316
// Timer was not yet run.
310
317
return true
311
318
}
@@ -486,6 +493,7 @@ func resettimer(t *timer, when int64) {
486
493
return
487
494
}
488
495
case timerDeleted :
496
+ tpp := t .pp .ptr ()
489
497
if atomic .Cas (& t .status , s , timerModifying ) {
490
498
t .nextwhen = when
491
499
newStatus := uint32 (timerModifiedLater )
@@ -496,6 +504,7 @@ func resettimer(t *timer, when int64) {
496
504
if ! atomic .Cas (& t .status , timerModifying , newStatus ) {
497
505
badTimer ()
498
506
}
507
+ atomic .Xadd (& tpp .deletedTimers , - 1 )
499
508
if newStatus == timerModifiedEarlier {
500
509
wakeNetPoller (when )
501
510
}
@@ -543,6 +552,7 @@ func cleantimers(pp *p) bool {
543
552
if ! atomic .Cas (& t .status , timerRemoving , timerRemoved ) {
544
553
return false
545
554
}
555
+ atomic .Xadd (& pp .deletedTimers , - 1 )
546
556
case timerModifiedEarlier , timerModifiedLater :
547
557
if ! atomic .Cas (& t .status , s , timerMoving ) {
548
558
continue
@@ -631,9 +641,13 @@ func adjusttimers(pp *p) {
631
641
return
632
642
}
633
643
if atomic .Load (& pp .adjustTimers ) == 0 {
644
+ if verifyTimers {
645
+ verifyTimerHeap (pp .timers )
646
+ }
634
647
return
635
648
}
636
649
var moved []* timer
650
+ loop:
637
651
for i := 0 ; i < len (pp .timers ); i ++ {
638
652
t := pp .timers [i ]
639
653
if t .pp .ptr () != pp {
@@ -648,6 +662,7 @@ func adjusttimers(pp *p) {
648
662
if ! atomic .Cas (& t .status , timerRemoving , timerRemoved ) {
649
663
badTimer ()
650
664
}
665
+ atomic .Xadd (& pp .deletedTimers , - 1 )
651
666
// Look at this heap position again.
652
667
i --
653
668
}
@@ -665,8 +680,7 @@ func adjusttimers(pp *p) {
665
680
moved = append (moved , t )
666
681
if s == timerModifiedEarlier {
667
682
if n := atomic .Xadd (& pp .adjustTimers , - 1 ); int32 (n ) <= 0 {
668
- addAdjustedTimers (pp , moved )
669
- return
683
+ break loop
670
684
}
671
685
}
672
686
// Look at this heap position again.
@@ -688,6 +702,10 @@ func adjusttimers(pp *p) {
688
702
if len (moved ) > 0 {
689
703
addAdjustedTimers (pp , moved )
690
704
}
705
+
706
+ if verifyTimers {
707
+ verifyTimerHeap (pp .timers )
708
+ }
691
709
}
692
710
693
711
// addAdjustedTimers adds any timers we adjusted in adjusttimers
@@ -762,6 +780,7 @@ func runtimer(pp *p, now int64) int64 {
762
780
if ! atomic .Cas (& t .status , timerRemoving , timerRemoved ) {
763
781
badTimer ()
764
782
}
783
+ atomic .Xadd (& pp .deletedTimers , - 1 )
765
784
if len (pp .timers ) == 0 {
766
785
return - 1
767
786
}
@@ -859,6 +878,107 @@ func runOneTimer(pp *p, t *timer, now int64) {
859
878
}
860
879
}
861
880
881
+ // clearDeletedTimers removes all deleted timers from the P's timer heap.
882
+ // This is used to avoid clogging up the heap if the program
883
+ // starts a lot of long-running timers and then stops them.
884
+ // For example, this can happen via context.WithTimeout.
885
+ //
886
+ // This is the only function that walks through the entire timer heap,
887
+ // other than moveTimers which only runs when the world is stopped.
888
+ //
889
+ // The caller must have locked the timers for pp.
890
+ func clearDeletedTimers (pp * p ) {
891
+ cdel := int32 (0 )
892
+ cearlier := int32 (0 )
893
+ to := 0
894
+ changedHeap := false
895
+ timers := pp .timers
896
+ nextTimer:
897
+ for _ , t := range timers {
898
+ for {
899
+ switch s := atomic .Load (& t .status ); s {
900
+ case timerWaiting :
901
+ if changedHeap {
902
+ timers [to ] = t
903
+ siftupTimer (timers , to )
904
+ }
905
+ to ++
906
+ continue nextTimer
907
+ case timerModifiedEarlier , timerModifiedLater :
908
+ if atomic .Cas (& t .status , s , timerMoving ) {
909
+ t .when = t .nextwhen
910
+ timers [to ] = t
911
+ siftupTimer (timers , to )
912
+ to ++
913
+ changedHeap = true
914
+ if ! atomic .Cas (& t .status , timerMoving , timerWaiting ) {
915
+ badTimer ()
916
+ }
917
+ if s == timerModifiedEarlier {
918
+ cearlier ++
919
+ }
920
+ continue nextTimer
921
+ }
922
+ case timerDeleted :
923
+ if atomic .Cas (& t .status , s , timerRemoving ) {
924
+ t .pp = 0
925
+ cdel ++
926
+ if ! atomic .Cas (& t .status , timerRemoving , timerRemoved ) {
927
+ badTimer ()
928
+ }
929
+ changedHeap = true
930
+ continue nextTimer
931
+ }
932
+ case timerModifying :
933
+ // Loop until modification complete.
934
+ osyield ()
935
+ case timerNoStatus , timerRemoved :
936
+ // We should not see these status values in a timer heap.
937
+ badTimer ()
938
+ case timerRunning , timerRemoving , timerMoving :
939
+ // Some other P thinks it owns this timer,
940
+ // which should not happen.
941
+ badTimer ()
942
+ default :
943
+ badTimer ()
944
+ }
945
+ }
946
+ }
947
+
948
+ // Set remaining slots in timers slice to nil,
949
+ // so that the timer values can be garbage collected.
950
+ for i := to ; i < len (timers ); i ++ {
951
+ timers [i ] = nil
952
+ }
953
+
954
+ timers = timers [:to ]
955
+ if verifyTimers {
956
+ verifyTimerHeap (timers )
957
+ }
958
+ pp .timers = timers
959
+ atomic .Xadd (& pp .deletedTimers , - cdel )
960
+ atomic .Xadd (& pp .adjustTimers , - cearlier )
961
+ }
962
+
963
+ // verifyTimerHeap verifies that the timer heap is in a valid state.
964
+ // This is only for debugging, and is only called if verifyTimers is true.
965
+ // The caller must have locked the timers.
966
+ func verifyTimerHeap (timers []* timer ) {
967
+ for i , t := range timers {
968
+ if i == 0 {
969
+ // First timer has no parent.
970
+ continue
971
+ }
972
+
973
+ // The heap is 4-ary. See siftupTimer and siftdownTimer.
974
+ p := (i - 1 ) / 4
975
+ if t .when < timers [p ].when {
976
+ print ("bad timer heap at " , i , ": " , p , ": " , timers [p ].when , ", " , i , ": " , t .when , "\n " )
977
+ throw ("bad timer heap" )
978
+ }
979
+ }
980
+ }
981
+
862
982
func timejump () * p {
863
983
if faketime == 0 {
864
984
return nil
0 commit comments