Source file
src/runtime/time.go
1
2
3
4
5
6
7 package runtime
8
9 import (
10 "internal/abi"
11 "runtime/internal/atomic"
12 "runtime/internal/sys"
13 "unsafe"
14 )
15
16
17
18 type timer struct {
19
20
21
22 pp puintptr
23
24
25
26
27
28
29 when int64
30 period int64
31 f func(any, uintptr)
32 arg any
33 seq uintptr
34
35
36 nextwhen int64
37
38
39 status uint32
40 }
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120 const (
121
122 timerNoStatus = iota
123
124
125
126 timerWaiting
127
128
129
130 timerRunning
131
132
133
134 timerDeleted
135
136
137
138 timerRemoving
139
140
141
142 timerRemoved
143
144
145
146 timerModifying
147
148
149
150
151 timerModifiedEarlier
152
153
154
155
156 timerModifiedLater
157
158
159
160 timerMoving
161 )
162
163
164 const maxWhen = 1<<63 - 1
165
166
167
168 const verifyTimers = false
169
170
171
172
173
174
175
176
177 func timeSleep(ns int64) {
178 if ns <= 0 {
179 return
180 }
181
182 gp := getg()
183 t := gp.timer
184 if t == nil {
185 t = new(timer)
186 gp.timer = t
187 }
188 t.f = goroutineReady
189 t.arg = gp
190 t.nextwhen = nanotime() + ns
191 if t.nextwhen < 0 {
192 t.nextwhen = maxWhen
193 }
194 gopark(resetForSleep, unsafe.Pointer(t), waitReasonSleep, traceEvGoSleep, 1)
195 }
196
197
198
199
200
201 func resetForSleep(gp *g, ut unsafe.Pointer) bool {
202 t := (*timer)(ut)
203 resettimer(t, t.nextwhen)
204 return true
205 }
206
207
208
209 func startTimer(t *timer) {
210 if raceenabled {
211 racerelease(unsafe.Pointer(t))
212 }
213 addtimer(t)
214 }
215
216
217
218
219 func stopTimer(t *timer) bool {
220 return deltimer(t)
221 }
222
223
224
225
226 func resetTimer(t *timer, when int64) bool {
227 if raceenabled {
228 racerelease(unsafe.Pointer(t))
229 }
230 return resettimer(t, when)
231 }
232
233
234
235 func modTimer(t *timer, when, period int64, f func(any, uintptr), arg any, seq uintptr) {
236 modtimer(t, when, period, f, arg, seq)
237 }
238
239
240
241
242 func goroutineReady(arg any, seq uintptr) {
243 goready(arg.(*g), 0)
244 }
245
246
247
248
249
250 func addtimer(t *timer) {
251
252
253
254 if t.when <= 0 {
255 throw("timer when must be positive")
256 }
257 if t.period < 0 {
258 throw("timer period must be non-negative")
259 }
260 if t.status != timerNoStatus {
261 throw("addtimer called with initialized timer")
262 }
263 t.status = timerWaiting
264
265 when := t.when
266
267
268 mp := acquirem()
269
270 pp := getg().m.p.ptr()
271 lock(&pp.timersLock)
272 cleantimers(pp)
273 doaddtimer(pp, t)
274 unlock(&pp.timersLock)
275
276 wakeNetPoller(when)
277
278 releasem(mp)
279 }
280
281
282
283 func doaddtimer(pp *p, t *timer) {
284
285
286 if netpollInited == 0 {
287 netpollGenericInit()
288 }
289
290 if t.pp != 0 {
291 throw("doaddtimer: P already set in timer")
292 }
293 t.pp.set(pp)
294 i := len(pp.timers)
295 pp.timers = append(pp.timers, t)
296 siftupTimer(pp.timers, i)
297 if t == pp.timers[0] {
298 atomic.Store64(&pp.timer0When, uint64(t.when))
299 }
300 atomic.Xadd(&pp.numTimers, 1)
301 }
302
303
304
305
306
307 func deltimer(t *timer) bool {
308 for {
309 switch s := atomic.Load(&t.status); s {
310 case timerWaiting, timerModifiedLater:
311
312
313 mp := acquirem()
314 if atomic.Cas(&t.status, s, timerModifying) {
315
316
317
318 tpp := t.pp.ptr()
319 if !atomic.Cas(&t.status, timerModifying, timerDeleted) {
320 badTimer()
321 }
322 releasem(mp)
323 atomic.Xadd(&tpp.deletedTimers, 1)
324
325 return true
326 } else {
327 releasem(mp)
328 }
329 case timerModifiedEarlier:
330
331
332 mp := acquirem()
333 if atomic.Cas(&t.status, s, timerModifying) {
334
335
336 tpp := t.pp.ptr()
337 if !atomic.Cas(&t.status, timerModifying, timerDeleted) {
338 badTimer()
339 }
340 releasem(mp)
341 atomic.Xadd(&tpp.deletedTimers, 1)
342
343 return true
344 } else {
345 releasem(mp)
346 }
347 case timerDeleted, timerRemoving, timerRemoved:
348
349 return false
350 case timerRunning, timerMoving:
351
352
353 osyield()
354 case timerNoStatus:
355
356
357 return false
358 case timerModifying:
359
360
361 osyield()
362 default:
363 badTimer()
364 }
365 }
366 }
367
368
369
370
371
372 func dodeltimer(pp *p, i int) int {
373 if t := pp.timers[i]; t.pp.ptr() != pp {
374 throw("dodeltimer: wrong P")
375 } else {
376 t.pp = 0
377 }
378 last := len(pp.timers) - 1
379 if i != last {
380 pp.timers[i] = pp.timers[last]
381 }
382 pp.timers[last] = nil
383 pp.timers = pp.timers[:last]
384 smallestChanged := i
385 if i != last {
386
387
388 smallestChanged = siftupTimer(pp.timers, i)
389 siftdownTimer(pp.timers, i)
390 }
391 if i == 0 {
392 updateTimer0When(pp)
393 }
394 atomic.Xadd(&pp.numTimers, -1)
395 return smallestChanged
396 }
397
398
399
400
401
402 func dodeltimer0(pp *p) {
403 if t := pp.timers[0]; t.pp.ptr() != pp {
404 throw("dodeltimer0: wrong P")
405 } else {
406 t.pp = 0
407 }
408 last := len(pp.timers) - 1
409 if last > 0 {
410 pp.timers[0] = pp.timers[last]
411 }
412 pp.timers[last] = nil
413 pp.timers = pp.timers[:last]
414 if last > 0 {
415 siftdownTimer(pp.timers, 0)
416 }
417 updateTimer0When(pp)
418 atomic.Xadd(&pp.numTimers, -1)
419 }
420
421
422
423
424 func modtimer(t *timer, when, period int64, f func(any, uintptr), arg any, seq uintptr) bool {
425 if when <= 0 {
426 throw("timer when must be positive")
427 }
428 if period < 0 {
429 throw("timer period must be non-negative")
430 }
431
432 status := uint32(timerNoStatus)
433 wasRemoved := false
434 var pending bool
435 var mp *m
436 loop:
437 for {
438 switch status = atomic.Load(&t.status); status {
439 case timerWaiting, timerModifiedEarlier, timerModifiedLater:
440
441
442 mp = acquirem()
443 if atomic.Cas(&t.status, status, timerModifying) {
444 pending = true
445 break loop
446 }
447 releasem(mp)
448 case timerNoStatus, timerRemoved:
449
450
451 mp = acquirem()
452
453
454
455 if atomic.Cas(&t.status, status, timerModifying) {
456 wasRemoved = true
457 pending = false
458 break loop
459 }
460 releasem(mp)
461 case timerDeleted:
462
463
464 mp = acquirem()
465 if atomic.Cas(&t.status, status, timerModifying) {
466 atomic.Xadd(&t.pp.ptr().deletedTimers, -1)
467 pending = false
468 break loop
469 }
470 releasem(mp)
471 case timerRunning, timerRemoving, timerMoving:
472
473
474 osyield()
475 case timerModifying:
476
477
478 osyield()
479 default:
480 badTimer()
481 }
482 }
483
484 t.period = period
485 t.f = f
486 t.arg = arg
487 t.seq = seq
488
489 if wasRemoved {
490 t.when = when
491 pp := getg().m.p.ptr()
492 lock(&pp.timersLock)
493 doaddtimer(pp, t)
494 unlock(&pp.timersLock)
495 if !atomic.Cas(&t.status, timerModifying, timerWaiting) {
496 badTimer()
497 }
498 releasem(mp)
499 wakeNetPoller(when)
500 } else {
501
502
503
504
505
506 t.nextwhen = when
507
508 newStatus := uint32(timerModifiedLater)
509 if when < t.when {
510 newStatus = timerModifiedEarlier
511 }
512
513 tpp := t.pp.ptr()
514
515 if newStatus == timerModifiedEarlier {
516 updateTimerModifiedEarliest(tpp, when)
517 }
518
519
520 if !atomic.Cas(&t.status, timerModifying, newStatus) {
521 badTimer()
522 }
523 releasem(mp)
524
525
526 if newStatus == timerModifiedEarlier {
527 wakeNetPoller(when)
528 }
529 }
530
531 return pending
532 }
533
534
535
536
537
538
539 func resettimer(t *timer, when int64) bool {
540 return modtimer(t, when, t.period, t.f, t.arg, t.seq)
541 }
542
543
544
545
546
547 func cleantimers(pp *p) {
548 gp := getg()
549 for {
550 if len(pp.timers) == 0 {
551 return
552 }
553
554
555
556
557
558 if gp.preemptStop {
559 return
560 }
561
562 t := pp.timers[0]
563 if t.pp.ptr() != pp {
564 throw("cleantimers: bad p")
565 }
566 switch s := atomic.Load(&t.status); s {
567 case timerDeleted:
568 if !atomic.Cas(&t.status, s, timerRemoving) {
569 continue
570 }
571 dodeltimer0(pp)
572 if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
573 badTimer()
574 }
575 atomic.Xadd(&pp.deletedTimers, -1)
576 case timerModifiedEarlier, timerModifiedLater:
577 if !atomic.Cas(&t.status, s, timerMoving) {
578 continue
579 }
580
581 t.when = t.nextwhen
582
583 dodeltimer0(pp)
584 doaddtimer(pp, t)
585 if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
586 badTimer()
587 }
588 default:
589
590 return
591 }
592 }
593 }
594
595
596
597
598
599 func moveTimers(pp *p, timers []*timer) {
600 for _, t := range timers {
601 loop:
602 for {
603 switch s := atomic.Load(&t.status); s {
604 case timerWaiting:
605 if !atomic.Cas(&t.status, s, timerMoving) {
606 continue
607 }
608 t.pp = 0
609 doaddtimer(pp, t)
610 if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
611 badTimer()
612 }
613 break loop
614 case timerModifiedEarlier, timerModifiedLater:
615 if !atomic.Cas(&t.status, s, timerMoving) {
616 continue
617 }
618 t.when = t.nextwhen
619 t.pp = 0
620 doaddtimer(pp, t)
621 if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
622 badTimer()
623 }
624 break loop
625 case timerDeleted:
626 if !atomic.Cas(&t.status, s, timerRemoved) {
627 continue
628 }
629 t.pp = 0
630
631 break loop
632 case timerModifying:
633
634 osyield()
635 case timerNoStatus, timerRemoved:
636
637 badTimer()
638 case timerRunning, timerRemoving, timerMoving:
639
640
641 badTimer()
642 default:
643 badTimer()
644 }
645 }
646 }
647 }
648
649
650
651
652
653
654 func adjusttimers(pp *p, now int64) {
655
656
657
658
659
660 first := atomic.Load64(&pp.timerModifiedEarliest)
661 if first == 0 || int64(first) > now {
662 if verifyTimers {
663 verifyTimerHeap(pp)
664 }
665 return
666 }
667
668
669 atomic.Store64(&pp.timerModifiedEarliest, 0)
670
671 var moved []*timer
672 for i := 0; i < len(pp.timers); i++ {
673 t := pp.timers[i]
674 if t.pp.ptr() != pp {
675 throw("adjusttimers: bad p")
676 }
677 switch s := atomic.Load(&t.status); s {
678 case timerDeleted:
679 if atomic.Cas(&t.status, s, timerRemoving) {
680 changed := dodeltimer(pp, i)
681 if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
682 badTimer()
683 }
684 atomic.Xadd(&pp.deletedTimers, -1)
685
686
687 i = changed - 1
688 }
689 case timerModifiedEarlier, timerModifiedLater:
690 if atomic.Cas(&t.status, s, timerMoving) {
691
692 t.when = t.nextwhen
693
694
695
696
697 changed := dodeltimer(pp, i)
698 moved = append(moved, t)
699
700
701 i = changed - 1
702 }
703 case timerNoStatus, timerRunning, timerRemoving, timerRemoved, timerMoving:
704 badTimer()
705 case timerWaiting:
706
707 case timerModifying:
708
709 osyield()
710 i--
711 default:
712 badTimer()
713 }
714 }
715
716 if len(moved) > 0 {
717 addAdjustedTimers(pp, moved)
718 }
719
720 if verifyTimers {
721 verifyTimerHeap(pp)
722 }
723 }
724
725
726
727 func addAdjustedTimers(pp *p, moved []*timer) {
728 for _, t := range moved {
729 doaddtimer(pp, t)
730 if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
731 badTimer()
732 }
733 }
734 }
735
736
737
738
739
740
741 func nobarrierWakeTime(pp *p) int64 {
742 next := int64(atomic.Load64(&pp.timer0When))
743 nextAdj := int64(atomic.Load64(&pp.timerModifiedEarliest))
744 if next == 0 || (nextAdj != 0 && nextAdj < next) {
745 next = nextAdj
746 }
747 return next
748 }
749
750
751
752
753
754
755
756
757 func runtimer(pp *p, now int64) int64 {
758 for {
759 t := pp.timers[0]
760 if t.pp.ptr() != pp {
761 throw("runtimer: bad p")
762 }
763 switch s := atomic.Load(&t.status); s {
764 case timerWaiting:
765 if t.when > now {
766
767 return t.when
768 }
769
770 if !atomic.Cas(&t.status, s, timerRunning) {
771 continue
772 }
773
774
775 runOneTimer(pp, t, now)
776 return 0
777
778 case timerDeleted:
779 if !atomic.Cas(&t.status, s, timerRemoving) {
780 continue
781 }
782 dodeltimer0(pp)
783 if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
784 badTimer()
785 }
786 atomic.Xadd(&pp.deletedTimers, -1)
787 if len(pp.timers) == 0 {
788 return -1
789 }
790
791 case timerModifiedEarlier, timerModifiedLater:
792 if !atomic.Cas(&t.status, s, timerMoving) {
793 continue
794 }
795 t.when = t.nextwhen
796 dodeltimer0(pp)
797 doaddtimer(pp, t)
798 if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
799 badTimer()
800 }
801
802 case timerModifying:
803
804 osyield()
805
806 case timerNoStatus, timerRemoved:
807
808 badTimer()
809 case timerRunning, timerRemoving, timerMoving:
810
811
812 badTimer()
813 default:
814 badTimer()
815 }
816 }
817 }
818
819
820
821
822
823 func runOneTimer(pp *p, t *timer, now int64) {
824 if raceenabled {
825 ppcur := getg().m.p.ptr()
826 if ppcur.timerRaceCtx == 0 {
827 ppcur.timerRaceCtx = racegostart(abi.FuncPCABIInternal(runtimer) + sys.PCQuantum)
828 }
829 raceacquirectx(ppcur.timerRaceCtx, unsafe.Pointer(t))
830 }
831
832 f := t.f
833 arg := t.arg
834 seq := t.seq
835
836 if t.period > 0 {
837
838 delta := t.when - now
839 t.when += t.period * (1 + -delta/t.period)
840 if t.when < 0 {
841 t.when = maxWhen
842 }
843 siftdownTimer(pp.timers, 0)
844 if !atomic.Cas(&t.status, timerRunning, timerWaiting) {
845 badTimer()
846 }
847 updateTimer0When(pp)
848 } else {
849
850 dodeltimer0(pp)
851 if !atomic.Cas(&t.status, timerRunning, timerNoStatus) {
852 badTimer()
853 }
854 }
855
856 if raceenabled {
857
858 gp := getg()
859 if gp.racectx != 0 {
860 throw("runOneTimer: unexpected racectx")
861 }
862 gp.racectx = gp.m.p.ptr().timerRaceCtx
863 }
864
865 unlock(&pp.timersLock)
866
867 f(arg, seq)
868
869 lock(&pp.timersLock)
870
871 if raceenabled {
872 gp := getg()
873 gp.racectx = 0
874 }
875 }
876
877
878
879
880
881
882
883
884
885
886 func clearDeletedTimers(pp *p) {
887
888
889 atomic.Store64(&pp.timerModifiedEarliest, 0)
890
891 cdel := int32(0)
892 to := 0
893 changedHeap := false
894 timers := pp.timers
895 nextTimer:
896 for _, t := range timers {
897 for {
898 switch s := atomic.Load(&t.status); s {
899 case timerWaiting:
900 if changedHeap {
901 timers[to] = t
902 siftupTimer(timers, to)
903 }
904 to++
905 continue nextTimer
906 case timerModifiedEarlier, timerModifiedLater:
907 if atomic.Cas(&t.status, s, timerMoving) {
908 t.when = t.nextwhen
909 timers[to] = t
910 siftupTimer(timers, to)
911 to++
912 changedHeap = true
913 if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
914 badTimer()
915 }
916 continue nextTimer
917 }
918 case timerDeleted:
919 if atomic.Cas(&t.status, s, timerRemoving) {
920 t.pp = 0
921 cdel++
922 if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
923 badTimer()
924 }
925 changedHeap = true
926 continue nextTimer
927 }
928 case timerModifying:
929
930 osyield()
931 case timerNoStatus, timerRemoved:
932
933 badTimer()
934 case timerRunning, timerRemoving, timerMoving:
935
936
937 badTimer()
938 default:
939 badTimer()
940 }
941 }
942 }
943
944
945
946 for i := to; i < len(timers); i++ {
947 timers[i] = nil
948 }
949
950 atomic.Xadd(&pp.deletedTimers, -cdel)
951 atomic.Xadd(&pp.numTimers, -cdel)
952
953 timers = timers[:to]
954 pp.timers = timers
955 updateTimer0When(pp)
956
957 if verifyTimers {
958 verifyTimerHeap(pp)
959 }
960 }
961
962
963
964
965 func verifyTimerHeap(pp *p) {
966 for i, t := range pp.timers {
967 if i == 0 {
968
969 continue
970 }
971
972
973 p := (i - 1) / 4
974 if t.when < pp.timers[p].when {
975 print("bad timer heap at ", i, ": ", p, ": ", pp.timers[p].when, ", ", i, ": ", t.when, "\n")
976 throw("bad timer heap")
977 }
978 }
979 if numTimers := int(atomic.Load(&pp.numTimers)); len(pp.timers) != numTimers {
980 println("timer heap len", len(pp.timers), "!= numTimers", numTimers)
981 throw("bad timer heap len")
982 }
983 }
984
985
986
987 func updateTimer0When(pp *p) {
988 if len(pp.timers) == 0 {
989 atomic.Store64(&pp.timer0When, 0)
990 } else {
991 atomic.Store64(&pp.timer0When, uint64(pp.timers[0].when))
992 }
993 }
994
995
996
997
998 func updateTimerModifiedEarliest(pp *p, nextwhen int64) {
999 for {
1000 old := atomic.Load64(&pp.timerModifiedEarliest)
1001 if old != 0 && int64(old) < nextwhen {
1002 return
1003 }
1004 if atomic.Cas64(&pp.timerModifiedEarliest, old, uint64(nextwhen)) {
1005 return
1006 }
1007 }
1008 }
1009
1010
1011
1012
1013 func timeSleepUntil() (int64, *p) {
1014 next := int64(maxWhen)
1015 var pret *p
1016
1017
1018 lock(&allpLock)
1019 for _, pp := range allp {
1020 if pp == nil {
1021
1022
1023 continue
1024 }
1025
1026 w := int64(atomic.Load64(&pp.timer0When))
1027 if w != 0 && w < next {
1028 next = w
1029 pret = pp
1030 }
1031
1032 w = int64(atomic.Load64(&pp.timerModifiedEarliest))
1033 if w != 0 && w < next {
1034 next = w
1035 pret = pp
1036 }
1037 }
1038 unlock(&allpLock)
1039
1040 return next, pret
1041 }
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054 func siftupTimer(t []*timer, i int) int {
1055 if i >= len(t) {
1056 badTimer()
1057 }
1058 when := t[i].when
1059 if when <= 0 {
1060 badTimer()
1061 }
1062 tmp := t[i]
1063 for i > 0 {
1064 p := (i - 1) / 4
1065 if when >= t[p].when {
1066 break
1067 }
1068 t[i] = t[p]
1069 i = p
1070 }
1071 if tmp != t[i] {
1072 t[i] = tmp
1073 }
1074 return i
1075 }
1076
1077
1078
1079 func siftdownTimer(t []*timer, i int) {
1080 n := len(t)
1081 if i >= n {
1082 badTimer()
1083 }
1084 when := t[i].when
1085 if when <= 0 {
1086 badTimer()
1087 }
1088 tmp := t[i]
1089 for {
1090 c := i*4 + 1
1091 c3 := c + 2
1092 if c >= n {
1093 break
1094 }
1095 w := t[c].when
1096 if c+1 < n && t[c+1].when < w {
1097 w = t[c+1].when
1098 c++
1099 }
1100 if c3 < n {
1101 w3 := t[c3].when
1102 if c3+1 < n && t[c3+1].when < w3 {
1103 w3 = t[c3+1].when
1104 c3++
1105 }
1106 if w3 < w {
1107 w = w3
1108 c = c3
1109 }
1110 }
1111 if w >= when {
1112 break
1113 }
1114 t[i] = t[c]
1115 i = c
1116 }
1117 if tmp != t[i] {
1118 t[i] = tmp
1119 }
1120 }
1121
1122
1123
1124
1125
1126 func badTimer() {
1127 throw("timer data corruption")
1128 }
1129
View as plain text