You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

86 lines
1.6 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package common
  2. import (
  3. "sync"
  4. "time"
  5. )
  6. /*
  7. RepeatTimer repeatedly sends a struct{}{} to .Ch after each "dur" period.
  8. It's good for keeping connections alive.
  9. A RepeatTimer must be Stop()'d or it will keep a goroutine alive.
  10. */
  11. type RepeatTimer struct {
  12. Ch chan time.Time
  13. mtx sync.Mutex
  14. name string
  15. ticker *time.Ticker
  16. quit chan struct{}
  17. wg *sync.WaitGroup
  18. dur time.Duration
  19. }
  20. func NewRepeatTimer(name string, dur time.Duration) *RepeatTimer {
  21. var t = &RepeatTimer{
  22. Ch: make(chan time.Time),
  23. ticker: time.NewTicker(dur),
  24. quit: make(chan struct{}),
  25. wg: new(sync.WaitGroup),
  26. name: name,
  27. dur: dur,
  28. }
  29. t.wg.Add(1)
  30. go t.fireRoutine(t.ticker)
  31. return t
  32. }
  33. func (t *RepeatTimer) fireRoutine(ticker *time.Ticker) {
  34. for {
  35. select {
  36. case t_ := <-ticker.C:
  37. t.Ch <- t_
  38. case <-t.quit:
  39. // needed so we know when we can reset t.quit
  40. t.wg.Done()
  41. return
  42. }
  43. }
  44. }
  45. // Wait the duration again before firing.
  46. func (t *RepeatTimer) Reset() {
  47. t.Stop()
  48. t.mtx.Lock() // Lock
  49. defer t.mtx.Unlock()
  50. t.ticker = time.NewTicker(t.dur)
  51. t.quit = make(chan struct{})
  52. t.wg.Add(1)
  53. go t.fireRoutine(t.ticker)
  54. }
  55. // For ease of .Stop()'ing services before .Start()'ing them,
  56. // we ignore .Stop()'s on nil RepeatTimers.
  57. func (t *RepeatTimer) Stop() bool {
  58. if t == nil {
  59. return false
  60. }
  61. t.mtx.Lock() // Lock
  62. defer t.mtx.Unlock()
  63. exists := t.ticker != nil
  64. if exists {
  65. t.ticker.Stop() // does not close the channel
  66. select {
  67. case <-t.Ch:
  68. // read off channel if there's anything there
  69. default:
  70. }
  71. close(t.quit)
  72. t.wg.Wait() // must wait for quit to close else we race Reset
  73. t.ticker = nil
  74. }
  75. return exists
  76. }