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 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_); |
| 146 data_.waiters_head_ = NULL; | |
| 147 data_.waiters_tail_ = NULL; | |
| 152 data_.waiters_ = 0; | 148 data_.waiters_ = 0; |
| 153 } | 149 } |
| 154 | 150 |
| 155 | 151 |
| 156 Monitor::~Monitor() { | 152 Monitor::~Monitor() { |
| 157 DeleteCriticalSection(&data_.cs_); | 153 DeleteCriticalSection(&data_.cs_); |
| 158 CloseHandle(data_.notify_event_); | |
| 159 CloseHandle(data_.notify_all_event_); | |
| 160 DeleteCriticalSection(&data_.waiters_cs_); | 154 DeleteCriticalSection(&data_.waiters_cs_); |
| 161 } | 155 } |
| 162 | 156 |
| 163 | 157 |
| 164 void Monitor::Enter() { | 158 void Monitor::Enter() { |
| 165 EnterCriticalSection(&data_.cs_); | 159 EnterCriticalSection(&data_.cs_); |
| 166 } | 160 } |
| 167 | 161 |
| 168 | 162 |
| 169 void Monitor::Exit() { | 163 void Monitor::Exit() { |
| 170 LeaveCriticalSection(&data_.cs_); | 164 LeaveCriticalSection(&data_.cs_); |
| 171 } | 165 } |
| 172 | 166 |
| 173 | 167 |
| 168 void MonitorData::AddWaiter(MonitorWaitData* wait_data) { | |
| 169 // Add the MonitorWaitData object to the list of objects waiting for | |
| 170 // this monitor. | |
| 171 EnterCriticalSection(&waiters_cs_); | |
| 172 if (waiters_tail_ == NULL) { | |
|
Søren Gjesse
2012/02/21 16:00:48
ASSERT(waiters_head_ == NULL)
Mads Ager (google)
2012/02/22 12:32:51
Done.
| |
| 173 waiters_head_ = waiters_tail_ = wait_data; | |
| 174 } else { | |
| 175 waiters_tail_->next_ = wait_data; | |
| 176 waiters_tail_ = wait_data; | |
| 177 } | |
| 178 waiters_++; | |
| 179 LeaveCriticalSection(&waiters_cs_); | |
| 180 } | |
| 181 | |
| 182 | |
| 183 void MonitorData::RemoveWaiter(MonitorWaitData* wait_data) { | |
| 184 // Remove the MonitorWaitData object from the list of objects | |
| 185 // waiting for this monitor. | |
| 186 EnterCriticalSection(&waiters_cs_); | |
| 187 MonitorWaitData* previous = NULL; | |
| 188 MonitorWaitData* current = waiters_head_; | |
| 189 while (current != NULL) { | |
| 190 if (current == wait_data) { | |
| 191 if (waiters_head_ == waiters_tail_) { | |
| 192 waiters_head_ = waiters_tail_ = NULL; | |
| 193 } else if (current == waiters_head_) { | |
| 194 waiters_head_ = waiters_head_->next_; | |
| 195 } else if (current == waiters_tail_) { | |
| 196 ASSERT(previous != NULL); | |
| 197 waiters_tail_ = previous; | |
| 198 previous->next_ = NULL; | |
| 199 } else { | |
| 200 ASSERT(previous != NULL); | |
| 201 previous->next_ = current->next_; | |
| 202 } | |
| 203 waiters_--; | |
| 204 break; | |
| 205 } | |
| 206 previous = current; | |
| 207 current = current->next_; | |
| 208 } | |
| 209 LeaveCriticalSection(&waiters_cs_); | |
| 210 } | |
| 211 | |
| 212 | |
| 213 MonitorWaitData* MonitorData::RemoveFirstWaiter() { | |
| 214 EnterCriticalSection(&waiters_cs_); | |
| 215 MonitorWaitData* first = NULL; | |
| 216 if (waiters_ > 0) { | |
| 217 first = waiters_head_; | |
| 218 if (waiters_ == 1) { | |
| 219 waiters_tail_ = waiters_head_ = NULL; | |
| 220 } else { | |
| 221 waiters_head_ = waiters_head_->next_; | |
| 222 } | |
| 223 waiters_--; | |
| 224 } | |
| 225 LeaveCriticalSection(&waiters_cs_); | |
| 226 return first; | |
| 227 } | |
| 228 | |
| 229 | |
| 230 MonitorWaitData** MonitorData::RemoveAllWaiters() { | |
| 231 EnterCriticalSection(&waiters_cs_); | |
| 232 MonitorWaitData** result = | |
| 233 reinterpret_cast<MonitorWaitData**>(calloc(waiters_ + 1, kWordSize)); | |
| 234 MonitorWaitData* current = waiters_head_; | |
| 235 intptr_t i = 0; | |
| 236 while (current != NULL) { | |
| 237 result[i++] = current; | |
| 238 current = current->next_; | |
| 239 } | |
| 240 ASSERT(i == waiters_); | |
| 241 result[i] = NULL; | |
| 242 waiters_head_ = waiters_tail_ = NULL; | |
| 243 waiters_ = 0; | |
| 244 LeaveCriticalSection(&waiters_cs_); | |
| 245 return result; | |
| 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 // Extract the first element in the list of waiters. |
| 234 // are any waiters. | 320 MonitorWaitData* head = data_.RemoveFirstWaiter(); |
| 235 EnterCriticalSection(&data_.waiters_cs_); | 321 |
| 236 if (data_.waiters_ > 0) { | 322 // Signal the first element if there was one. |
| 237 SetEvent(data_.notify_event_); | 323 if (head != NULL) { |
| 324 BOOL result = SetEvent(head->event_); | |
| 325 if (result == 0) { | |
| 326 FATAL("Monitor::Notify failed to signal event"); | |
| 327 } | |
| 238 } | 328 } |
| 239 LeaveCriticalSection(&data_.waiters_cs_); | |
| 240 } | 329 } |
| 241 | 330 |
| 242 | 331 |
| 243 void Monitor::NotifyAll() { | 332 void Monitor::NotifyAll() { |
| 244 // Signal all waiters through the notify all manual-reset event if | 333 // Extract the entire list of waiters into a separate array. Do not |
| 245 // there are any waiters. | 334 // use the linked-list structure embedded in the MonitorWaitData |
| 246 EnterCriticalSection(&data_.waiters_cs_); | 335 // objects. If a timeout occurs on an object in the array while we |
| 247 if (data_.waiters_ > 0) { | 336 // are processing them the MonitorWaitData object can be reused and |
| 248 SetEvent(data_.notify_all_event_); | 337 // the link structure can change. That should not influence which |
| 338 // events are signaled here so we use a separate array. | |
| 339 // | |
|
cshapiro
2012/02/21 18:49:36
When a thread waits on a monitor and the wait time
Mads Ager (google)
2012/02/22 12:32:51
I don't understand. The notification loop over the
| |
| 340 // If one of the objects in the array wakes because of a timeout | |
| 341 // before we signal it, that object will get an extra signal. This | |
| 342 // will be treated as a spurious wake-up and is OK since all uses of | |
| 343 // monitors should recheck the condition after a Wait. | |
| 344 MonitorWaitData** waiters = data_.RemoveAllWaiters(); | |
| 345 | |
| 346 // Signal all the waiters. | |
| 347 for (intptr_t i = 0; waiters[i] != NULL; i++) { | |
|
cshapiro
2012/02/21 18:49:36
As noted in the header, this should be written as
Mads Ager (google)
2012/02/22 12:32:51
This could be expensive, I agree. However, it is m
| |
| 348 BOOL result = SetEvent(waiters[i]->event_); | |
| 349 if (result == 0) { | |
| 350 FATAL("Monitor::NotifyAll failed to signal event"); | |
| 351 } | |
| 249 } | 352 } |
| 250 LeaveCriticalSection(&data_.waiters_cs_); | 353 |
| 354 free(waiters); | |
| 251 } | 355 } |
| 252 | 356 |
| 253 } // namespace dart | 357 } // namespace dart |
| OLD | NEW |