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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/platform/thread_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
OLDNEW
« 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