pipe.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // Copyright 2010 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package deadline
  5. import (
  6. "sync"
  7. "time"
  8. )
  9. // pipeDeadline is an abstraction for handling timeouts.
  10. type pipeDeadline struct {
  11. mu sync.Mutex // Guards timer and cancel
  12. timer *time.Timer
  13. cancel chan struct{} // Must be non-nil
  14. }
  15. func makePipeDeadline() pipeDeadline {
  16. return pipeDeadline{cancel: make(chan struct{})}
  17. }
  18. // set sets the point in time when the deadline will time out.
  19. // A timeout event is signaled by closing the channel returned by waiter.
  20. // Once a timeout has occurred, the deadline can be refreshed by specifying a
  21. // t value in the future.
  22. //
  23. // A zero value for t prevents timeout.
  24. func (d *pipeDeadline) set(t time.Time) {
  25. d.mu.Lock()
  26. defer d.mu.Unlock()
  27. if d.timer != nil && !d.timer.Stop() {
  28. <-d.cancel // Wait for the timer callback to finish and close cancel
  29. }
  30. d.timer = nil
  31. // Time is zero, then there is no deadline.
  32. closed := isClosedChan(d.cancel)
  33. if t.IsZero() {
  34. if closed {
  35. d.cancel = make(chan struct{})
  36. }
  37. return
  38. }
  39. // Time in the future, setup a timer to cancel in the future.
  40. if dur := time.Until(t); dur > 0 {
  41. if closed {
  42. d.cancel = make(chan struct{})
  43. }
  44. d.timer = time.AfterFunc(dur, func() {
  45. close(d.cancel)
  46. })
  47. return
  48. }
  49. // Time in the past, so close immediately.
  50. if !closed {
  51. close(d.cancel)
  52. }
  53. }
  54. // wait returns a channel that is closed when the deadline is exceeded.
  55. func (d *pipeDeadline) wait() chan struct{} {
  56. d.mu.Lock()
  57. defer d.mu.Unlock()
  58. return d.cancel
  59. }
  60. func isClosedChan(c <-chan struct{}) bool {
  61. select {
  62. case <-c:
  63. return true
  64. default:
  65. return false
  66. }
  67. }
  68. func makeFilledChan() chan struct{} {
  69. ch := make(chan struct{}, 1)
  70. ch <- struct{}{}
  71. return ch
  72. }