Chromium Code Reviews| 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 |