gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/kernel/time/time.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package time defines the Timer type, which provides a periodic timer that 16 // works by sampling a user-provided clock. 17 package time 18 19 import ( 20 "fmt" 21 "math" 22 "time" 23 24 "gvisor.dev/gvisor/pkg/abi/linux" 25 "gvisor.dev/gvisor/pkg/errors/linuxerr" 26 "gvisor.dev/gvisor/pkg/sync" 27 "gvisor.dev/gvisor/pkg/waiter" 28 ) 29 30 // Events that may be generated by a Clock. 31 const ( 32 // ClockEventSet occurs when a Clock undergoes a discontinuous change. 33 ClockEventSet waiter.EventMask = 1 << iota 34 35 // ClockEventRateIncrease occurs when the rate at which a Clock advances 36 // increases significantly, such that values returned by previous calls to 37 // Clock.WallTimeUntil may be too large. 38 ClockEventRateIncrease 39 ) 40 41 // Time represents an instant in time with nanosecond precision. 42 // 43 // Time may represent time with respect to any clock and may not have any 44 // meaning in the real world. 45 // 46 // +stateify savable 47 type Time struct { 48 ns int64 49 } 50 51 var ( 52 // MinTime is the zero time instant, the lowest possible time that can 53 // be represented by Time. 54 MinTime = Time{ns: math.MinInt64} 55 56 // MaxTime is the highest possible time that can be represented by 57 // Time. 58 MaxTime = Time{ns: math.MaxInt64} 59 60 // ZeroTime represents the zero time in an unspecified Clock's domain. 61 ZeroTime = Time{ns: 0} 62 ) 63 64 const ( 65 // MinDuration is the minimum duration representable by time.Duration. 66 MinDuration = time.Duration(math.MinInt64) 67 68 // MaxDuration is the maximum duration representable by time.Duration. 69 MaxDuration = time.Duration(math.MaxInt64) 70 ) 71 72 // FromNanoseconds returns a Time representing the point ns nanoseconds after 73 // an unspecified Clock's zero time. 74 func FromNanoseconds(ns int64) Time { 75 return Time{ns} 76 } 77 78 // FromSeconds returns a Time representing the point s seconds after an 79 // unspecified Clock's zero time. 80 func FromSeconds(s int64) Time { 81 if s > math.MaxInt64/time.Second.Nanoseconds() { 82 return MaxTime 83 } 84 return Time{s * 1e9} 85 } 86 87 // FromUnix converts from Unix seconds and nanoseconds to Time, assuming a real 88 // time Unix clock domain. 89 func FromUnix(s int64, ns int64) Time { 90 if s > math.MaxInt64/time.Second.Nanoseconds() { 91 return MaxTime 92 } 93 t := s * 1e9 94 if t > math.MaxInt64-ns { 95 return MaxTime 96 } 97 return Time{t + ns} 98 } 99 100 // FromTimespec converts from Linux Timespec to Time. 101 func FromTimespec(ts linux.Timespec) Time { 102 return Time{ts.ToNsecCapped()} 103 } 104 105 // FromTimeval converts a Linux Timeval to Time. 106 func FromTimeval(tv linux.Timeval) Time { 107 return Time{tv.ToNsecCapped()} 108 } 109 110 // Nanoseconds returns nanoseconds elapsed since the zero time in t's Clock 111 // domain. If t represents walltime, this is nanoseconds since the Unix epoch. 112 func (t Time) Nanoseconds() int64 { 113 return t.ns 114 } 115 116 // Microseconds returns microseconds elapsed since the zero time in t's Clock 117 // domain. If t represents walltime, this is microseconds since the Unix epoch. 118 func (t Time) Microseconds() int64 { 119 return t.ns / 1000 120 } 121 122 // Seconds returns seconds elapsed since the zero time in t's Clock domain. If 123 // t represents walltime, this is seconds since Unix epoch. 124 func (t Time) Seconds() int64 { 125 return t.Nanoseconds() / time.Second.Nanoseconds() 126 } 127 128 // Timespec converts Time to a Linux timespec. 129 func (t Time) Timespec() linux.Timespec { 130 return linux.NsecToTimespec(t.Nanoseconds()) 131 } 132 133 // Unix returns the (seconds, nanoseconds) representation of t such that 134 // seconds*1e9 + nanoseconds = t. 135 func (t Time) Unix() (s int64, ns int64) { 136 s = t.ns / 1e9 137 ns = t.ns % 1e9 138 return 139 } 140 141 // TimeT converts Time to a Linux time_t. 142 func (t Time) TimeT() linux.TimeT { 143 return linux.NsecToTimeT(t.Nanoseconds()) 144 } 145 146 // Timeval converts Time to a Linux timeval. 147 func (t Time) Timeval() linux.Timeval { 148 return linux.NsecToTimeval(t.Nanoseconds()) 149 } 150 151 // StatxTimestamp converts Time to a Linux statx_timestamp. 152 func (t Time) StatxTimestamp() linux.StatxTimestamp { 153 return linux.NsecToStatxTimestamp(t.Nanoseconds()) 154 } 155 156 // Add adds the duration of d to t. 157 func (t Time) Add(d time.Duration) Time { 158 if t.ns > 0 && d.Nanoseconds() > math.MaxInt64-int64(t.ns) { 159 return MaxTime 160 } 161 if t.ns < 0 && d.Nanoseconds() < math.MinInt64-int64(t.ns) { 162 return MinTime 163 } 164 return Time{int64(t.ns) + d.Nanoseconds()} 165 } 166 167 // AddTime adds the duration of u to t. 168 func (t Time) AddTime(u Time) Time { 169 return t.Add(time.Duration(u.ns)) 170 } 171 172 // Equal reports whether the two times represent the same instant in time. 173 func (t Time) Equal(u Time) bool { 174 return t.ns == u.ns 175 } 176 177 // Before reports whether the instant t is before the instant u. 178 func (t Time) Before(u Time) bool { 179 return t.ns < u.ns 180 } 181 182 // After reports whether the instant t is after the instant u. 183 func (t Time) After(u Time) bool { 184 return t.ns > u.ns 185 } 186 187 // Sub returns the duration of t - u. 188 // 189 // N.B. This measure may not make sense for every Time returned by ktime.Clock. 190 // Callers who need wall time duration can use ktime.Clock.WallTimeUntil to 191 // estimate that wall time. 192 func (t Time) Sub(u Time) time.Duration { 193 dur := time.Duration(int64(t.ns)-int64(u.ns)) * time.Nanosecond 194 switch { 195 case u.Add(dur).Equal(t): 196 return dur 197 case t.Before(u): 198 return MinDuration 199 default: 200 return MaxDuration 201 } 202 } 203 204 // IsMin returns whether t represents the lowest possible time instant. 205 func (t Time) IsMin() bool { 206 return t == MinTime 207 } 208 209 // IsZero returns whether t represents the zero time instant in t's Clock domain. 210 func (t Time) IsZero() bool { 211 return t == ZeroTime 212 } 213 214 // String returns the time represented in nanoseconds as a string. 215 func (t Time) String() string { 216 return fmt.Sprintf("%dns", t.Nanoseconds()) 217 } 218 219 // A Clock is an abstract time source. 220 type Clock interface { 221 // Now returns the current time in nanoseconds according to the Clock. 222 Now() Time 223 224 // WallTimeUntil returns the estimated wall time until Now will return a 225 // value greater than or equal to t, given that a recent call to Now 226 // returned now. If t has already passed, WallTimeUntil may return 0 or a 227 // negative value. 228 // 229 // WallTimeUntil must be abstract to support Clocks that do not represent 230 // wall time (e.g. thread group execution timers). Clocks that represent 231 // wall times may embed the WallRateClock type to obtain an appropriate 232 // trivial implementation of WallTimeUntil. 233 // 234 // WallTimeUntil is used to determine when associated Timers should next 235 // check for expirations. Returning too small a value may result in 236 // spurious Timer goroutine wakeups, while returning too large a value may 237 // result in late expirations. Implementations should usually err on the 238 // side of underestimating. 239 WallTimeUntil(t, now Time) time.Duration 240 241 // Waitable methods may be used to subscribe to Clock events. Waiters will 242 // not be preserved by Save and must be re-established during restore. 243 // 244 // Since Clock events are transient, implementations of 245 // waiter.Waitable.Readiness should return 0. 246 waiter.Waitable 247 } 248 249 // WallRateClock implements Clock.WallTimeUntil for Clocks that elapse at the 250 // same rate as wall time. 251 type WallRateClock struct{} 252 253 // WallTimeUntil implements Clock.WallTimeUntil. 254 func (*WallRateClock) WallTimeUntil(t, now Time) time.Duration { 255 return t.Sub(now) 256 } 257 258 // NoClockEvents implements waiter.Waitable for Clocks that do not generate 259 // events. 260 type NoClockEvents struct{} 261 262 // Readiness implements waiter.Waitable.Readiness. 263 func (*NoClockEvents) Readiness(mask waiter.EventMask) waiter.EventMask { 264 return 0 265 } 266 267 // EventRegister implements waiter.Waitable.EventRegister. 268 func (*NoClockEvents) EventRegister(e *waiter.Entry) error { 269 return nil 270 } 271 272 // EventUnregister implements waiter.Waitable.EventUnregister. 273 func (*NoClockEvents) EventUnregister(e *waiter.Entry) { 274 } 275 276 // ClockEventsQueue implements waiter.Waitable by wrapping waiter.Queue and 277 // defining waiter.Waitable.Readiness as required by Clock. 278 type ClockEventsQueue struct { 279 waiter.Queue 280 } 281 282 // EventRegister implements waiter.Waitable. 283 func (c *ClockEventsQueue) EventRegister(e *waiter.Entry) error { 284 c.Queue.EventRegister(e) 285 return nil 286 } 287 288 // Readiness implements waiter.Waitable.Readiness. 289 func (*ClockEventsQueue) Readiness(mask waiter.EventMask) waiter.EventMask { 290 return 0 291 } 292 293 // Listener receives expirations from a Timer. 294 type Listener interface { 295 // NotifyTimer is called when its associated Timer expires. exp is the number 296 // of expirations. setting is the next timer Setting. 297 // 298 // Notify is called with the associated Timer's mutex locked, so Notify 299 // must not take any locks that precede Timer.mu in lock order. 300 // 301 // If Notify returns true, the timer will use the returned setting 302 // rather than the passed one. 303 // 304 // Preconditions: exp > 0. 305 NotifyTimer(exp uint64, setting Setting) (newSetting Setting, update bool) 306 } 307 308 // Setting contains user-controlled mutable Timer properties. 309 // 310 // +stateify savable 311 type Setting struct { 312 // Enabled is true if the timer is running. 313 Enabled bool 314 315 // Next is the time in nanoseconds of the next expiration. 316 Next Time 317 318 // Period is the time in nanoseconds between expirations. If Period is 319 // zero, the timer will not automatically restart after expiring. 320 // 321 // Invariant: Period >= 0. 322 Period time.Duration 323 } 324 325 // SettingFromSpec converts a (value, interval) pair to a Setting based on a 326 // reading from c. value is interpreted as a time relative to c.Now(). 327 func SettingFromSpec(value time.Duration, interval time.Duration, c Clock) (Setting, error) { 328 return SettingFromSpecAt(value, interval, c.Now()) 329 } 330 331 // SettingFromSpecAt converts a (value, interval) pair to a Setting. value is 332 // interpreted as a time relative to now. 333 func SettingFromSpecAt(value time.Duration, interval time.Duration, now Time) (Setting, error) { 334 if value < 0 { 335 return Setting{}, linuxerr.EINVAL 336 } 337 if value == 0 { 338 return Setting{Period: interval}, nil 339 } 340 return Setting{ 341 Enabled: true, 342 Next: now.Add(value), 343 Period: interval, 344 }, nil 345 } 346 347 // SettingFromAbsSpec converts a (value, interval) pair to a Setting. value is 348 // interpreted as an absolute time. 349 func SettingFromAbsSpec(value Time, interval time.Duration) (Setting, error) { 350 if value.Before(ZeroTime) { 351 return Setting{}, linuxerr.EINVAL 352 } 353 if value.IsZero() { 354 return Setting{Period: interval}, nil 355 } 356 return Setting{ 357 Enabled: true, 358 Next: value, 359 Period: interval, 360 }, nil 361 } 362 363 // SettingFromItimerspec converts a linux.Itimerspec to a Setting. If abs is 364 // true, its.Value is interpreted as an absolute time. Otherwise, it is 365 // interpreted as a time relative to c.Now(). 366 func SettingFromItimerspec(its linux.Itimerspec, abs bool, c Clock) (Setting, error) { 367 if abs { 368 return SettingFromAbsSpec(FromTimespec(its.Value), its.Interval.ToDuration()) 369 } 370 return SettingFromSpec(its.Value.ToDuration(), its.Interval.ToDuration(), c) 371 } 372 373 // SpecFromSetting converts a timestamp and a Setting to a (relative value, 374 // interval) pair, as used by most Linux syscalls that return a struct 375 // itimerval or struct itimerspec. 376 func SpecFromSetting(now Time, s Setting) (value, period time.Duration) { 377 if !s.Enabled { 378 return 0, s.Period 379 } 380 return s.Next.Sub(now), s.Period 381 } 382 383 // ItimerspecFromSetting converts a Setting to a linux.Itimerspec. 384 func ItimerspecFromSetting(now Time, s Setting) linux.Itimerspec { 385 val, iv := SpecFromSetting(now, s) 386 return linux.Itimerspec{ 387 Interval: linux.DurationToTimespec(iv), 388 Value: linux.DurationToTimespec(val), 389 } 390 } 391 392 // At returns an updated Setting and a number of expirations after the 393 // associated Clock indicates a time of now. 394 // 395 // Settings may be created by successive calls to At with decreasing 396 // values of now (i.e. time may appear to go backward). Supporting this is 397 // required to support non-monotonic clocks, as well as allowing 398 // Timer.clock.Now() to be called without holding Timer.mu. 399 func (s Setting) At(now Time) (Setting, uint64) { 400 if !s.Enabled { 401 return s, 0 402 } 403 if s.Next.After(now) { 404 return s, 0 405 } 406 if s.Period == 0 { 407 s.Enabled = false 408 return s, 1 409 } 410 exp := 1 + uint64(now.Sub(s.Next).Nanoseconds())/uint64(s.Period) 411 s.Next = s.Next.Add(time.Duration(uint64(s.Period) * exp)) 412 return s, exp 413 } 414 415 // Timer is an optionally-periodic timer driven by sampling a user-specified 416 // Clock. Timer's semantics support the requirements of Linux's interval timers 417 // (setitimer(2), timer_create(2), timerfd_create(2)). 418 // 419 // Timers should be created using NewTimer and must be cleaned up by calling 420 // Timer.Destroy when no longer used. 421 // 422 // +stateify savable 423 type Timer struct { 424 // clock is the time source. clock is protected by mu and clockSeq. 425 clockSeq sync.SeqCount `state:"nosave"` 426 clock Clock 427 428 // listener is notified of expirations. listener is immutable. 429 listener Listener 430 431 // mu protects the following mutable fields. 432 mu sync.Mutex `state:"nosave"` 433 434 // setting is the timer setting. setting is protected by mu. 435 setting Setting 436 437 // paused is true if the Timer is paused. paused is protected by mu. 438 paused bool 439 440 // kicker is used to wake the Timer goroutine. The kicker pointer is 441 // immutable, but its state is protected by mu. 442 kicker *time.Timer `state:"nosave"` 443 444 // entry is registered with clock.EventRegister. entry is immutable. 445 // 446 // Per comment in Clock, entry must be re-registered after restore; per 447 // comment in Timer.Load, this is done in Timer.Resume. 448 entry waiter.Entry `state:"nosave"` 449 450 // events is the channel that will be notified whenever entry receives an 451 // event. It is also closed by Timer.Destroy to instruct the Timer 452 // goroutine to exit. 453 events chan struct{} `state:"nosave"` 454 } 455 456 // timerTickEvents are Clock events that require the Timer goroutine to Tick 457 // prematurely. 458 const timerTickEvents = ClockEventSet | ClockEventRateIncrease 459 460 // NewTimer returns a new Timer that will obtain time from clock and send 461 // expirations to listener. The Timer is initially stopped and has no first 462 // expiration or period configured. 463 func NewTimer(clock Clock, listener Listener) *Timer { 464 t := &Timer{ 465 clock: clock, 466 listener: listener, 467 } 468 t.init() 469 return t 470 } 471 472 // init initializes Timer state that is not preserved across save/restore. If 473 // init has already been called, calling it again is a no-op. 474 // 475 // Preconditions: t.mu must be locked, or the caller must have exclusive access 476 // to t. 477 func (t *Timer) init() { 478 if t.kicker != nil { 479 return 480 } 481 // If t.kicker is nil, the Timer goroutine can't be running, so we can't 482 // race with it. 483 t.kicker = time.NewTimer(0) 484 t.entry, t.events = waiter.NewChannelEntry(timerTickEvents) 485 if err := t.clock.EventRegister(&t.entry); err != nil { 486 panic(err) 487 } 488 go t.runGoroutine() // S/R-SAFE: synchronized by t.mu 489 } 490 491 // Destroy releases resources owned by the Timer. A Destroyed Timer must not be 492 // used again; in particular, a Destroyed Timer should not be Saved. 493 func (t *Timer) Destroy() { 494 // Stop the Timer, ensuring that the Timer goroutine will not call 495 // t.kicker.Reset, before calling t.kicker.Stop. 496 t.mu.Lock() 497 t.setting.Enabled = false 498 t.mu.Unlock() 499 t.kicker.Stop() 500 // Unregister t.entry, ensuring that the Clock will not send to t.events, 501 // before closing t.events to instruct the Timer goroutine to exit. 502 t.clock.EventUnregister(&t.entry) 503 close(t.events) 504 } 505 506 func (t *Timer) runGoroutine() { 507 for { 508 select { 509 case <-t.kicker.C: 510 case _, ok := <-t.events: 511 if !ok { 512 // Channel closed by Destroy. 513 return 514 } 515 } 516 t.Tick() 517 } 518 } 519 520 // Tick requests that the Timer immediately check for expirations and 521 // re-evaluate when it should next check for expirations. 522 func (t *Timer) Tick() { 523 // Optimistically read t.Clock().Now() before locking t.mu, as t.clock is 524 // unlikely to change. 525 unlockedClock := t.Clock() 526 now := unlockedClock.Now() 527 t.mu.Lock() 528 defer t.mu.Unlock() 529 if t.paused { 530 return 531 } 532 if t.clock != unlockedClock { 533 now = t.clock.Now() 534 } 535 s, exp := t.setting.At(now) 536 t.setting = s 537 if exp > 0 { 538 if newS, ok := t.listener.NotifyTimer(exp, t.setting); ok { 539 t.setting = newS 540 } 541 } 542 t.resetKickerLocked(now) 543 } 544 545 // Pause pauses the Timer, ensuring that it does not generate any further 546 // expirations until Resume is called. If the Timer is already paused, Pause 547 // has no effect. 548 func (t *Timer) Pause() { 549 t.mu.Lock() 550 defer t.mu.Unlock() 551 t.paused = true 552 // t.kicker may be nil if we were restored but never resumed. 553 if t.kicker != nil { 554 t.kicker.Stop() 555 } 556 } 557 558 // Resume ends the effect of Pause. If the Timer is not paused, Resume has no 559 // effect. 560 func (t *Timer) Resume() { 561 t.mu.Lock() 562 defer t.mu.Unlock() 563 if !t.paused { 564 return 565 } 566 t.paused = false 567 568 // Lazily initialize the Timer. We can't call Timer.init until Timer.Resume 569 // because save/restore will restore Timers before 570 // kernel.Timekeeper.SetClocks() has been called, so if t.clock is backed 571 // by a kernel.Timekeeper then the Timer goroutine will panic if it calls 572 // t.clock.Now(). 573 t.init() 574 575 // Kick the Timer goroutine in case it was already initialized, but the 576 // Timer goroutine was sleeping. 577 t.kicker.Reset(0) 578 } 579 580 // Get returns a snapshot of the Timer's current Setting and the time 581 // (according to the Timer's Clock) at which the snapshot was taken. 582 // 583 // Preconditions: The Timer must not be paused (since its Setting cannot 584 // be advanced to the current time while it is paused.) 585 func (t *Timer) Get() (Time, Setting) { 586 // Optimistically read t.Clock().Now() before locking t.mu, as t.clock is 587 // unlikely to change. 588 unlockedClock := t.Clock() 589 now := unlockedClock.Now() 590 t.mu.Lock() 591 defer t.mu.Unlock() 592 if t.paused { 593 panic(fmt.Sprintf("Timer.Get called on paused Timer %p", t)) 594 } 595 if t.clock != unlockedClock { 596 now = t.clock.Now() 597 } 598 s, exp := t.setting.At(now) 599 t.setting = s 600 if exp > 0 { 601 if newS, ok := t.listener.NotifyTimer(exp, t.setting); ok { 602 t.setting = newS 603 } 604 } 605 t.resetKickerLocked(now) 606 return now, s 607 } 608 609 // Swap atomically changes the Timer's Setting and returns the Timer's previous 610 // Setting and the time (according to the Timer's Clock) at which the snapshot 611 // was taken. Setting s.Enabled to true starts the Timer, while setting 612 // s.Enabled to false stops it. 613 // 614 // Preconditions: The Timer must not be paused. 615 func (t *Timer) Swap(s Setting) (Time, Setting) { 616 return t.SwapAnd(s, nil) 617 } 618 619 // SwapAnd atomically changes the Timer's Setting, calls f if it is not nil, 620 // and returns the Timer's previous Setting and the time (according to the 621 // Timer's Clock) at which the Setting was changed. Setting s.Enabled to true 622 // starts the timer, while setting s.Enabled to false stops it. 623 // 624 // Preconditions: 625 // - The Timer must not be paused. 626 // - f cannot call any Timer methods since it is called with the Timer mutex 627 // locked. 628 func (t *Timer) SwapAnd(s Setting, f func()) (Time, Setting) { 629 // Optimistically read t.Clock().Now() before locking t.mu, as t.clock is 630 // unlikely to change. 631 unlockedClock := t.Clock() 632 now := unlockedClock.Now() 633 t.mu.Lock() 634 defer t.mu.Unlock() 635 if t.paused { 636 panic(fmt.Sprintf("Timer.SwapAnd called on paused Timer %p", t)) 637 } 638 if t.clock != unlockedClock { 639 now = t.clock.Now() 640 } 641 oldS, oldExp := t.setting.At(now) 642 if oldExp > 0 { 643 t.listener.NotifyTimer(oldExp, oldS) 644 // N.B. The returned Setting doesn't matter because we're about 645 // to overwrite. 646 } 647 if f != nil { 648 f() 649 } 650 newS, newExp := s.At(now) 651 t.setting = newS 652 if newExp > 0 { 653 if newS, ok := t.listener.NotifyTimer(newExp, t.setting); ok { 654 t.setting = newS 655 } 656 } 657 t.resetKickerLocked(now) 658 return now, oldS 659 } 660 661 // SetClock atomically changes a Timer's Clock and Setting. 662 func (t *Timer) SetClock(c Clock, s Setting) { 663 var now Time 664 if s.Enabled { 665 now = c.Now() 666 } 667 t.mu.Lock() 668 defer t.mu.Unlock() 669 t.setting = s 670 if oldC := t.clock; oldC != c { 671 oldC.EventUnregister(&t.entry) 672 c.EventRegister(&t.entry) 673 t.clockSeq.BeginWrite() 674 t.clock = c 675 t.clockSeq.EndWrite() 676 } 677 t.resetKickerLocked(now) 678 } 679 680 // Preconditions: t.mu must be locked. 681 func (t *Timer) resetKickerLocked(now Time) { 682 if t.setting.Enabled { 683 // Clock.WallTimeUntil may return a negative value. This is fine; 684 // time.when treats negative Durations as 0. 685 t.kicker.Reset(t.clock.WallTimeUntil(t.setting.Next, now)) 686 } 687 // We don't call t.kicker.Stop if !t.setting.Enabled because in most cases 688 // resetKickerLocked will be called from the Timer goroutine itself, in 689 // which case t.kicker has already fired and t.kicker.Stop will be an 690 // expensive no-op (time.Timer.Stop => time.stopTimer => runtime.stopTimer 691 // => runtime.deltimer). 692 } 693 694 // Clock returns the Clock used by t. 695 func (t *Timer) Clock() Clock { 696 return SeqAtomicLoadClock(&t.clockSeq, &t.clock) 697 } 698 699 // ChannelNotifier is a Listener that sends on a channel. 700 // 701 // ChannelNotifier cannot be saved or loaded. 702 type ChannelNotifier chan struct{} 703 704 // NewChannelNotifier creates a new channel notifier. 705 // 706 // If the notifier is used with a timer, Timer.Destroy will close the channel 707 // returned here. 708 func NewChannelNotifier() (Listener, <-chan struct{}) { 709 tchan := make(chan struct{}, 1) 710 return ChannelNotifier(tchan), tchan 711 } 712 713 // NotifyTimer implements Listener.NotifyTimer. 714 func (c ChannelNotifier) NotifyTimer(uint64, Setting) (Setting, bool) { 715 select { 716 case c <- struct{}{}: 717 default: 718 } 719 720 return Setting{}, false 721 }