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

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: Fix timeout handling. 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
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_);
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698