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_); |
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 |
OLD | NEW |