cond.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Copyright 2011 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 sync
  5. import (
  6. "sync/atomic"
  7. "unsafe"
  8. )
  9. // Cond implements a condition variable, a rendezvous point
  10. // for goroutines waiting for or announcing the occurrence
  11. // of an event.
  12. //
  13. // Each Cond has an associated Locker L (often a *Mutex or *RWMutex),
  14. // which must be held when changing the condition and
  15. // when calling the Wait method.
  16. //
  17. // A Cond can be created as part of other structures.
  18. // A Cond must not be copied after first use.
  19. type Cond struct {
  20. // L is held while observing or changing the condition
  21. L Locker
  22. sema syncSema
  23. waiters uint32 // number of waiters
  24. checker copyChecker
  25. }
  26. // NewCond returns a new Cond with Locker l.
  27. func NewCond(l Locker) *Cond {
  28. return &Cond{L: l}
  29. }
  30. // Wait atomically unlocks c.L and suspends execution
  31. // of the calling goroutine. After later resuming execution,
  32. // Wait locks c.L before returning. Unlike in other systems,
  33. // Wait cannot return unless awoken by Broadcast or Signal.
  34. //
  35. // Because c.L is not locked when Wait first resumes, the caller
  36. // typically cannot assume that the condition is true when
  37. // Wait returns. Instead, the caller should Wait in a loop:
  38. //
  39. // c.L.Lock()
  40. // for !condition() {
  41. // c.Wait()
  42. // }
  43. // ... make use of condition ...
  44. // c.L.Unlock()
  45. //
  46. func (c *Cond) Wait() {
  47. c.checker.check()
  48. if raceenabled {
  49. raceDisable()
  50. }
  51. atomic.AddUint32(&c.waiters, 1)
  52. if raceenabled {
  53. raceEnable()
  54. }
  55. c.L.Unlock()
  56. runtime_Syncsemacquire(&c.sema)
  57. c.L.Lock()
  58. }
  59. // Signal wakes one goroutine waiting on c, if there is any.
  60. //
  61. // It is allowed but not required for the caller to hold c.L
  62. // during the call.
  63. func (c *Cond) Signal() {
  64. c.signalImpl(false)
  65. }
  66. // Broadcast wakes all goroutines waiting on c.
  67. //
  68. // It is allowed but not required for the caller to hold c.L
  69. // during the call.
  70. func (c *Cond) Broadcast() {
  71. c.signalImpl(true)
  72. }
  73. func (c *Cond) signalImpl(all bool) {
  74. c.checker.check()
  75. if raceenabled {
  76. raceDisable()
  77. }
  78. for {
  79. old := atomic.LoadUint32(&c.waiters)
  80. if old == 0 {
  81. if raceenabled {
  82. raceEnable()
  83. }
  84. return
  85. }
  86. new := old - 1
  87. if all {
  88. new = 0
  89. }
  90. if atomic.CompareAndSwapUint32(&c.waiters, old, new) {
  91. if raceenabled {
  92. raceEnable()
  93. }
  94. runtime_Syncsemrelease(&c.sema, old-new)
  95. return
  96. }
  97. }
  98. }
  99. // copyChecker holds back pointer to itself to detect object copying.
  100. type copyChecker uintptr
  101. func (c *copyChecker) check() {
  102. if uintptr(*c) != uintptr(unsafe.Pointer(c)) &&
  103. !atomic.CompareAndSwapUintptr((*uintptr)(c), 0, uintptr(unsafe.Pointer(c))) &&
  104. uintptr(*c) != uintptr(unsafe.Pointer(c)) {
  105. panic("sync.Cond is copied")
  106. }
  107. }