Chromium Code Reviews| Index: runtime/platform/thread_win.cc |
| diff --git a/runtime/platform/thread_win.cc b/runtime/platform/thread_win.cc |
| index 18a85a91f81cdcd530fc4ed8cda44c1054c7bf5e..47acd91c74b974274dbffe1567744db49e6c0aa1 100644 |
| --- a/runtime/platform/thread_win.cc |
| +++ b/runtime/platform/thread_win.cc |
| @@ -138,12 +138,26 @@ void Mutex::Unlock() { |
| Monitor::Monitor() { |
| InitializeCriticalSection(&data_.cs_); |
| - InitializeConditionVariable(&data_.cond_); |
| + // Create auto-reset event used to implement Notify. Auto-reset |
| + // events only wake one thread waiting for them on SetEvent. |
| + data_.notify_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); |
| + // Create manual-reset event used to implement |
| + // NotifyAll. Manual-reset events wake all threads waiting for them |
| + // on SetEvent. |
| + data_.notify_all_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); |
| + if ((data_.notify_event_ == NULL) || (data_.notify_all_event_ == NULL)) { |
| + FATAL("Failed allocating event object for monitor"); |
| + } |
| + InitializeCriticalSection(&data_.waiters_cs_); |
| + data_.waiters_ = 0; |
| } |
| Monitor::~Monitor() { |
| DeleteCriticalSection(&data_.cs_); |
| + CloseHandle(data_.notify_event_); |
| + CloseHandle(data_.notify_all_event_); |
| + DeleteCriticalSection(&data_.waiters_cs_); |
| } |
| @@ -159,38 +173,81 @@ void Monitor::Exit() { |
| Monitor::WaitResult Monitor::Wait(int64_t millis) { |
| Monitor::WaitResult retval = kNotified; |
| + |
| + // Record the fact that we will start waiting. This is used to only |
| + // reset the notify all event when all waiting threads have dealt |
| + // with the event. |
| + EnterCriticalSection(&data_.waiters_cs_); |
| + data_.waiters_++; |
| + LeaveCriticalSection(&data_.waiters_cs_); |
| + |
| + // Leave the monitor critical section while waiting. |
| + LeaveCriticalSection(&data_.cs_); |
| + |
| + // Perform the actual wait using wait for multiple objects on both |
| + // the notify and the notify all events. |
| + static const intptr_t kNotifyEventIndex = 0; |
| + static const intptr_t kNotifyAllEventIndex = 1; |
| + static const intptr_t kNumberOfEvents = 2; |
| + HANDLE events[kNumberOfEvents]; |
| + events[kNotifyEventIndex] = data_.notify_event_; |
| + events[kNotifyAllEventIndex] = data_.notify_all_event_; |
| + |
| + DWORD result = WAIT_FAILED; |
| if (millis == 0) { |
| - // Wait forever. |
| - BOOL result = SleepConditionVariableCS(&data_.cond_, &data_.cs_, INFINITE); |
| - if (result == 0) { |
| + // Wait forever for a Notify or a NotifyAll event. |
| + result = WaitForMultipleObjects(2, events, FALSE, INFINITE); |
| + if (result == WAIT_FAILED) { |
| FATAL("Monitor::Wait failed"); |
| } |
| } else { |
| - BOOL result = SleepConditionVariableCS(&data_.cond_, &data_.cs_, millis); |
| - if (result == 0) { |
| - DWORD error = GetLastError(); |
| - // Windows condition variables should set error to WAIT_TIMEOUT |
| - // but occationally sets it to ERROR_TIMEOUT for timeouts. On |
| - // Windows 7 it seems to pretty consistently set it to |
| - // ERROR_TIMEOUT. |
| - if ((error == WAIT_TIMEOUT) || (error == ERROR_TIMEOUT)) { |
| - retval = kTimedOut; |
| - } else { |
| - FATAL("Monitor::Wait failed"); |
| - } |
| + // Wait for the given period of time for a Notify or a NotifyAll |
| + // event. |
| + result = WaitForMultipleObjects(2, events, FALSE, millis); |
| + if (result == WAIT_FAILED) { |
| + FATAL("Monitor::Wait with timeout failed"); |
| + } |
| + if (result == WAIT_TIMEOUT) { |
| + retval = kTimedOut; |
| } |
| } |
| + |
| + // Check if we are the last waiter on a notify all. If we are, reset |
| + // the notify all event. |
| + EnterCriticalSection(&data_.waiters_cs_); |
|
Søren Gjesse
2012/02/08 15:32:58
I am wondering whether we can get into a situation
|
| + data_.waiters_--; |
| + if ((data_.waiters_ == 0) && |
| + (result == (WAIT_OBJECT_0 + kNotifyAllEventIndex))) { |
| + ResetEvent(data_.notify_all_event_); |
| + } |
| + LeaveCriticalSection(&data_.waiters_cs_); |
| + |
| + // Reacquire the monitor critical section before continuing. |
| + EnterCriticalSection(&data_.cs_); |
| + |
| return retval; |
| } |
| void Monitor::Notify() { |
| - WakeConditionVariable(&data_.cond_); |
| + // Signal one waiter through the notify auto-reset event if there |
| + // are any waiters. |
| + EnterCriticalSection(&data_.waiters_cs_); |
| + if (data_.waiters_ > 0) { |
| + SetEvent(data_.notify_event_); |
| + } |
| + LeaveCriticalSection(&data_.waiters_cs_); |
| } |
| void Monitor::NotifyAll() { |
| - WakeAllConditionVariable(&data_.cond_); |
| + // Signal all waiters through the notify all manual-reset event if |
| + // there are any waiters. |
| + EnterCriticalSection(&data_.waiters_cs_); |
| + if (data_.waiters_ > 0) { |
| + SetEvent(data_.notify_all_event_); |
| + } |
| + LeaveCriticalSection(&data_.waiters_cs_); |
| } |
| } // namespace dart |