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

Side by Side Diff: runtime/platform/thread_win.cc

Issue 9424050: Reimplement Windows Monitors. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Avoid copying by holding internal lock during SetEvent 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') | runtime/tests/vm/vm.status » ('j') | 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 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
OLDNEW
« no previous file with comments | « runtime/platform/thread_win.h ('k') | runtime/tests/vm/vm.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698