aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/time.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-04-10 22:07:21 -0700
committerIan Lance Taylor <iant@golang.org>2019-10-22 22:15:25 +0000
commit432ca0ea83d12519004c6f7f7c1728410923987f (patch)
tree236bbfe36c93b2eb1822abd6729fc3b6d75afd60 /src/runtime/time.go
parent220150ff3c03a0d2618093689ab129ab5ea7dc7b (diff)
downloadgo-432ca0ea83d12519004c6f7f7c1728410923987f.tar.gz
go-432ca0ea83d12519004c6f7f7c1728410923987f.zip
runtime: add new runtimer function
Updates #27707 Change-Id: I1e65effb708911c727d126c51e0f50fe219f42ff Reviewed-on: https://go-review.googlesource.com/c/go/+/171878 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime/time.go')
-rw-r--r--src/runtime/time.go108
1 files changed, 105 insertions, 3 deletions
diff --git a/src/runtime/time.go b/src/runtime/time.go
index bacef16e0a..de8cb0835f 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -157,6 +157,18 @@ type timersBucket struct {
// adjusttimers (looks in P's timer heap):
// timerDeleted -> timerRemoving -> timerRemoved
// timerModifiedXX -> timerMoving -> timerWaiting
+// runtimer (looks in P's timer heap):
+// timerNoStatus -> panic: uninitialized timer
+// timerWaiting -> timerWaiting or
+// timerWaiting -> timerRunning -> timerNoStatus or
+// timerWaiting -> timerRunning -> timerWaiting
+// timerModifying -> wait until status changes
+// timerModifiedXX -> timerMoving -> timerWaiting
+// timerDeleted -> timerRemoving -> timerRemoved
+// timerRunning -> panic: concurrent runtimer calls
+// timerRemoved -> panic: inconsistent timer heap
+// timerRemoving -> panic: inconsistent timer heap
+// timerMoving -> panic: inconsistent timer heap
// Values for the timer status field.
const (
@@ -989,14 +1001,104 @@ func addAdjustedTimers(pp *p, moved []*timer) {
// when the first timer should run.
// The caller must have locked the timers for pp.
func runtimer(pp *p, now int64) int64 {
- throw("runtimer: not yet implemented")
- return -1
+ for {
+ t := pp.timers[0]
+ if t.pp.ptr() != pp {
+ throw("runtimer: bad p")
+ }
+ switch s := atomic.Load(&t.status); s {
+ case timerWaiting:
+ if t.when > now {
+ // Not ready to run.
+ return t.when
+ }
+
+ if !atomic.Cas(&t.status, s, timerRunning) {
+ continue
+ }
+ runOneTimer(pp, t, now)
+ return 0
+
+ case timerDeleted:
+ if !atomic.Cas(&t.status, s, timerRemoving) {
+ continue
+ }
+ if !dodeltimer0(pp) {
+ badTimer()
+ }
+ if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
+ badTimer()
+ }
+ if len(pp.timers) == 0 {
+ return -1
+ }
+
+ case timerModifiedEarlier, timerModifiedLater:
+ if !atomic.Cas(&t.status, s, timerMoving) {
+ continue
+ }
+ t.when = t.nextwhen
+ if !dodeltimer0(pp) {
+ badTimer()
+ }
+ if !doaddtimer(pp, t) {
+ badTimer()
+ }
+ if s == timerModifiedEarlier {
+ atomic.Xadd(&pp.adjustTimers, -1)
+ }
+ if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
+ badTimer()
+ }
+
+ case timerModifying:
+ // Wait for modification to complete.
+ osyield()
+
+ case timerNoStatus, timerRemoved:
+ // Should not see a new or inactive timer on the heap.
+ badTimer()
+ case timerRunning, timerRemoving, timerMoving:
+ // These should only be set when timers are locked,
+ // and we didn't do it.
+ badTimer()
+ default:
+ badTimer()
+ }
+ }
}
// runOneTimer runs a single timer.
// The caller must have locked the timers for pp.
func runOneTimer(pp *p, t *timer, now int64) {
- throw("runOneTimer: not yet implemented")
+ f := t.f
+ arg := t.arg
+ seq := t.seq
+
+ if t.period > 0 {
+ // Leave in heap but adjust next time to fire.
+ delta := t.when - now
+ t.when += t.period * (1 + -delta/t.period)
+ if !siftdownTimer(pp.timers, 0) {
+ badTimer()
+ }
+ if !atomic.Cas(&t.status, timerRunning, timerWaiting) {
+ badTimer()
+ }
+ } else {
+ // Remove from heap.
+ if !dodeltimer0(pp) {
+ badTimer()
+ }
+ if !atomic.Cas(&t.status, timerRunning, timerNoStatus) {
+ badTimer()
+ }
+ }
+
+ // Note that since timers are locked here, f may not call
+ // addtimer or resettimer.
+
+ f(arg, seq)
}
func timejump() *g {