aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/time.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-04-10 17:56:18 -0700
committerIan Lance Taylor <iant@golang.org>2019-10-22 18:41:00 +0000
commit2e0aa581b4a2544249ad2f8e86e17204ca778ca7 (patch)
treefd16f15efc56946b7f51343440457726b32be80a /src/runtime/time.go
parent3db6d46a4e0ee33eb34cef29f797ab7c12530a80 (diff)
downloadgo-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.go63
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