| 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 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 | 129 |
| 130 | 130 |
| 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 ThreadLocalKey MonitorWaitData::monitor_wait_data_key_ = |
| 140 Thread::kUnsetThreadLocalKey; |
| 141 |
| 142 |
| 139 Monitor::Monitor() { | 143 Monitor::Monitor() { |
| 140 InitializeCriticalSection(&data_.cs_); | 144 InitializeCriticalSection(&data_.cs_); |
| 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_); | 145 InitializeCriticalSection(&data_.waiters_cs_); |
| 152 data_.waiters_ = 0; | 146 data_.waiters_head_ = NULL; |
| 147 data_.waiters_tail_ = NULL; |
| 153 } | 148 } |
| 154 | 149 |
| 155 | 150 |
| 156 Monitor::~Monitor() { | 151 Monitor::~Monitor() { |
| 157 DeleteCriticalSection(&data_.cs_); | 152 DeleteCriticalSection(&data_.cs_); |
| 158 CloseHandle(data_.notify_event_); | |
| 159 CloseHandle(data_.notify_all_event_); | |
| 160 DeleteCriticalSection(&data_.waiters_cs_); | 153 DeleteCriticalSection(&data_.waiters_cs_); |
| 161 } | 154 } |
| 162 | 155 |
| 163 | 156 |
| 164 void Monitor::Enter() { | 157 void Monitor::Enter() { |
| 165 EnterCriticalSection(&data_.cs_); | 158 EnterCriticalSection(&data_.cs_); |
| 166 } | 159 } |
| 167 | 160 |
| 168 | 161 |
| 169 void Monitor::Exit() { | 162 void Monitor::Exit() { |
| 170 LeaveCriticalSection(&data_.cs_); | 163 LeaveCriticalSection(&data_.cs_); |
| 171 } | 164 } |
| 172 | 165 |
| 173 | 166 |
| 167 void MonitorData::AddWaiter(MonitorWaitData* wait_data) { |
| 168 // Add the MonitorWaitData object to the list of objects waiting for |
| 169 // this monitor. |
| 170 EnterCriticalSection(&waiters_cs_); |
| 171 if (waiters_tail_ == NULL) { |
| 172 ASSERT(waiters_head_ == NULL); |
| 173 waiters_head_ = waiters_tail_ = wait_data; |
| 174 } else { |
| 175 waiters_tail_->next_ = wait_data; |
| 176 waiters_tail_ = wait_data; |
| 177 } |
| 178 LeaveCriticalSection(&waiters_cs_); |
| 179 } |
| 180 |
| 181 |
| 182 void MonitorData::RemoveWaiter(MonitorWaitData* wait_data) { |
| 183 // Remove the MonitorWaitData object from the list of objects |
| 184 // waiting for this monitor. |
| 185 EnterCriticalSection(&waiters_cs_); |
| 186 MonitorWaitData* previous = NULL; |
| 187 MonitorWaitData* current = waiters_head_; |
| 188 while (current != NULL) { |
| 189 if (current == wait_data) { |
| 190 if (waiters_head_ == waiters_tail_) { |
| 191 waiters_head_ = waiters_tail_ = NULL; |
| 192 } else if (current == waiters_head_) { |
| 193 waiters_head_ = waiters_head_->next_; |
| 194 } else if (current == waiters_tail_) { |
| 195 ASSERT(previous != NULL); |
| 196 waiters_tail_ = previous; |
| 197 previous->next_ = NULL; |
| 198 } else { |
| 199 ASSERT(previous != NULL); |
| 200 previous->next_ = current->next_; |
| 201 } |
| 202 break; |
| 203 } |
| 204 previous = current; |
| 205 current = current->next_; |
| 206 } |
| 207 LeaveCriticalSection(&waiters_cs_); |
| 208 } |
| 209 |
| 210 |
| 211 void MonitorData::SignalAndRemoveFirstWaiter() { |
| 212 EnterCriticalSection(&waiters_cs_); |
| 213 MonitorWaitData* first = waiters_head_; |
| 214 if (first != NULL) { |
| 215 // Remove from list. |
| 216 if (waiters_head_ == waiters_tail_) { |
| 217 waiters_tail_ = waiters_head_ = NULL; |
| 218 } else { |
| 219 waiters_head_ = waiters_head_->next_; |
| 220 } |
| 221 // Signal event. |
| 222 BOOL result = SetEvent(first->event_); |
| 223 if (result == 0) { |
| 224 FATAL("Monitor::Notify failed to signal event"); |
| 225 } |
| 226 } |
| 227 LeaveCriticalSection(&waiters_cs_); |
| 228 } |
| 229 |
| 230 |
| 231 void MonitorData::SignalAndRemoveAllWaiters() { |
| 232 EnterCriticalSection(&waiters_cs_); |
| 233 // Extract list to signal. |
| 234 MonitorWaitData* current = waiters_head_; |
| 235 // Clear list. |
| 236 waiters_head_ = waiters_tail_ = NULL; |
| 237 // Iterate and signal all events. |
| 238 while (current != NULL) { |
| 239 BOOL result = SetEvent(current->event_); |
| 240 if (result == 0) { |
| 241 FATAL("Failed to set event for NotifyAll"); |
| 242 } |
| 243 current = current->next_; |
| 244 } |
| 245 LeaveCriticalSection(&waiters_cs_); |
| 246 } |
| 247 |
| 248 |
| 249 MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() { |
| 250 // Ensure that the thread local key for monitor wait data objects is |
| 251 // initialized. |
| 252 EnterCriticalSection(&waiters_cs_); |
| 253 if (MonitorWaitData::monitor_wait_data_key_ == Thread::kUnsetThreadLocalKey) { |
| 254 MonitorWaitData::monitor_wait_data_key_ = Thread::CreateThreadLocal(); |
| 255 } |
| 256 LeaveCriticalSection(&waiters_cs_); |
| 257 |
| 258 // Get the MonitorWaitData object containing the event for this |
| 259 // thread from thread local storage. Create it if it does not exist. |
| 260 uword raw_wait_data = |
| 261 Thread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); |
| 262 MonitorWaitData* wait_data = NULL; |
| 263 if (raw_wait_data == 0) { |
| 264 HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); |
| 265 wait_data = new MonitorWaitData(event); |
| 266 Thread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_, |
| 267 reinterpret_cast<uword>(wait_data)); |
| 268 } else { |
| 269 wait_data = reinterpret_cast<MonitorWaitData*>(raw_wait_data); |
| 270 wait_data->next_ = NULL; |
| 271 } |
| 272 return wait_data; |
| 273 } |
| 274 |
| 275 |
| 174 Monitor::WaitResult Monitor::Wait(int64_t millis) { | 276 Monitor::WaitResult Monitor::Wait(int64_t millis) { |
| 175 Monitor::WaitResult retval = kNotified; | 277 Monitor::WaitResult retval = kNotified; |
| 176 | 278 |
| 177 // Record the fact that we will start waiting. This is used to only | 279 // Get the wait data object containing the event to wait for. |
| 178 // reset the notify all event when all waiting threads have dealt | 280 MonitorWaitData* wait_data = data_.GetMonitorWaitDataForThread(); |
| 179 // with the event. | 281 |
| 180 EnterCriticalSection(&data_.waiters_cs_); | 282 // Start waiting by adding the MonitorWaitData to the list of |
| 181 data_.waiters_++; | 283 // waiters. |
| 182 LeaveCriticalSection(&data_.waiters_cs_); | 284 data_.AddWaiter(wait_data); |
| 183 | 285 |
| 184 // Leave the monitor critical section while waiting. | 286 // Leave the monitor critical section while waiting. |
| 185 LeaveCriticalSection(&data_.cs_); | 287 LeaveCriticalSection(&data_.cs_); |
| 186 | 288 |
| 187 // Perform the actual wait using wait for multiple objects on both | 289 // Perform the actual wait on the event. |
| 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; | 290 DWORD result = WAIT_FAILED; |
| 197 if (millis == 0) { | 291 if (millis == 0) { |
| 198 // Wait forever for a Notify or a NotifyAll event. | 292 // Wait forever for a Notify or a NotifyAll event. |
| 199 result = WaitForMultipleObjects(2, events, FALSE, INFINITE); | 293 result = WaitForSingleObject(wait_data->event_, INFINITE); |
| 200 if (result == WAIT_FAILED) { | 294 if (result == WAIT_FAILED) { |
| 201 FATAL("Monitor::Wait failed"); | 295 FATAL("Monitor::Wait failed"); |
| 202 } | 296 } |
| 203 } else { | 297 } else { |
| 204 // Wait for the given period of time for a Notify or a NotifyAll | 298 // Wait for the given period of time for a Notify or a NotifyAll |
| 205 // event. | 299 // event. |
| 206 result = WaitForMultipleObjects(2, events, FALSE, millis); | 300 result = WaitForSingleObject(wait_data->event_, millis); |
| 207 if (result == WAIT_FAILED) { | 301 if (result == WAIT_FAILED) { |
| 208 FATAL("Monitor::Wait with timeout failed"); | 302 FATAL("Monitor::Wait with timeout failed"); |
| 209 } | 303 } |
| 210 if (result == WAIT_TIMEOUT) { | 304 if (result == WAIT_TIMEOUT) { |
| 305 // No longer waiting. Remove from the list of waiters. |
| 306 data_.RemoveWaiter(wait_data); |
| 211 retval = kTimedOut; | 307 retval = kTimedOut; |
| 212 } | 308 } |
| 213 } | 309 } |
| 214 | 310 |
| 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_); | |
| 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. | 311 // Reacquire the monitor critical section before continuing. |
| 226 EnterCriticalSection(&data_.cs_); | 312 EnterCriticalSection(&data_.cs_); |
| 227 | 313 |
| 228 return retval; | 314 return retval; |
| 229 } | 315 } |
| 230 | 316 |
| 231 | 317 |
| 232 void Monitor::Notify() { | 318 void Monitor::Notify() { |
| 233 // Signal one waiter through the notify auto-reset event if there | 319 data_.SignalAndRemoveFirstWaiter(); |
| 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_); | |
| 240 } | 320 } |
| 241 | 321 |
| 242 | 322 |
| 243 void Monitor::NotifyAll() { | 323 void Monitor::NotifyAll() { |
| 244 // Signal all waiters through the notify all manual-reset event if | 324 // If one of the objects in the list of waiters wakes because of a |
| 245 // there are any waiters. | 325 // timeout before we signal it, that object will get an extra |
| 246 EnterCriticalSection(&data_.waiters_cs_); | 326 // signal. This will be treated as a spurious wake-up and is OK |
| 247 if (data_.waiters_ > 0) { | 327 // since all uses of monitors should recheck the condition after a |
| 248 SetEvent(data_.notify_all_event_); | 328 // Wait. |
| 249 } | 329 data_.SignalAndRemoveAllWaiters(); |
| 250 LeaveCriticalSection(&data_.waiters_cs_); | |
| 251 } | 330 } |
| 252 | 331 |
| 253 } // namespace dart | 332 } // namespace dart |
| OLD | NEW |