Skip to content

Commit 2e0aa58

Browse files
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Michael Knyszek <[email protected]>
1 parent 3db6d46 commit 2e0aa58

File tree

3 files changed

+73
-3
lines changed

3 files changed

+73
-3
lines changed

src/runtime/netpoll.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,13 @@ var (
100100

101101
//go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit
102102
func poll_runtime_pollServerInit() {
103-
netpollinit()
104-
atomic.Store(&netpollInited, 1)
103+
netpollGenericInit()
104+
}
105+
106+
func netpollGenericInit() {
107+
if atomic.Cas(&netpollInited, 0, 1) {
108+
netpollinit()
109+
}
105110
}
106111

107112
func netpollinited() bool {

src/runtime/netpoll_stub.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,16 @@ package runtime
88

99
import "runtime/internal/atomic"
1010

11+
var netpollInited uint32
1112
var netpollWaiters uint32
1213

1314
var netpollStubLock mutex
1415
var netpollNote note
1516
var netpollBroken uint32
1617

18+
func netpollGenericInit() {
19+
}
20+
1721
func netpollBreak() {
1822
if atomic.Cas(&netpollBroken, 0, 1) {
1923
notewakeup(&netpollNote)

src/runtime/time.go

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ type timersBucket struct {
116116
//
117117
// Active timers live in heaps attached to P, in the timers field.
118118
// Inactive timers live there too temporarily, until they are removed.
119+
//
120+
// addtimer:
121+
// timerNoStatus -> timerWaiting
122+
// anything else -> panic: invalid value
119123

120124
// Values for the timer status field.
121125
const (
@@ -161,6 +165,9 @@ const (
161165
timerMoving
162166
)
163167

168+
// maxWhen is the maximum value for timer's when field.
169+
const maxWhen = 1<<63 - 1
170+
164171
// Package time APIs.
165172
// Godoc uses the comments in package time, not these.
166173

@@ -232,12 +239,56 @@ func goroutineReady(arg interface{}, seq uintptr) {
232239
goready(arg.(*g), 0)
233240
}
234241

242+
// addtimer adds a timer to the current P.
243+
// This should only be called with a newly created timer.
244+
// That avoids the risk of changing the when field of a timer in some P's heap,
245+
// which could cause the heap to become unsorted.
235246
func addtimer(t *timer) {
236247
if oldTimers {
237248
addtimerOld(t)
238249
return
239250
}
240-
throw("new addtimer not yet implemented")
251+
252+
// when must never be negative; otherwise runtimer will overflow
253+
// during its delta calculation and never expire other runtime timers.
254+
if t.when < 0 {
255+
t.when = maxWhen
256+
}
257+
if t.status != timerNoStatus {
258+
badTimer()
259+
}
260+
t.status = timerWaiting
261+
262+
when := t.when
263+
264+
pp := getg().m.p.ptr()
265+
lock(&pp.timersLock)
266+
ok := cleantimers(pp) && doaddtimer(pp, t)
267+
unlock(&pp.timersLock)
268+
if !ok {
269+
badTimer()
270+
}
271+
272+
wakeNetPoller(when)
273+
}
274+
275+
// doaddtimer adds t to the current P's heap.
276+
// It reports whether it saw no problems due to races.
277+
// The caller must have locked the timers for pp.
278+
func doaddtimer(pp *p, t *timer) bool {
279+
// Timers rely on the network poller, so make sure the poller
280+
// has started.
281+
if netpollInited == 0 {
282+
netpollGenericInit()
283+
}
284+
285+
if t.pp != 0 {
286+
throw("doaddtimer: P already set in timer")
287+
}
288+
t.pp.set(pp)
289+
i := len(pp.timers)
290+
pp.timers = append(pp.timers, t)
291+
return siftupTimer(pp.timers, i)
241292
}
242293

243294
func addtimerOld(t *timer) {
@@ -457,6 +508,16 @@ func timerproc(tb *timersBucket) {
457508
}
458509
}
459510

511+
// cleantimers cleans up the head of the timer queue. This speeds up
512+
// programs that create and delete timers; leaving them in the heap
513+
// slows down addtimer. Reports whether no timer problems were found.
514+
// The caller must have locked the timers for pp.
515+
func cleantimers(pp *p) bool {
516+
// TODO: write this.
517+
throw("cleantimers")
518+
return true
519+
}
520+
460521
// moveTimers moves a slice of timers to pp. The slice has been taken
461522
// from a different P.
462523
// This is currently called when the world is stopped, but it could

0 commit comments

Comments
 (0)