Commit 2e0aa581 authored by Ian Lance Taylor's avatar Ian Lance Taylor

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: default avatarMichael Knyszek <mknyszek@google.com>
parent 3db6d46a
...@@ -100,8 +100,13 @@ var ( ...@@ -100,8 +100,13 @@ var (
//go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit //go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit
func poll_runtime_pollServerInit() { func poll_runtime_pollServerInit() {
netpollinit() netpollGenericInit()
atomic.Store(&netpollInited, 1) }
func netpollGenericInit() {
if atomic.Cas(&netpollInited, 0, 1) {
netpollinit()
}
} }
func netpollinited() bool { func netpollinited() bool {
......
...@@ -8,12 +8,16 @@ package runtime ...@@ -8,12 +8,16 @@ package runtime
import "runtime/internal/atomic" import "runtime/internal/atomic"
var netpollInited uint32
var netpollWaiters uint32 var netpollWaiters uint32
var netpollStubLock mutex var netpollStubLock mutex
var netpollNote note var netpollNote note
var netpollBroken uint32 var netpollBroken uint32
func netpollGenericInit() {
}
func netpollBreak() { func netpollBreak() {
if atomic.Cas(&netpollBroken, 0, 1) { if atomic.Cas(&netpollBroken, 0, 1) {
notewakeup(&netpollNote) notewakeup(&netpollNote)
......
...@@ -116,6 +116,10 @@ type timersBucket struct { ...@@ -116,6 +116,10 @@ type timersBucket struct {
// //
// Active timers live in heaps attached to P, in the timers field. // Active timers live in heaps attached to P, in the timers field.
// Inactive timers live there too temporarily, until they are removed. // Inactive timers live there too temporarily, until they are removed.
//
// addtimer:
// timerNoStatus -> timerWaiting
// anything else -> panic: invalid value
// Values for the timer status field. // Values for the timer status field.
const ( const (
...@@ -161,6 +165,9 @@ const ( ...@@ -161,6 +165,9 @@ const (
timerMoving timerMoving
) )
// maxWhen is the maximum value for timer's when field.
const maxWhen = 1<<63 - 1
// Package time APIs. // Package time APIs.
// Godoc uses the comments in package time, not these. // Godoc uses the comments in package time, not these.
...@@ -232,12 +239,56 @@ func goroutineReady(arg interface{}, seq uintptr) { ...@@ -232,12 +239,56 @@ func goroutineReady(arg interface{}, seq uintptr) {
goready(arg.(*g), 0) 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) { func addtimer(t *timer) {
if oldTimers { if oldTimers {
addtimerOld(t) addtimerOld(t)
return 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) { func addtimerOld(t *timer) {
...@@ -457,6 +508,16 @@ func timerproc(tb *timersBucket) { ...@@ -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 // moveTimers moves a slice of timers to pp. The slice has been taken
// from a different P. // from a different P.
// This is currently called when the world is stopped, but it could // This is currently called when the world is stopped, but it could
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment