OLD | NEW |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package sync | 5 package sync |
6 | 6 |
| 7 import ( |
| 8 "sync/atomic" |
| 9 "unsafe" |
| 10 ) |
| 11 |
7 // Cond implements a condition variable, a rendezvous point | 12 // Cond implements a condition variable, a rendezvous point |
8 // for goroutines waiting for or announcing the occurrence | 13 // for goroutines waiting for or announcing the occurrence |
9 // of an event. | 14 // of an event. |
10 // | 15 // |
11 // Each Cond has an associated Locker L (often a *Mutex or *RWMutex), | 16 // Each Cond has an associated Locker L (often a *Mutex or *RWMutex), |
12 // which must be held when changing the condition and | 17 // which must be held when changing the condition and |
13 // when calling the Wait method. | 18 // when calling the Wait method. |
| 19 // |
| 20 // A Cond can be created as part of other structures. |
| 21 // A Cond must not be copied after first use. |
14 type Cond struct { | 22 type Cond struct { |
15 » L Locker // held while observing or changing the condition | 23 » // L is held while observing or changing the condition |
16 » m Mutex // held to avoid internal races | 24 » L Locker |
17 | 25 |
18 » // We must be careful to make sure that when Signal | 26 » sema syncSema |
19 » // releases a semaphore, the corresponding acquire is | 27 » waiters uint32 // number of waiters |
20 » // executed by a goroutine that was already waiting at | 28 » checker copyChecker |
21 » // the time of the call to Signal, not one that arrived later. | |
22 » // To ensure this, we segment waiting goroutines into | |
23 » // generations punctuated by calls to Signal. Each call to | |
24 » // Signal begins another generation if there are no goroutines | |
25 » // left in older generations for it to wake. Because of this | |
26 » // optimization (only begin another generation if there | |
27 » // are no older goroutines left), we only need to keep track | |
28 » // of the two most recent generations, which we call old | |
29 » // and new. | |
30 » oldWaiters int // number of waiters in old generation... | |
31 » oldSema *uint32 // ... waiting on this semaphore | |
32 | |
33 » newWaiters int // number of waiters in new generation... | |
34 » newSema *uint32 // ... waiting on this semaphore | |
35 } | 29 } |
36 | 30 |
37 // NewCond returns a new Cond with Locker l. | 31 // NewCond returns a new Cond with Locker l. |
38 func NewCond(l Locker) *Cond { | 32 func NewCond(l Locker) *Cond { |
39 return &Cond{L: l} | 33 return &Cond{L: l} |
40 } | 34 } |
41 | 35 |
42 // Wait atomically unlocks c.L and suspends execution | 36 // Wait atomically unlocks c.L and suspends execution |
43 // of the calling goroutine. After later resuming execution, | 37 // of the calling goroutine. After later resuming execution, |
44 // Wait locks c.L before returning. Unlike in other systems, | 38 // Wait locks c.L before returning. Unlike in other systems, |
45 // Wait cannot return unless awoken by Broadcast or Signal. | 39 // Wait cannot return unless awoken by Broadcast or Signal. |
46 // | 40 // |
47 // Because c.L is not locked when Wait first resumes, the caller | 41 // Because c.L is not locked when Wait first resumes, the caller |
48 // typically cannot assume that the condition is true when | 42 // typically cannot assume that the condition is true when |
49 // Wait returns. Instead, the caller should Wait in a loop: | 43 // Wait returns. Instead, the caller should Wait in a loop: |
50 // | 44 // |
51 // c.L.Lock() | 45 // c.L.Lock() |
52 // for !condition() { | 46 // for !condition() { |
53 // c.Wait() | 47 // c.Wait() |
54 // } | 48 // } |
55 // ... make use of condition ... | 49 // ... make use of condition ... |
56 // c.L.Unlock() | 50 // c.L.Unlock() |
57 // | 51 // |
58 func (c *Cond) Wait() { | 52 func (c *Cond) Wait() { |
| 53 c.checker.check() |
59 if raceenabled { | 54 if raceenabled { |
60 _ = c.m.state | |
61 raceDisable() | 55 raceDisable() |
62 } | 56 } |
63 » c.m.Lock() | 57 » atomic.AddUint32(&c.waiters, 1) |
64 » if c.newSema == nil { | |
65 » » c.newSema = new(uint32) | |
66 » } | |
67 » s := c.newSema | |
68 » c.newWaiters++ | |
69 » c.m.Unlock() | |
70 if raceenabled { | 58 if raceenabled { |
71 raceEnable() | 59 raceEnable() |
72 } | 60 } |
73 c.L.Unlock() | 61 c.L.Unlock() |
74 » runtime_Semacquire(s) | 62 » runtime_Syncsemacquire(&c.sema) |
75 c.L.Lock() | 63 c.L.Lock() |
76 } | 64 } |
77 | 65 |
78 // Signal wakes one goroutine waiting on c, if there is any. | 66 // Signal wakes one goroutine waiting on c, if there is any. |
79 // | 67 // |
80 // It is allowed but not required for the caller to hold c.L | 68 // It is allowed but not required for the caller to hold c.L |
81 // during the call. | 69 // during the call. |
82 func (c *Cond) Signal() { | 70 func (c *Cond) Signal() { |
83 » if raceenabled { | 71 » c.signalImpl(false) |
84 » » _ = c.m.state | |
85 » » raceDisable() | |
86 » } | |
87 » c.m.Lock() | |
88 » if c.oldWaiters == 0 && c.newWaiters > 0 { | |
89 » » // Retire old generation; rename new to old. | |
90 » » c.oldWaiters = c.newWaiters | |
91 » » c.oldSema = c.newSema | |
92 » » c.newWaiters = 0 | |
93 » » c.newSema = nil | |
94 » } | |
95 » if c.oldWaiters > 0 { | |
96 » » c.oldWaiters-- | |
97 » » runtime_Semrelease(c.oldSema) | |
98 » } | |
99 » c.m.Unlock() | |
100 » if raceenabled { | |
101 » » raceEnable() | |
102 » } | |
103 } | 72 } |
104 | 73 |
105 // Broadcast wakes all goroutines waiting on c. | 74 // Broadcast wakes all goroutines waiting on c. |
106 // | 75 // |
107 // It is allowed but not required for the caller to hold c.L | 76 // It is allowed but not required for the caller to hold c.L |
108 // during the call. | 77 // during the call. |
109 func (c *Cond) Broadcast() { | 78 func (c *Cond) Broadcast() { |
| 79 c.signalImpl(true) |
| 80 } |
| 81 |
| 82 func (c *Cond) signalImpl(all bool) { |
| 83 c.checker.check() |
110 if raceenabled { | 84 if raceenabled { |
111 _ = c.m.state | |
112 raceDisable() | 85 raceDisable() |
113 } | 86 } |
114 » c.m.Lock() | 87 » for { |
115 » // Wake both generations. | 88 » » old := atomic.LoadUint32(&c.waiters) |
116 » if c.oldWaiters > 0 { | 89 » » if old == 0 { |
117 » » for i := 0; i < c.oldWaiters; i++ { | 90 » » » if raceenabled { |
118 » » » runtime_Semrelease(c.oldSema) | 91 » » » » raceEnable() |
| 92 » » » } |
| 93 » » » return |
119 } | 94 } |
120 » » c.oldWaiters = 0 | 95 » » new := old - 1 |
121 » } | 96 » » if all { |
122 » if c.newWaiters > 0 { | 97 » » » new = 0 |
123 » » for i := 0; i < c.newWaiters; i++ { | |
124 » » » runtime_Semrelease(c.newSema) | |
125 } | 98 } |
126 » » c.newWaiters = 0 | 99 » » if atomic.CompareAndSwapUint32(&c.waiters, old, new) { |
127 » » c.newSema = nil | 100 » » » if raceenabled { |
128 » } | 101 » » » » raceEnable() |
129 » c.m.Unlock() | 102 » » » } |
130 » if raceenabled { | 103 » » » runtime_Syncsemrelease(&c.sema, old-new) |
131 » » raceEnable() | 104 » » » return |
| 105 » » } |
132 } | 106 } |
133 } | 107 } |
| 108 |
| 109 // copyChecker holds back pointer to itself to detect object copying. |
| 110 type copyChecker uintptr |
| 111 |
| 112 func (c *copyChecker) check() { |
| 113 if uintptr(*c) != uintptr(unsafe.Pointer(c)) && |
| 114 !atomic.CompareAndSwapUintptr((*uintptr)(c), 0, uintptr(unsafe.P
ointer(c))) && |
| 115 uintptr(*c) != uintptr(unsafe.Pointer(c)) { |
| 116 panic("sync.Cond is copied") |
| 117 } |
| 118 } |
OLD | NEW |