Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(212)

Unified Diff: runtime/platform/thread_win.cc

Issue 9361036: Implement condition variables on Windows on top of Event/SetEvent/ResetEvent. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/platform/thread_win.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « runtime/platform/thread_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698