OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "platform/thread.h" | 5 #include "platform/thread.h" |
6 | 6 |
7 #include <process.h> | 7 #include <process.h> |
8 | 8 |
9 #include "platform/assert.h" | 9 #include "platform/assert.h" |
10 | 10 |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
131 void Mutex::Unlock() { | 131 void Mutex::Unlock() { |
132 BOOL result = ReleaseSemaphore(data_.semaphore_, 1, NULL); | 132 BOOL result = ReleaseSemaphore(data_.semaphore_, 1, NULL); |
133 if (result == 0) { | 133 if (result == 0) { |
134 FATAL("Mutex unlock failed"); | 134 FATAL("Mutex unlock failed"); |
135 } | 135 } |
136 } | 136 } |
137 | 137 |
138 | 138 |
139 Monitor::Monitor() { | 139 Monitor::Monitor() { |
140 InitializeCriticalSection(&data_.cs_); | 140 InitializeCriticalSection(&data_.cs_); |
141 InitializeConditionVariable(&data_.cond_); | 141 // Create auto-reset event used to implement Notify. Auto-reset |
142 // events only wake one thread waiting for them on SetEvent. | |
143 data_.notify_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); | |
144 // Create manual-reset event used to implement | |
145 // NotifyAll. Manual-reset events wake all threads waiting for them | |
146 // on SetEvent. | |
147 data_.notify_all_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); | |
148 if ((data_.notify_event_ == NULL) || (data_.notify_all_event_ == NULL)) { | |
149 FATAL("Failed allocating event object for monitor"); | |
150 } | |
151 InitializeCriticalSection(&data_.waiters_cs_); | |
152 data_.waiters_ = 0; | |
142 } | 153 } |
143 | 154 |
144 | 155 |
145 Monitor::~Monitor() { | 156 Monitor::~Monitor() { |
146 DeleteCriticalSection(&data_.cs_); | 157 DeleteCriticalSection(&data_.cs_); |
158 CloseHandle(data_.notify_event_); | |
159 CloseHandle(data_.notify_all_event_); | |
160 DeleteCriticalSection(&data_.waiters_cs_); | |
147 } | 161 } |
148 | 162 |
149 | 163 |
150 void Monitor::Enter() { | 164 void Monitor::Enter() { |
151 EnterCriticalSection(&data_.cs_); | 165 EnterCriticalSection(&data_.cs_); |
152 } | 166 } |
153 | 167 |
154 | 168 |
155 void Monitor::Exit() { | 169 void Monitor::Exit() { |
156 LeaveCriticalSection(&data_.cs_); | 170 LeaveCriticalSection(&data_.cs_); |
157 } | 171 } |
158 | 172 |
159 | 173 |
160 Monitor::WaitResult Monitor::Wait(int64_t millis) { | 174 Monitor::WaitResult Monitor::Wait(int64_t millis) { |
161 Monitor::WaitResult retval = kNotified; | 175 Monitor::WaitResult retval = kNotified; |
176 | |
177 // Record the fact that we will start waiting. This is used to only | |
178 // reset the notify all event when all waiting threads have dealt | |
179 // with the event. | |
180 EnterCriticalSection(&data_.waiters_cs_); | |
181 data_.waiters_++; | |
182 LeaveCriticalSection(&data_.waiters_cs_); | |
183 | |
184 // Leave the monitor critical section while waiting. | |
185 LeaveCriticalSection(&data_.cs_); | |
186 | |
187 // Perform the actual wait using wait for multiple objects on both | |
188 // the notify and the notify all events. | |
189 static const intptr_t kNotifyEventIndex = 0; | |
190 static const intptr_t kNotifyAllEventIndex = 1; | |
191 static const intptr_t kNumberOfEvents = 2; | |
192 HANDLE events[kNumberOfEvents]; | |
193 events[kNotifyEventIndex] = data_.notify_event_; | |
194 events[kNotifyAllEventIndex] = data_.notify_all_event_; | |
195 | |
196 DWORD result = WAIT_FAILED; | |
162 if (millis == 0) { | 197 if (millis == 0) { |
163 // Wait forever. | 198 // Wait forever for a Notify or a NotifyAll event. |
164 BOOL result = SleepConditionVariableCS(&data_.cond_, &data_.cs_, INFINITE); | 199 result = WaitForMultipleObjects(2, events, FALSE, INFINITE); |
165 if (result == 0) { | 200 if (result == WAIT_FAILED) { |
166 FATAL("Monitor::Wait failed"); | 201 FATAL("Monitor::Wait failed"); |
167 } | 202 } |
168 } else { | 203 } else { |
169 BOOL result = SleepConditionVariableCS(&data_.cond_, &data_.cs_, millis); | 204 // Wait for the given period of time for a Notify or a NotifyAll |
170 if (result == 0) { | 205 // event. |
171 DWORD error = GetLastError(); | 206 result = WaitForMultipleObjects(2, events, FALSE, millis); |
172 // Windows condition variables should set error to WAIT_TIMEOUT | 207 if (result == WAIT_FAILED) { |
173 // but occationally sets it to ERROR_TIMEOUT for timeouts. On | 208 FATAL("Monitor::Wait with timeout failed"); |
174 // Windows 7 it seems to pretty consistently set it to | 209 } |
175 // ERROR_TIMEOUT. | 210 if (result == WAIT_TIMEOUT) { |
176 if ((error == WAIT_TIMEOUT) || (error == ERROR_TIMEOUT)) { | 211 retval = kTimedOut; |
177 retval = kTimedOut; | |
178 } else { | |
179 FATAL("Monitor::Wait failed"); | |
180 } | |
181 } | 212 } |
182 } | 213 } |
214 | |
215 // Check if we are the last waiter on a notify all. If we are, reset | |
216 // the notify all event. | |
217 EnterCriticalSection(&data_.waiters_cs_); | |
Søren Gjesse
2012/02/08 15:32:58
I am wondering whether we can get into a situation
| |
218 data_.waiters_--; | |
219 if ((data_.waiters_ == 0) && | |
220 (result == (WAIT_OBJECT_0 + kNotifyAllEventIndex))) { | |
221 ResetEvent(data_.notify_all_event_); | |
222 } | |
223 LeaveCriticalSection(&data_.waiters_cs_); | |
224 | |
225 // Reacquire the monitor critical section before continuing. | |
226 EnterCriticalSection(&data_.cs_); | |
227 | |
183 return retval; | 228 return retval; |
184 } | 229 } |
185 | 230 |
186 | 231 |
187 void Monitor::Notify() { | 232 void Monitor::Notify() { |
188 WakeConditionVariable(&data_.cond_); | 233 // Signal one waiter through the notify auto-reset event if there |
234 // are any waiters. | |
235 EnterCriticalSection(&data_.waiters_cs_); | |
236 if (data_.waiters_ > 0) { | |
237 SetEvent(data_.notify_event_); | |
238 } | |
239 LeaveCriticalSection(&data_.waiters_cs_); | |
189 } | 240 } |
190 | 241 |
191 | 242 |
192 void Monitor::NotifyAll() { | 243 void Monitor::NotifyAll() { |
193 WakeAllConditionVariable(&data_.cond_); | 244 // Signal all waiters through the notify all manual-reset event if |
245 // there are any waiters. | |
246 EnterCriticalSection(&data_.waiters_cs_); | |
247 if (data_.waiters_ > 0) { | |
248 SetEvent(data_.notify_all_event_); | |
249 } | |
250 LeaveCriticalSection(&data_.waiters_cs_); | |
194 } | 251 } |
195 | 252 |
196 } // namespace dart | 253 } // namespace dart |
OLD | NEW |