diff options
author | Ian Lance Taylor <iant@golang.org> | 2019-04-10 17:56:18 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2019-10-22 18:41:00 +0000 |
commit | 2e0aa581b4a2544249ad2f8e86e17204ca778ca7 (patch) | |
tree | fd16f15efc56946b7f51343440457726b32be80a /src/runtime/time.go | |
parent | 3db6d46a4e0ee33eb34cef29f797ab7c12530a80 (diff) | |
download | go-2e0aa581b4a2544249ad2f8e86e17204ca778ca7.tar.gz go-2e0aa581b4a2544249ad2f8e86e17204ca778ca7.zip |
runtime: add new addtimer function
When we add a timer, make sure that the network poller is initialized,
since we will use it if we have to wait for the timer to be ready.
Updates #27707
Change-Id: I0637fe646bade2cc5ce50b745712292aa9c445b1
Reviewed-on: https://go-review.googlesource.com/c/go/+/171830
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.go | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/src/runtime/time.go b/src/runtime/time.go index b9105592a4..b4f1c0205e 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -116,6 +116,10 @@ type timersBucket struct { // // Active timers live in heaps attached to P, in the timers field. // Inactive timers live there too temporarily, until they are removed. +// +// addtimer: +// timerNoStatus -> timerWaiting +// anything else -> panic: invalid value // Values for the timer status field. const ( @@ -161,6 +165,9 @@ const ( timerMoving ) +// maxWhen is the maximum value for timer's when field. +const maxWhen = 1<<63 - 1 + // Package time APIs. // Godoc uses the comments in package time, not these. @@ -232,12 +239,56 @@ func goroutineReady(arg interface{}, seq uintptr) { goready(arg.(*g), 0) } +// addtimer adds a timer to the current P. +// This should only be called with a newly created timer. +// That avoids the risk of changing the when field of a timer in some P's heap, +// which could cause the heap to become unsorted. func addtimer(t *timer) { if oldTimers { addtimerOld(t) return } - throw("new addtimer not yet implemented") + + // when must never be negative; otherwise runtimer will overflow + // during its delta calculation and never expire other runtime timers. + if t.when < 0 { + t.when = maxWhen + } + if t.status != timerNoStatus { + badTimer() + } + t.status = timerWaiting + + when := t.when + + pp := getg().m.p.ptr() + lock(&pp.timersLock) + ok := cleantimers(pp) && doaddtimer(pp, t) + unlock(&pp.timersLock) + if !ok { + badTimer() + } + + wakeNetPoller(when) +} + +// doaddtimer adds t to the current P's heap. +// It reports whether it saw no problems due to races. +// The caller must have locked the timers for pp. +func doaddtimer(pp *p, t *timer) bool { + // Timers rely on the network poller, so make sure the poller + // has started. + if netpollInited == 0 { + netpollGenericInit() + } + + if t.pp != 0 { + throw("doaddtimer: P already set in timer") + } + t.pp.set(pp) + i := len(pp.timers) + pp.timers = append(pp.timers, t) + return siftupTimer(pp.timers, i) } func addtimerOld(t *timer) { @@ -457,6 +508,16 @@ func timerproc(tb *timersBucket) { } } +// cleantimers cleans up the head of the timer queue. This speeds up +// programs that create and delete timers; leaving them in the heap +// slows down addtimer. Reports whether no timer problems were found. +// The caller must have locked the timers for pp. +func cleantimers(pp *p) bool { + // TODO: write this. + throw("cleantimers") + return true +} + // moveTimers moves a slice of timers to pp. The slice has been taken // from a different P. // This is currently called when the world is stopped, but it could |