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.

77 lines
1.5 KiB

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