clock.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package tstest
  4. import (
  5. "container/heap"
  6. "sync"
  7. "time"
  8. "tailscale.com/tstime"
  9. "tailscale.com/util/mak"
  10. )
  11. // ClockOpts is used to configure the initial settings for a Clock. Once the
  12. // settings are configured as desired, call NewClock to get the resulting Clock.
  13. type ClockOpts struct {
  14. // Start is the starting time for the Clock. When FollowRealTime is false,
  15. // Start is also the value that will be returned by the first call
  16. // to Clock.Now.
  17. Start time.Time
  18. // Step is the amount of time the Clock will advance whenever Clock.Now is
  19. // called. If set to zero, the Clock will only advance when Clock.Advance is
  20. // called and/or if FollowRealTime is true.
  21. //
  22. // FollowRealTime and Step cannot be enabled at the same time.
  23. Step time.Duration
  24. // TimerChannelSize configures the maximum buffered ticks that are
  25. // permitted in the channel of any Timer and Ticker created by this Clock.
  26. // The special value 0 means to use the default of 1. The buffer may need to
  27. // be increased if time is advanced by more than a single tick and proper
  28. // functioning of the test requires that the ticks are not lost.
  29. TimerChannelSize int
  30. // FollowRealTime makes the simulated time increment along with real time.
  31. // It is a compromise between determinism and the difficulty of explicitly
  32. // managing the simulated time via Step or Clock.Advance. When
  33. // FollowRealTime is set, calls to Now() and PeekNow() will add the
  34. // elapsed real-world time to the simulated time.
  35. //
  36. // FollowRealTime and Step cannot be enabled at the same time.
  37. FollowRealTime bool
  38. }
  39. // NewClock creates a Clock with the specified settings. To create a
  40. // Clock with only the default settings, new(Clock) is equivalent, except that
  41. // the start time will not be computed until one of the receivers is called.
  42. func NewClock(co ClockOpts) *Clock {
  43. if co.FollowRealTime && co.Step != 0 {
  44. panic("only one of FollowRealTime and Step are allowed in NewClock")
  45. }
  46. return newClockInternal(co, nil)
  47. }
  48. // newClockInternal creates a Clock with the specified settings and allows
  49. // specifying a non-standard realTimeClock.
  50. func newClockInternal(co ClockOpts, rtClock tstime.Clock) *Clock {
  51. if !co.FollowRealTime && rtClock != nil {
  52. panic("rtClock can only be set with FollowRealTime enabled")
  53. }
  54. if co.FollowRealTime && rtClock == nil {
  55. rtClock = new(tstime.StdClock)
  56. }
  57. c := &Clock{
  58. start: co.Start,
  59. realTimeClock: rtClock,
  60. step: co.Step,
  61. timerChannelSize: co.TimerChannelSize,
  62. }
  63. c.init() // init now to capture the current time when co.Start.IsZero()
  64. return c
  65. }
  66. // Clock is a testing clock that advances every time its Now method is
  67. // called, beginning at its start time. If no start time is specified using
  68. // ClockBuilder, an arbitrary start time will be selected when the Clock is
  69. // created and can be retrieved by calling Clock.Start().
  70. type Clock struct {
  71. // start is the first value returned by Now. It must not be modified after
  72. // init is called.
  73. start time.Time
  74. // realTimeClock, if not nil, indicates that the Clock shall move forward
  75. // according to realTimeClock + the accumulated calls to Advance. This can
  76. // make writing tests easier that require some control over the clock but do
  77. // not need exact control over the clock. While step can also be used for
  78. // this purpose, it is harder to control how quickly time moves using step.
  79. realTimeClock tstime.Clock
  80. initOnce sync.Once
  81. mu sync.Mutex
  82. // step is how much to advance with each Now call.
  83. step time.Duration
  84. // present is the last value returned by Now (and will be returned again by
  85. // PeekNow).
  86. present time.Time
  87. // realTime is the time from realTimeClock corresponding to the current
  88. // value of present.
  89. realTime time.Time
  90. // skipStep indicates that the next call to Now should not add step to
  91. // present. This occurs after initialization and after Advance.
  92. skipStep bool
  93. // timerChannelSize is the buffer size to use for channels created by
  94. // NewTimer and NewTicker.
  95. timerChannelSize int
  96. events eventManager
  97. }
  98. func (c *Clock) init() {
  99. c.initOnce.Do(func() {
  100. if c.realTimeClock != nil {
  101. c.realTime = c.realTimeClock.Now()
  102. }
  103. if c.start.IsZero() {
  104. if c.realTime.IsZero() {
  105. c.start = time.Now()
  106. } else {
  107. c.start = c.realTime
  108. }
  109. }
  110. if c.timerChannelSize == 0 {
  111. c.timerChannelSize = 1
  112. }
  113. c.present = c.start
  114. c.skipStep = true
  115. c.events.AdvanceTo(c.present)
  116. })
  117. }
  118. // Now returns the virtual clock's current time, and advances it
  119. // according to its step configuration.
  120. func (c *Clock) Now() time.Time {
  121. c.init()
  122. rt := c.maybeGetRealTime()
  123. c.mu.Lock()
  124. defer c.mu.Unlock()
  125. step := c.step
  126. if c.skipStep {
  127. step = 0
  128. c.skipStep = false
  129. }
  130. c.advanceLocked(rt, step)
  131. return c.present
  132. }
  133. func (c *Clock) maybeGetRealTime() time.Time {
  134. if c.realTimeClock == nil {
  135. return time.Time{}
  136. }
  137. return c.realTimeClock.Now()
  138. }
  139. func (c *Clock) advanceLocked(now time.Time, add time.Duration) {
  140. if !now.IsZero() {
  141. add += now.Sub(c.realTime)
  142. c.realTime = now
  143. }
  144. if add == 0 {
  145. return
  146. }
  147. c.present = c.present.Add(add)
  148. c.events.AdvanceTo(c.present)
  149. }
  150. // PeekNow returns the last time reported by Now. If Now has never been called,
  151. // PeekNow returns the same value as GetStart.
  152. func (c *Clock) PeekNow() time.Time {
  153. c.init()
  154. c.mu.Lock()
  155. defer c.mu.Unlock()
  156. return c.present
  157. }
  158. // Advance moves simulated time forward or backwards by a relative amount. Any
  159. // Timer or Ticker that is waiting will fire at the requested point in simulated
  160. // time. Advance returns the new simulated time. If this Clock follows real time
  161. // then the next call to Now will equal the return value of Advance + the
  162. // elapsed time since calling Advance. Otherwise, the next call to Now will
  163. // equal the return value of Advance, regardless of the current step.
  164. func (c *Clock) Advance(d time.Duration) time.Time {
  165. c.init()
  166. rt := c.maybeGetRealTime()
  167. c.mu.Lock()
  168. defer c.mu.Unlock()
  169. c.skipStep = true
  170. c.advanceLocked(rt, d)
  171. return c.present
  172. }
  173. // AdvanceTo moves simulated time to a new absolute value. Any Timer or Ticker
  174. // that is waiting will fire at the requested point in simulated time. If this
  175. // Clock follows real time then the next call to Now will equal t + the elapsed
  176. // time since calling Advance. Otherwise, the next call to Now will equal t,
  177. // regardless of the configured step.
  178. func (c *Clock) AdvanceTo(t time.Time) {
  179. c.init()
  180. rt := c.maybeGetRealTime()
  181. c.mu.Lock()
  182. defer c.mu.Unlock()
  183. c.skipStep = true
  184. c.realTime = rt
  185. c.present = t
  186. c.events.AdvanceTo(c.present)
  187. }
  188. // GetStart returns the initial simulated time when this Clock was created.
  189. func (c *Clock) GetStart() time.Time {
  190. c.init()
  191. c.mu.Lock()
  192. defer c.mu.Unlock()
  193. return c.start
  194. }
  195. // GetStep returns the amount that simulated time advances on every call to Now.
  196. func (c *Clock) GetStep() time.Duration {
  197. c.init()
  198. c.mu.Lock()
  199. defer c.mu.Unlock()
  200. return c.step
  201. }
  202. // SetStep updates the amount that simulated time advances on every call to Now.
  203. func (c *Clock) SetStep(d time.Duration) {
  204. c.init()
  205. c.mu.Lock()
  206. defer c.mu.Unlock()
  207. c.step = d
  208. }
  209. // SetTimerChannelSize changes the channel size for any Timer or Ticker created
  210. // in the future. It does not affect those that were already created.
  211. func (c *Clock) SetTimerChannelSize(n int) {
  212. c.init()
  213. c.mu.Lock()
  214. defer c.mu.Unlock()
  215. c.timerChannelSize = n
  216. }
  217. // NewTicker returns a Ticker that uses this Clock for accessing the current
  218. // time.
  219. func (c *Clock) NewTicker(d time.Duration) (tstime.TickerController, <-chan time.Time) {
  220. c.init()
  221. rt := c.maybeGetRealTime()
  222. c.mu.Lock()
  223. defer c.mu.Unlock()
  224. c.advanceLocked(rt, 0)
  225. t := &Ticker{
  226. nextTrigger: c.present.Add(d),
  227. period: d,
  228. em: &c.events,
  229. }
  230. t.init(c.timerChannelSize)
  231. return t, t.C
  232. }
  233. // NewTimer returns a Timer that uses this Clock for accessing the current
  234. // time.
  235. func (c *Clock) NewTimer(d time.Duration) (tstime.TimerController, <-chan time.Time) {
  236. c.init()
  237. rt := c.maybeGetRealTime()
  238. c.mu.Lock()
  239. defer c.mu.Unlock()
  240. c.advanceLocked(rt, 0)
  241. t := &Timer{
  242. nextTrigger: c.present.Add(d),
  243. em: &c.events,
  244. }
  245. t.init(c.timerChannelSize, nil)
  246. return t, t.C
  247. }
  248. // AfterFunc returns a Timer that calls f when it fires, using this Clock for
  249. // accessing the current time.
  250. func (c *Clock) AfterFunc(d time.Duration, f func()) tstime.TimerController {
  251. c.init()
  252. rt := c.maybeGetRealTime()
  253. c.mu.Lock()
  254. defer c.mu.Unlock()
  255. c.advanceLocked(rt, 0)
  256. t := &Timer{
  257. nextTrigger: c.present.Add(d),
  258. em: &c.events,
  259. }
  260. t.init(c.timerChannelSize, f)
  261. return t
  262. }
  263. // Since subtracts specified duration from Now().
  264. func (c *Clock) Since(t time.Time) time.Duration {
  265. return c.Now().Sub(t)
  266. }
  267. // eventHandler offers a common interface for Timer and Ticker events to avoid
  268. // code duplication in eventManager.
  269. type eventHandler interface {
  270. // Fire signals the event. The provided time is written to the event's
  271. // channel as the current time. The return value is the next time this event
  272. // should fire, otherwise if it is zero then the event will be removed from
  273. // the eventManager.
  274. Fire(time.Time) time.Time
  275. }
  276. // event tracks details about an upcoming Timer or Ticker firing.
  277. type event struct {
  278. position int // The current index in the heap, needed for heap.Fix and heap.Remove.
  279. when time.Time // A cache of the next time the event triggers to avoid locking issues if we were to get it from eh.
  280. eh eventHandler
  281. }
  282. // eventManager tracks pending events created by Timer and Ticker. eventManager
  283. // implements heap.Interface for efficient lookups of the next event.
  284. type eventManager struct {
  285. // clock is a real time clock for scheduling events with. When clock is nil,
  286. // events only fire when AdvanceTo is called by the simulated clock that
  287. // this eventManager belongs to. When clock is not nil, events may fire when
  288. // timer triggers.
  289. clock tstime.Clock
  290. mu sync.Mutex
  291. now time.Time
  292. heap []*event
  293. reverseLookup map[eventHandler]*event
  294. // timer is an AfterFunc that triggers at heap[0].when.Sub(now) relative to
  295. // the time represented by clock. In other words, if clock is real world
  296. // time, then if an event is scheduled 1 second into the future in the
  297. // simulated time, then the event will trigger after 1 second of actual test
  298. // execution time (unless the test advances simulated time, in which case
  299. // the timer is updated accordingly). This makes tests easier to write in
  300. // situations where the simulated time only needs to be partially
  301. // controlled, and the test writer wishes for simulated time to pass with an
  302. // offset but still synchronized with the real world.
  303. //
  304. // In the future, this could be extended to allow simulated time to run at a
  305. // multiple of real world time.
  306. timer tstime.TimerController
  307. }
  308. func (em *eventManager) handleTimer() {
  309. rt := em.clock.Now()
  310. em.AdvanceTo(rt)
  311. }
  312. // Push implements heap.Interface.Push and must only be called by heap funcs
  313. // with em.mu already held.
  314. func (em *eventManager) Push(x any) {
  315. e, ok := x.(*event)
  316. if !ok {
  317. panic("incorrect event type")
  318. }
  319. if e == nil {
  320. panic("nil event")
  321. }
  322. mak.Set(&em.reverseLookup, e.eh, e)
  323. e.position = len(em.heap)
  324. em.heap = append(em.heap, e)
  325. }
  326. // Pop implements heap.Interface.Pop and must only be called by heap funcs with
  327. // em.mu already held.
  328. func (em *eventManager) Pop() any {
  329. e := em.heap[len(em.heap)-1]
  330. em.heap = em.heap[:len(em.heap)-1]
  331. delete(em.reverseLookup, e.eh)
  332. return e
  333. }
  334. // Len implements sort.Interface.Len and must only be called by heap funcs with
  335. // em.mu already held.
  336. func (em *eventManager) Len() int {
  337. return len(em.heap)
  338. }
  339. // Less implements sort.Interface.Less and must only be called by heap funcs
  340. // with em.mu already held.
  341. func (em *eventManager) Less(i, j int) bool {
  342. return em.heap[i].when.Before(em.heap[j].when)
  343. }
  344. // Swap implements sort.Interface.Swap and must only be called by heap funcs
  345. // with em.mu already held.
  346. func (em *eventManager) Swap(i, j int) {
  347. em.heap[i], em.heap[j] = em.heap[j], em.heap[i]
  348. em.heap[i].position = i
  349. em.heap[j].position = j
  350. }
  351. // Reschedule adds/updates/deletes an event in the heap, whichever
  352. // operation is applicable (use a zero time to delete).
  353. func (em *eventManager) Reschedule(eh eventHandler, t time.Time) {
  354. em.mu.Lock()
  355. defer em.mu.Unlock()
  356. defer em.updateTimerLocked()
  357. e, ok := em.reverseLookup[eh]
  358. if !ok {
  359. if t.IsZero() {
  360. // eh is not scheduled and also not active, so do nothing.
  361. return
  362. }
  363. // eh is not scheduled but is active, so add it.
  364. heap.Push(em, &event{
  365. when: t,
  366. eh: eh,
  367. })
  368. em.processEventsLocked(em.now) // This is always safe and required when !t.After(em.now).
  369. return
  370. }
  371. if t.IsZero() {
  372. // e is scheduled but not active, so remove it.
  373. heap.Remove(em, e.position)
  374. return
  375. }
  376. // e is scheduled and active, so update it.
  377. e.when = t
  378. heap.Fix(em, e.position)
  379. em.processEventsLocked(em.now) // This is always safe and required when !t.After(em.now).
  380. }
  381. // AdvanceTo updates the current time to tm and fires all events scheduled
  382. // before or equal to tm. When an event fires, it may request rescheduling and
  383. // the rescheduled events will be combined with the other existing events that
  384. // are waiting, and will be run in the unified ordering. A poorly behaved event
  385. // may theoretically prevent this from ever completing, but both Timer and
  386. // Ticker require positive steps into the future.
  387. func (em *eventManager) AdvanceTo(tm time.Time) {
  388. em.mu.Lock()
  389. defer em.mu.Unlock()
  390. defer em.updateTimerLocked()
  391. em.processEventsLocked(tm)
  392. em.now = tm
  393. }
  394. // Now returns the cached current time. It is intended for use by a Timer or
  395. // Ticker that needs to convert a relative time to an absolute time.
  396. func (em *eventManager) Now() time.Time {
  397. em.mu.Lock()
  398. defer em.mu.Unlock()
  399. return em.now
  400. }
  401. func (em *eventManager) processEventsLocked(tm time.Time) {
  402. for len(em.heap) > 0 && !em.heap[0].when.After(tm) {
  403. // Ideally some jitter would be added here but it's difficult to do so
  404. // in a deterministic fashion.
  405. em.now = em.heap[0].when
  406. if nextFire := em.heap[0].eh.Fire(em.now); !nextFire.IsZero() {
  407. em.heap[0].when = nextFire
  408. heap.Fix(em, 0)
  409. } else {
  410. heap.Pop(em)
  411. }
  412. }
  413. }
  414. func (em *eventManager) updateTimerLocked() {
  415. if em.clock == nil {
  416. return
  417. }
  418. if len(em.heap) == 0 {
  419. if em.timer != nil {
  420. em.timer.Stop()
  421. }
  422. return
  423. }
  424. timeToEvent := em.heap[0].when.Sub(em.now)
  425. if em.timer == nil {
  426. em.timer = em.clock.AfterFunc(timeToEvent, em.handleTimer)
  427. return
  428. }
  429. em.timer.Reset(timeToEvent)
  430. }
  431. // Ticker is a time.Ticker lookalike for use in tests that need to control when
  432. // events fire. Ticker could be made standalone in future but for now is
  433. // expected to be paired with a Clock and created by Clock.NewTicker.
  434. type Ticker struct {
  435. C <-chan time.Time // The channel on which ticks are delivered.
  436. // em is the eventManager to be notified when nextTrigger changes.
  437. // eventManager has its own mutex, and the pointer is immutable, therefore
  438. // em can be accessed without holding mu.
  439. em *eventManager
  440. c chan<- time.Time // The writer side of C.
  441. mu sync.Mutex
  442. // nextTrigger is the time of the ticker's next scheduled activation. When
  443. // Fire activates the ticker, nextTrigger is the timestamp written to the
  444. // channel.
  445. nextTrigger time.Time
  446. // period is the duration that is added to nextTrigger when the ticker
  447. // fires.
  448. period time.Duration
  449. }
  450. func (t *Ticker) init(channelSize int) {
  451. if channelSize <= 0 {
  452. panic("ticker channel size must be non-negative")
  453. }
  454. c := make(chan time.Time, channelSize)
  455. t.c = c
  456. t.C = c
  457. t.em.Reschedule(t, t.nextTrigger)
  458. }
  459. // Fire triggers the ticker. curTime is the timestamp to write to the channel.
  460. // The next trigger time for the ticker is updated to the last computed trigger
  461. // time + the ticker period (set at creation or using Reset). The next trigger
  462. // time is computed this way to match standard time.Ticker behavior, which
  463. // prevents accumulation of long term drift caused by delays in event execution.
  464. func (t *Ticker) Fire(curTime time.Time) time.Time {
  465. t.mu.Lock()
  466. defer t.mu.Unlock()
  467. if t.nextTrigger.IsZero() {
  468. return time.Time{}
  469. }
  470. select {
  471. case t.c <- curTime:
  472. default:
  473. }
  474. t.nextTrigger = t.nextTrigger.Add(t.period)
  475. return t.nextTrigger
  476. }
  477. // Reset adjusts the Ticker's period to d and reschedules the next fire time to
  478. // the current simulated time + d.
  479. func (t *Ticker) Reset(d time.Duration) {
  480. if d <= 0 {
  481. // The standard time.Ticker requires a positive period.
  482. panic("non-positive period for Ticker.Reset")
  483. }
  484. now := t.em.Now()
  485. t.mu.Lock()
  486. t.resetLocked(now.Add(d), d)
  487. t.mu.Unlock()
  488. t.em.Reschedule(t, t.nextTrigger)
  489. }
  490. // ResetAbsolute adjusts the Ticker's period to d and reschedules the next fire
  491. // time to nextTrigger.
  492. func (t *Ticker) ResetAbsolute(nextTrigger time.Time, d time.Duration) {
  493. if nextTrigger.IsZero() {
  494. panic("zero nextTrigger time for ResetAbsolute")
  495. }
  496. if d <= 0 {
  497. panic("non-positive period for ResetAbsolute")
  498. }
  499. t.mu.Lock()
  500. t.resetLocked(nextTrigger, d)
  501. t.mu.Unlock()
  502. t.em.Reschedule(t, t.nextTrigger)
  503. }
  504. func (t *Ticker) resetLocked(nextTrigger time.Time, d time.Duration) {
  505. t.nextTrigger = nextTrigger
  506. t.period = d
  507. }
  508. // Stop deactivates the Ticker.
  509. func (t *Ticker) Stop() {
  510. t.mu.Lock()
  511. t.nextTrigger = time.Time{}
  512. t.mu.Unlock()
  513. t.em.Reschedule(t, t.nextTrigger)
  514. }
  515. // Timer is a time.Timer lookalike for use in tests that need to control when
  516. // events fire. Timer could be made standalone in future but for now must be
  517. // paired with a Clock and created by Clock.NewTimer.
  518. type Timer struct {
  519. C <-chan time.Time // The channel on which ticks are delivered.
  520. // em is the eventManager to be notified when nextTrigger changes.
  521. // eventManager has its own mutex, and the pointer is immutable, therefore
  522. // em can be accessed without holding mu.
  523. em *eventManager
  524. f func(time.Time) // The function to call when the timer expires.
  525. mu sync.Mutex
  526. // nextTrigger is the time of the ticker's next scheduled activation. When
  527. // Fire activates the ticker, nextTrigger is the timestamp written to the
  528. // channel.
  529. nextTrigger time.Time
  530. }
  531. func (t *Timer) init(channelSize int, afterFunc func()) {
  532. if channelSize <= 0 {
  533. panic("ticker channel size must be non-negative")
  534. }
  535. c := make(chan time.Time, channelSize)
  536. t.C = c
  537. if afterFunc == nil {
  538. t.f = func(curTime time.Time) {
  539. select {
  540. case c <- curTime:
  541. default:
  542. }
  543. }
  544. } else {
  545. t.f = func(_ time.Time) { afterFunc() }
  546. }
  547. t.em.Reschedule(t, t.nextTrigger)
  548. }
  549. // Fire triggers the ticker. curTime is the timestamp to write to the channel.
  550. // The next trigger time for the ticker is updated to the last computed trigger
  551. // time + the ticker period (set at creation or using Reset). The next trigger
  552. // time is computed this way to match standard time.Ticker behavior, which
  553. // prevents accumulation of long term drift caused by delays in event execution.
  554. func (t *Timer) Fire(curTime time.Time) time.Time {
  555. t.mu.Lock()
  556. defer t.mu.Unlock()
  557. if t.nextTrigger.IsZero() {
  558. return time.Time{}
  559. }
  560. t.nextTrigger = time.Time{}
  561. t.f(curTime)
  562. return time.Time{}
  563. }
  564. // Reset reschedules the next fire time to the current simulated time + d.
  565. // Reset reports whether the timer was still active before the reset.
  566. func (t *Timer) Reset(d time.Duration) bool {
  567. if d <= 0 {
  568. // The standard time.Timer requires a positive delay.
  569. panic("non-positive delay for Timer.Reset")
  570. }
  571. return t.reset(t.em.Now().Add(d))
  572. }
  573. // ResetAbsolute reschedules the next fire time to nextTrigger.
  574. // ResetAbsolute reports whether the timer was still active before the reset.
  575. func (t *Timer) ResetAbsolute(nextTrigger time.Time) bool {
  576. if nextTrigger.IsZero() {
  577. panic("zero nextTrigger time for ResetAbsolute")
  578. }
  579. return t.reset(nextTrigger)
  580. }
  581. // Stop deactivates the Timer. Stop reports whether the timer was active before
  582. // stopping.
  583. func (t *Timer) Stop() bool {
  584. return t.reset(time.Time{})
  585. }
  586. func (t *Timer) reset(nextTrigger time.Time) bool {
  587. t.mu.Lock()
  588. wasActive := !t.nextTrigger.IsZero()
  589. t.nextTrigger = nextTrigger
  590. t.mu.Unlock()
  591. t.em.Reschedule(t, t.nextTrigger)
  592. return wasActive
  593. }