OLD | NEW |
---|---|
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 Loading... | |
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 |
OLD | NEW |