@@ -131,6 +131,16 @@ type timersBucket struct {
131
131
// timerRunning -> wait until status changes
132
132
// timerMoving -> wait until status changes
133
133
// timerModifying -> panic: concurrent deltimer/modtimer calls
134
+ // modtimer:
135
+ // timerWaiting -> timerModifying -> timerModifiedXX
136
+ // timerModifiedXX -> timerModifying -> timerModifiedYY
137
+ // timerNoStatus -> timerWaiting
138
+ // timerRemoved -> timerWaiting
139
+ // timerRunning -> wait until status changes
140
+ // timerMoving -> wait until status changes
141
+ // timerRemoving -> wait until status changes
142
+ // timerDeleted -> panic: concurrent modtimer/deltimer calls
143
+ // timerModifying -> panic: concurrent modtimer calls
134
144
135
145
// Values for the timer status field.
136
146
const (
@@ -270,6 +280,11 @@ func addtimer(t *timer) {
270
280
}
271
281
t .status = timerWaiting
272
282
283
+ addInitializedTimer (t )
284
+ }
285
+
286
+ // addInitializedTimer adds an initialized timer to the current P.
287
+ func addInitializedTimer (t * timer ) {
273
288
when := t .when
274
289
275
290
pp := getg ().m .p .ptr ()
@@ -363,7 +378,9 @@ func deltimer(t *timer) bool {
363
378
return true
364
379
}
365
380
case timerModifiedEarlier :
381
+ tpp := t .pp .ptr ()
366
382
if atomic .Cas (& t .status , s , timerModifying ) {
383
+ atomic .Xadd (& tpp .adjustTimers , - 1 )
367
384
if ! atomic .Cas (& t .status , timerModifying , timerDeleted ) {
368
385
badTimer ()
369
386
}
@@ -438,12 +455,94 @@ func (tb *timersBucket) deltimerLocked(t *timer) (removed, ok bool) {
438
455
return true , ok
439
456
}
440
457
458
+ // modtimer modifies an existing timer.
459
+ // This is called by the netpoll code.
441
460
func modtimer (t * timer , when , period int64 , f func (interface {}, uintptr ), arg interface {}, seq uintptr ) {
442
461
if oldTimers {
443
462
modtimerOld (t , when , period , f , arg , seq )
444
463
return
445
464
}
446
- throw ("new modtimer not yet implemented" )
465
+
466
+ if when < 0 {
467
+ when = maxWhen
468
+ }
469
+
470
+ status := uint32 (timerNoStatus )
471
+ wasRemoved := false
472
+ loop:
473
+ for {
474
+ switch status = atomic .Load (& t .status ); status {
475
+ case timerWaiting , timerModifiedEarlier , timerModifiedLater :
476
+ if atomic .Cas (& t .status , status , timerModifying ) {
477
+ break loop
478
+ }
479
+ case timerNoStatus , timerRemoved :
480
+ // Timer was already run and t is no longer in a heap.
481
+ // Act like addtimer.
482
+ wasRemoved = true
483
+ atomic .Store (& t .status , timerWaiting )
484
+ break loop
485
+ case timerRunning , timerRemoving , timerMoving :
486
+ // The timer is being run or moved, by a different P.
487
+ // Wait for it to complete.
488
+ osyield ()
489
+ case timerDeleted :
490
+ // Simultaneous calls to modtimer and deltimer.
491
+ badTimer ()
492
+ case timerModifying :
493
+ // Multiple simultaneous calls to modtimer.
494
+ badTimer ()
495
+ default :
496
+ badTimer ()
497
+ }
498
+ }
499
+
500
+ t .period = period
501
+ t .f = f
502
+ t .arg = arg
503
+ t .seq = seq
504
+
505
+ if wasRemoved {
506
+ t .when = when
507
+ addInitializedTimer (t )
508
+ } else {
509
+ // The timer is in some other P's heap, so we can't change
510
+ // the when field. If we did, the other P's heap would
511
+ // be out of order. So we put the new when value in the
512
+ // nextwhen field, and let the other P set the when field
513
+ // when it is prepared to resort the heap.
514
+ t .nextwhen = when
515
+
516
+ newStatus := uint32 (timerModifiedLater )
517
+ if when < t .when {
518
+ newStatus = timerModifiedEarlier
519
+ }
520
+
521
+ // Update the adjustTimers field. Subtract one if we
522
+ // are removing a timerModifiedEarlier, add one if we
523
+ // are adding a timerModifiedEarlier.
524
+ tpp := t .pp .ptr ()
525
+ adjust := int32 (0 )
526
+ if status == timerModifiedEarlier {
527
+ adjust --
528
+ }
529
+ if newStatus == timerModifiedEarlier {
530
+ adjust ++
531
+ }
532
+ if adjust != 0 {
533
+ atomic .Xadd (& tpp .adjustTimers , adjust )
534
+ }
535
+
536
+ // Set the new status of the timer.
537
+ if ! atomic .Cas (& t .status , timerModifying , newStatus ) {
538
+ badTimer ()
539
+ }
540
+
541
+ // If the new status is earlier, wake up the poller.
542
+ if newStatus == timerModifiedEarlier {
543
+ wakeNetPoller (when )
544
+ }
545
+ }
447
546
}
448
547
449
548
func modtimerOld (t * timer , when , period int64 , f func (interface {}, uintptr ), arg interface {}, seq uintptr ) {
0 commit comments