@@ -116,6 +116,10 @@ type timersBucket struct {
116
116
//
117
117
// Active timers live in heaps attached to P, in the timers field.
118
118
// Inactive timers live there too temporarily, until they are removed.
119
+ //
120
+ // addtimer:
121
+ // timerNoStatus -> timerWaiting
122
+ // anything else -> panic: invalid value
119
123
120
124
// Values for the timer status field.
121
125
const (
@@ -161,6 +165,9 @@ const (
161
165
timerMoving
162
166
)
163
167
168
+ // maxWhen is the maximum value for timer's when field.
169
+ const maxWhen = 1 << 63 - 1
170
+
164
171
// Package time APIs.
165
172
// Godoc uses the comments in package time, not these.
166
173
@@ -232,12 +239,56 @@ func goroutineReady(arg interface{}, seq uintptr) {
232
239
goready (arg .(* g ), 0 )
233
240
}
234
241
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.
235
246
func addtimer (t * timer ) {
236
247
if oldTimers {
237
248
addtimerOld (t )
238
249
return
239
250
}
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 )
241
292
}
242
293
243
294
func addtimerOld (t * timer ) {
@@ -457,6 +508,16 @@ func timerproc(tb *timersBucket) {
457
508
}
458
509
}
459
510
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
+
460
521
// moveTimers moves a slice of timers to pp. The slice has been taken
461
522
// from a different P.
462
523
// This is currently called when the world is stopped, but it could
0 commit comments