aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/time.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-04-10 17:38:26 -0700
committerIan Lance Taylor <iant@golang.org>2019-10-21 23:41:41 +0000
commit0050c079d5a50e441aa32d0da5338687890194ef (patch)
treefc8a8644378392cda84e3f9aae8f149b1e699560 /src/runtime/time.go
parenta59808ed01b52119025c49c7ab71ceffbf56c080 (diff)
downloadgo-0050c079d5a50e441aa32d0da5338687890194ef.tar.gz
go-0050c079d5a50e441aa32d0da5338687890194ef.zip
runtime, syscall, time: prepare for adding timers to P's
Add new fields to runtime.timer, and adjust the various timer functions in preparation for adding timers to P's. This continues to use the old timer code. Updates #6239 Updates #27707 Change-Id: I9adb3814f657e083ec5e22736c4b5b52b77b6a3f Reviewed-on: https://go-review.googlesource.com/c/go/+/171829 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.go138
1 files changed, 135 insertions, 3 deletions
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 0148f47a9e..b9105592a4 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -11,11 +11,19 @@ import (
"unsafe"
)
+// Temporary scaffolding while the new timer code is added.
+const oldTimers = true
+
// Package time knows the layout of this structure.
// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
type timer struct {
- tb *timersBucket // the bucket the timer lives in
- i int // heap index
+ tb *timersBucket // the bucket the timer lives in (oldTimers)
+ i int // heap index (oldTimers)
+
+ // If this timer is on a heap, which P's heap it is on.
+ // puintptr rather than *p to match uintptr in the versions
+ // of this struct defined in other packages. (!oldTimers)
+ pp puintptr
// Timer wakes up at when, and then at when+period, ... (period > 0 only)
// each time calling f(arg, now) in the timer goroutine, so f must be
@@ -25,6 +33,12 @@ type timer struct {
f func(interface{}, uintptr)
arg interface{}
seq uintptr
+
+ // What to set the when field to in timerModifiedXX status. (!oldTimers)
+ nextwhen int64
+
+ // The status field holds one of the values below. (!oldTimers)
+ status uint32
}
// timersLen is the length of timers array.
@@ -69,6 +83,84 @@ type timersBucket struct {
t []*timer
}
+// Code outside this file has to be careful in using a timer value.
+//
+// The pp, status, and nextwhen fields may only be used by code in this file.
+//
+// Code that creates a new timer value can set the when, period, f,
+// arg, and seq fields.
+// A new timer value may be passed to addtimer (called by time.startTimer).
+// After doing that no fields may be touched.
+//
+// An active timer (one that has been passed to addtimer) may be
+// passed to deltimer (time.stopTimer), after which it is no longer an
+// active timer. It is an inactive timer.
+// In an inactive timer the period, f, arg, and seq fields may be modified,
+// but not the when field.
+// It's OK to just drop an inactive timer and let the GC collect it.
+// It's not OK to pass an inactive timer to addtimer.
+// Only newly allocated timer values may be passed to addtimer.
+//
+// An active timer may be passed to modtimer. No fields may be touched.
+// It remains an active timer.
+//
+// An inactive timer may be passed to resettimer to turn into an
+// active timer with an updated when field.
+// It's OK to pass a newly allocated timer value to resettimer.
+//
+// Timer operations are addtimer, deltimer, modtimer, resettimer,
+// cleantimers, adjusttimers, and runtimer.
+//
+// We don't permit calling addtimer/deltimer/modtimer/resettimer simultaneously,
+// but adjusttimers and runtimer can be called at the same time as any of those.
+//
+// Active timers live in heaps attached to P, in the timers field.
+// Inactive timers live there too temporarily, until they are removed.
+
+// Values for the timer status field.
+const (
+ // Timer has no status set yet.
+ timerNoStatus = iota
+
+ // Waiting for timer to fire.
+ // The timer is in some P's heap.
+ timerWaiting
+
+ // Running the timer function.
+ // A timer will only have this status briefly.
+ timerRunning
+
+ // The timer is deleted and should be removed.
+ // It should not be run, but it is still in some P's heap.
+ timerDeleted
+
+ // The timer is being removed.
+ // The timer will only have this status briefly.
+ timerRemoving
+
+ // The timer has been stopped.
+ // It is not in any P's heap.
+ timerRemoved
+
+ // The timer is being modified.
+ // The timer will only have this status briefly.
+ timerModifying
+
+ // The timer has been modified to an earlier time.
+ // The new when value is in the nextwhen field.
+ // The timer is in some P's heap, possibly in the wrong place.
+ timerModifiedEarlier
+
+ // The timer has been modified to the same or a later time.
+ // The new when value is in the nextwhen field.
+ // The timer is in some P's heap, possibly in the wrong place.
+ timerModifiedLater
+
+ // The timer has been modified and is being moved.
+ // The timer will only have this status briefly.
+ timerMoving
+)
+
// Package time APIs.
// Godoc uses the comments in package time, not these.
@@ -77,6 +169,14 @@ type timersBucket struct {
// timeSleep puts the current goroutine to sleep for at least ns nanoseconds.
//go:linkname timeSleep time.Sleep
func timeSleep(ns int64) {
+ if oldTimers {
+ timeSleepOld(ns)
+ return
+ }
+ throw("new timeSleep not yet implemented")
+}
+
+func timeSleepOld(ns int64) {
if ns <= 0 {
return
}
@@ -97,7 +197,7 @@ func timeSleep(ns int64) {
unlock(&tb.lock)
badTimer()
}
- goparkunlock(&tb.lock, waitReasonSleep, traceEvGoSleep, 2)
+ goparkunlock(&tb.lock, waitReasonSleep, traceEvGoSleep, 3)
}
// startTimer adds t to the timer heap.
@@ -133,6 +233,14 @@ func goroutineReady(arg interface{}, seq uintptr) {
}
func addtimer(t *timer) {
+ if oldTimers {
+ addtimerOld(t)
+ return
+ }
+ throw("new addtimer not yet implemented")
+}
+
+func addtimerOld(t *timer) {
tb := t.assignBucket()
lock(&tb.lock)
ok := tb.addtimerLocked(t)
@@ -179,6 +287,14 @@ func (tb *timersBucket) addtimerLocked(t *timer) bool {
// Delete timer t from the heap.
// Do not need to update the timerproc: if it wakes up early, no big deal.
func deltimer(t *timer) bool {
+ if oldTimers {
+ return deltimerOld(t)
+ }
+ throw("no deltimer not yet implemented")
+ return false
+}
+
+func deltimerOld(t *timer) bool {
if t.tb == nil {
// t.tb can be nil if the user created a timer
// directly, without invoking startTimer e.g
@@ -227,6 +343,14 @@ func (tb *timersBucket) deltimerLocked(t *timer) (removed, ok bool) {
}
func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
+ if oldTimers {
+ modtimerOld(t, when, period, f, arg, seq)
+ return
+ }
+ throw("new modtimer not yet implemented")
+}
+
+func modtimerOld(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
tb := t.tb
lock(&tb.lock)
@@ -250,6 +374,14 @@ func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg in
// This should be called instead of addtimer if the timer value has been,
// or may have been, used previously.
func resettimer(t *timer, when int64) {
+ if oldTimers {
+ resettimerOld(t, when)
+ return
+ }
+ throw("new resettimer not yet implemented")
+}
+
+func resettimerOld(t *timer, when int64) {
t.when = when
addtimer(t)
}