deadline.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Package deadline provides deadline timer used to implement
  2. // net.Conn compatible connection
  3. package deadline
  4. import (
  5. "context"
  6. "sync"
  7. "time"
  8. )
  9. // Deadline signals updatable deadline timer.
  10. // Also, it implements context.Context.
  11. type Deadline struct {
  12. exceeded chan struct{}
  13. stop chan struct{}
  14. stopped chan bool
  15. deadline time.Time
  16. mu sync.RWMutex
  17. }
  18. // New creates new deadline timer.
  19. func New() *Deadline {
  20. d := &Deadline{
  21. exceeded: make(chan struct{}),
  22. stop: make(chan struct{}),
  23. stopped: make(chan bool, 1),
  24. }
  25. d.stopped <- true
  26. return d
  27. }
  28. // Set new deadline. Zero value means no deadline.
  29. func (d *Deadline) Set(t time.Time) {
  30. d.mu.Lock()
  31. defer d.mu.Unlock()
  32. d.deadline = t
  33. close(d.stop)
  34. select {
  35. case <-d.exceeded:
  36. d.exceeded = make(chan struct{})
  37. default:
  38. stopped := <-d.stopped
  39. if !stopped {
  40. d.exceeded = make(chan struct{})
  41. }
  42. }
  43. d.stop = make(chan struct{})
  44. d.stopped = make(chan bool, 1)
  45. if t.IsZero() {
  46. d.stopped <- true
  47. return
  48. }
  49. if dur := time.Until(t); dur > 0 {
  50. exceeded := d.exceeded
  51. stopped := d.stopped
  52. go func() {
  53. select {
  54. case <-time.After(dur):
  55. close(exceeded)
  56. stopped <- false
  57. case <-d.stop:
  58. stopped <- true
  59. }
  60. }()
  61. return
  62. }
  63. close(d.exceeded)
  64. d.stopped <- false
  65. }
  66. // Done receives deadline signal.
  67. func (d *Deadline) Done() <-chan struct{} {
  68. d.mu.RLock()
  69. defer d.mu.RUnlock()
  70. return d.exceeded
  71. }
  72. // Err returns context.DeadlineExceeded if the deadline is exceeded.
  73. // Otherwise, it returns nil.
  74. func (d *Deadline) Err() error {
  75. d.mu.RLock()
  76. defer d.mu.RUnlock()
  77. select {
  78. case <-d.exceeded:
  79. return context.DeadlineExceeded
  80. default:
  81. return nil
  82. }
  83. }
  84. // Deadline returns current deadline.
  85. func (d *Deadline) Deadline() (time.Time, bool) {
  86. d.mu.RLock()
  87. defer d.mu.RUnlock()
  88. if d.deadline.IsZero() {
  89. return d.deadline, false
  90. }
  91. return d.deadline, true
  92. }
  93. // Value returns nil.
  94. func (d *Deadline) Value(interface{}) interface{} {
  95. return nil
  96. }