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/globals.h" | 5 #include "platform/globals.h" |
6 #if defined(TARGET_OS_WINDOWS) | 6 #if defined(TARGET_OS_WINDOWS) |
7 | 7 |
8 #include "platform/thread.h" | 8 #include "platform/thread.h" |
9 | 9 |
10 #include <process.h> // NOLINT | 10 #include <process.h> // NOLINT |
(...skipping 21 matching lines...) Expand all Loading... |
32 // Dispatch to the thread start function provided by the caller. This trampoline | 32 // Dispatch to the thread start function provided by the caller. This trampoline |
33 // is used to ensure that the thread is properly destroyed if the thread just | 33 // is used to ensure that the thread is properly destroyed if the thread just |
34 // exits. | 34 // exits. |
35 static unsigned int __stdcall ThreadEntry(void* data_ptr) { | 35 static unsigned int __stdcall ThreadEntry(void* data_ptr) { |
36 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr); | 36 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr); |
37 | 37 |
38 Thread::ThreadStartFunction function = data->function(); | 38 Thread::ThreadStartFunction function = data->function(); |
39 uword parameter = data->parameter(); | 39 uword parameter = data->parameter(); |
40 delete data; | 40 delete data; |
41 | 41 |
| 42 ASSERT(ThreadInlineImpl::thread_id_key != Thread::kUnsetThreadLocalKey); |
| 43 |
| 44 ThreadId thread_id = ThreadInlineImpl::CreateThreadId(); |
| 45 // Set thread ID in TLS. |
| 46 Thread::SetThreadLocal(ThreadInlineImpl::thread_id_key, |
| 47 reinterpret_cast<DWORD>(thread_id)); |
| 48 MonitorData::GetMonitorWaitDataForThread(); |
| 49 |
42 // Call the supplied thread start function handing it its parameters. | 50 // Call the supplied thread start function handing it its parameters. |
43 function(parameter); | 51 function(parameter); |
44 | 52 |
45 // Clean up the monitor wait data for this thread. | 53 // Clean up the monitor wait data for this thread. |
46 MonitorWaitData::ThreadExit(); | 54 MonitorWaitData::ThreadExit(); |
47 | 55 |
| 56 // Clear thread ID in TLS. |
| 57 Thread::SetThreadLocal(ThreadInlineImpl::thread_id_key, NULL); |
| 58 ThreadInlineImpl::DestroyThreadId(thread_id); |
| 59 |
48 return 0; | 60 return 0; |
49 } | 61 } |
50 | 62 |
51 | 63 |
52 int Thread::Start(ThreadStartFunction function, uword parameter) { | 64 int Thread::Start(ThreadStartFunction function, uword parameter) { |
53 ThreadStartData* start_data = new ThreadStartData(function, parameter); | 65 ThreadStartData* start_data = new ThreadStartData(function, parameter); |
54 uint32_t tid; | 66 uint32_t tid; |
55 uintptr_t thread = _beginthreadex(NULL, Thread::GetMaxStackSize(), | 67 uintptr_t thread = _beginthreadex(NULL, Thread::GetMaxStackSize(), |
56 ThreadEntry, start_data, 0, &tid); | 68 ThreadEntry, start_data, 0, &tid); |
57 if (thread == -1L || thread == 0) { | 69 if (thread == -1L || thread == 0) { |
58 #ifdef DEBUG | 70 #ifdef DEBUG |
59 fprintf(stderr, "_beginthreadex error: %d (%s)\n", errno, strerror(errno)); | 71 fprintf(stderr, "_beginthreadex error: %d (%s)\n", errno, strerror(errno)); |
60 #endif | 72 #endif |
61 return errno; | 73 return errno; |
62 } | 74 } |
63 | 75 |
64 return 0; | 76 return 0; |
65 } | 77 } |
66 | 78 |
67 | 79 |
| 80 ThreadId ThreadInlineImpl::CreateThreadId() { |
| 81 // Create an ID for this thread that can be shared with other threads. |
| 82 HANDLE thread_id = OpenThread(THREAD_GET_CONTEXT | |
| 83 THREAD_SUSPEND_RESUME | |
| 84 THREAD_QUERY_INFORMATION, |
| 85 false, |
| 86 GetCurrentThreadId()); |
| 87 ASSERT(thread_id != NULL); |
| 88 return thread_id; |
| 89 } |
| 90 |
| 91 |
| 92 void ThreadInlineImpl::DestroyThreadId(ThreadId thread_id) { |
| 93 ASSERT(thread_id != NULL); |
| 94 // Destroy thread ID. |
| 95 CloseHandle(thread_id); |
| 96 } |
| 97 |
| 98 |
| 99 ThreadLocalKey ThreadInlineImpl::thread_id_key = Thread::kUnsetThreadLocalKey; |
| 100 |
68 ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES; | 101 ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES; |
69 | 102 |
70 | 103 |
71 ThreadLocalKey Thread::CreateThreadLocal() { | 104 ThreadLocalKey Thread::CreateThreadLocal() { |
72 ThreadLocalKey key = TlsAlloc(); | 105 ThreadLocalKey key = TlsAlloc(); |
73 if (key == kUnsetThreadLocalKey) { | 106 if (key == kUnsetThreadLocalKey) { |
74 FATAL1("TlsAlloc failed %d", GetLastError()); | 107 FATAL1("TlsAlloc failed %d", GetLastError()); |
75 } | 108 } |
76 return key; | 109 return key; |
77 } | 110 } |
78 | 111 |
79 | 112 |
80 void Thread::DeleteThreadLocal(ThreadLocalKey key) { | 113 void Thread::DeleteThreadLocal(ThreadLocalKey key) { |
81 ASSERT(key != kUnsetThreadLocalKey); | 114 ASSERT(key != kUnsetThreadLocalKey); |
82 BOOL result = TlsFree(key); | 115 BOOL result = TlsFree(key); |
83 if (!result) { | 116 if (!result) { |
84 FATAL1("TlsFree failed %d", GetLastError()); | 117 FATAL1("TlsFree failed %d", GetLastError()); |
85 } | 118 } |
86 } | 119 } |
87 | 120 |
88 | 121 |
89 intptr_t Thread::GetMaxStackSize() { | 122 intptr_t Thread::GetMaxStackSize() { |
90 const int kStackSize = (128 * kWordSize * KB); | 123 const int kStackSize = (128 * kWordSize * KB); |
91 return kStackSize; | 124 return kStackSize; |
92 } | 125 } |
93 | 126 |
94 | 127 |
| 128 ThreadId Thread::GetCurrentThreadId() { |
| 129 ThreadId id = reinterpret_cast<ThreadId>( |
| 130 Thread::GetThreadLocal(ThreadInlineImpl::thread_id_key)); |
| 131 ASSERT(id != NULL); |
| 132 return id; |
| 133 } |
| 134 |
| 135 |
| 136 void Thread::GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage) { |
| 137 static const int64_t kTimeEpoc = 116444736000000000LL; |
| 138 static const int64_t kTimeScaler = 10; // 100 ns to us. |
| 139 // Although win32 uses 64-bit integers for representing timestamps, |
| 140 // these are packed into a FILETIME structure. The FILETIME |
| 141 // structure is just a struct representing a 64-bit integer. The |
| 142 // TimeStamp union allows access to both a FILETIME and an integer |
| 143 // representation of the timestamp. The Windows timestamp is in |
| 144 // 100-nanosecond intervals since January 1, 1601. |
| 145 union TimeStamp { |
| 146 FILETIME ft_; |
| 147 int64_t t_; |
| 148 }; |
| 149 ASSERT(cpu_usage != NULL); |
| 150 TimeStamp created; |
| 151 TimeStamp exited; |
| 152 TimeStamp kernel; |
| 153 TimeStamp user; |
| 154 BOOL result = GetThreadTimes(thread_id, |
| 155 &created.ft_, |
| 156 &exited.ft_, |
| 157 &kernel.ft_, |
| 158 &user.ft_); |
| 159 if (!result) { |
| 160 FATAL1("GetThreadCpuUsage failed %d\n", GetLastError()); |
| 161 } |
| 162 *cpu_usage = (user.t_ - kTimeEpoc) / kTimeScaler; |
| 163 } |
| 164 |
| 165 |
95 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) { | 166 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) { |
96 ASSERT(key != kUnsetThreadLocalKey); | 167 ASSERT(key != kUnsetThreadLocalKey); |
97 BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value)); | 168 BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value)); |
98 if (!result) { | 169 if (!result) { |
99 FATAL1("TlsSetValue failed %d", GetLastError()); | 170 FATAL1("TlsSetValue failed %d", GetLastError()); |
100 } | 171 } |
101 } | 172 } |
102 | 173 |
103 | 174 |
104 Mutex::Mutex() { | 175 Mutex::Mutex() { |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 void MonitorData::SignalAndRemoveFirstWaiter() { | 305 void MonitorData::SignalAndRemoveFirstWaiter() { |
235 EnterCriticalSection(&waiters_cs_); | 306 EnterCriticalSection(&waiters_cs_); |
236 MonitorWaitData* first = waiters_head_; | 307 MonitorWaitData* first = waiters_head_; |
237 if (first != NULL) { | 308 if (first != NULL) { |
238 // Remove from list. | 309 // Remove from list. |
239 if (waiters_head_ == waiters_tail_) { | 310 if (waiters_head_ == waiters_tail_) { |
240 waiters_tail_ = waiters_head_ = NULL; | 311 waiters_tail_ = waiters_head_ = NULL; |
241 } else { | 312 } else { |
242 waiters_head_ = waiters_head_->next_; | 313 waiters_head_ = waiters_head_->next_; |
243 } | 314 } |
| 315 // Clear next. |
| 316 first->next_ = NULL; |
244 // Signal event. | 317 // Signal event. |
245 BOOL result = SetEvent(first->event_); | 318 BOOL result = SetEvent(first->event_); |
246 if (result == 0) { | 319 if (result == 0) { |
247 FATAL1("Monitor::Notify failed to signal event %d", GetLastError()); | 320 FATAL1("Monitor::Notify failed to signal event %d", GetLastError()); |
248 } | 321 } |
249 } | 322 } |
250 LeaveCriticalSection(&waiters_cs_); | 323 LeaveCriticalSection(&waiters_cs_); |
251 } | 324 } |
252 | 325 |
253 | 326 |
254 void MonitorData::SignalAndRemoveAllWaiters() { | 327 void MonitorData::SignalAndRemoveAllWaiters() { |
255 EnterCriticalSection(&waiters_cs_); | 328 EnterCriticalSection(&waiters_cs_); |
256 // Extract list to signal. | 329 // Extract list to signal. |
257 MonitorWaitData* current = waiters_head_; | 330 MonitorWaitData* current = waiters_head_; |
258 // Clear list. | 331 // Clear list. |
259 waiters_head_ = waiters_tail_ = NULL; | 332 waiters_head_ = waiters_tail_ = NULL; |
260 // Iterate and signal all events. | 333 // Iterate and signal all events. |
261 while (current != NULL) { | 334 while (current != NULL) { |
| 335 // Copy next. |
| 336 MonitorWaitData* next = current->next_; |
| 337 // Clear next. |
| 338 current->next_ = NULL; |
| 339 // Signal event. |
262 BOOL result = SetEvent(current->event_); | 340 BOOL result = SetEvent(current->event_); |
263 if (result == 0) { | 341 if (result == 0) { |
264 FATAL1("Failed to set event for NotifyAll %d", GetLastError()); | 342 FATAL1("Failed to set event for NotifyAll %d", GetLastError()); |
265 } | 343 } |
266 current = current->next_; | 344 current = next; |
267 } | 345 } |
268 LeaveCriticalSection(&waiters_cs_); | 346 LeaveCriticalSection(&waiters_cs_); |
269 } | 347 } |
270 | 348 |
271 | 349 |
272 MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() { | 350 MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() { |
273 // Ensure that the thread local key for monitor wait data objects is | 351 // Ensure that the thread local key for monitor wait data objects is |
274 // initialized. | 352 // initialized. |
275 EnterCriticalSection(&waiters_cs_); | 353 ASSERT(MonitorWaitData::monitor_wait_data_key_ != |
276 if (MonitorWaitData::monitor_wait_data_key_ == Thread::kUnsetThreadLocalKey) { | 354 Thread::kUnsetThreadLocalKey); |
277 MonitorWaitData::monitor_wait_data_key_ = Thread::CreateThreadLocal(); | |
278 } | |
279 LeaveCriticalSection(&waiters_cs_); | |
280 | 355 |
281 // Get the MonitorWaitData object containing the event for this | 356 // Get the MonitorWaitData object containing the event for this |
282 // thread from thread local storage. Create it if it does not exist. | 357 // thread from thread local storage. Create it if it does not exist. |
283 uword raw_wait_data = | 358 uword raw_wait_data = |
284 Thread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); | 359 Thread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); |
285 MonitorWaitData* wait_data = NULL; | 360 MonitorWaitData* wait_data = NULL; |
286 if (raw_wait_data == 0) { | 361 if (raw_wait_data == 0) { |
287 HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); | 362 HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); |
288 wait_data = new MonitorWaitData(event); | 363 wait_data = new MonitorWaitData(event); |
289 Thread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_, | 364 Thread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_, |
290 reinterpret_cast<uword>(wait_data)); | 365 reinterpret_cast<uword>(wait_data)); |
291 } else { | 366 } else { |
292 wait_data = reinterpret_cast<MonitorWaitData*>(raw_wait_data); | 367 wait_data = reinterpret_cast<MonitorWaitData*>(raw_wait_data); |
293 wait_data->next_ = NULL; | 368 wait_data->next_ = NULL; |
294 } | 369 } |
295 return wait_data; | 370 return wait_data; |
296 } | 371 } |
297 | 372 |
298 | 373 |
299 Monitor::WaitResult Monitor::Wait(int64_t millis) { | 374 Monitor::WaitResult Monitor::Wait(int64_t millis) { |
300 Monitor::WaitResult retval = kNotified; | 375 Monitor::WaitResult retval = kNotified; |
301 | 376 |
302 // Get the wait data object containing the event to wait for. | 377 // Get the wait data object containing the event to wait for. |
303 MonitorWaitData* wait_data = data_.GetMonitorWaitDataForThread(); | 378 MonitorWaitData* wait_data = MonitorData::GetMonitorWaitDataForThread(); |
304 | 379 |
305 // Start waiting by adding the MonitorWaitData to the list of | 380 // Start waiting by adding the MonitorWaitData to the list of |
306 // waiters. | 381 // waiters. |
307 data_.AddWaiter(wait_data); | 382 data_.AddWaiter(wait_data); |
308 | 383 |
309 // Leave the monitor critical section while waiting. | 384 // Leave the monitor critical section while waiting. |
310 LeaveCriticalSection(&data_.cs_); | 385 LeaveCriticalSection(&data_.cs_); |
311 | 386 |
312 // Perform the actual wait on the event. | 387 // Perform the actual wait on the event. |
313 DWORD result = WAIT_FAILED; | 388 DWORD result = WAIT_FAILED; |
(...skipping 17 matching lines...) Expand all Loading... |
331 } | 406 } |
332 } | 407 } |
333 | 408 |
334 // Reacquire the monitor critical section before continuing. | 409 // Reacquire the monitor critical section before continuing. |
335 EnterCriticalSection(&data_.cs_); | 410 EnterCriticalSection(&data_.cs_); |
336 | 411 |
337 return retval; | 412 return retval; |
338 } | 413 } |
339 | 414 |
340 | 415 |
| 416 Monitor::WaitResult Monitor::WaitMicros(int64_t micros) { |
| 417 // TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows. |
| 418 int64_t millis = micros / kMicrosecondsPerMillisecond; |
| 419 if ((millis * kMicrosecondsPerMillisecond) < micros) { |
| 420 // We've been asked to sleep for a fraction of a millisecond, |
| 421 // this isn't supported on Windows. Bumps milliseconds up by one |
| 422 // so that we never return too early. We likely return late though. |
| 423 millis += 1; |
| 424 } |
| 425 return Wait(millis); |
| 426 } |
| 427 |
| 428 |
341 void Monitor::Notify() { | 429 void Monitor::Notify() { |
342 data_.SignalAndRemoveFirstWaiter(); | 430 data_.SignalAndRemoveFirstWaiter(); |
343 } | 431 } |
344 | 432 |
345 | 433 |
346 void Monitor::NotifyAll() { | 434 void Monitor::NotifyAll() { |
347 // If one of the objects in the list of waiters wakes because of a | 435 // If one of the objects in the list of waiters wakes because of a |
348 // timeout before we signal it, that object will get an extra | 436 // timeout before we signal it, that object will get an extra |
349 // signal. This will be treated as a spurious wake-up and is OK | 437 // signal. This will be treated as a spurious wake-up and is OK |
350 // since all uses of monitors should recheck the condition after a | 438 // since all uses of monitors should recheck the condition after a |
351 // Wait. | 439 // Wait. |
352 data_.SignalAndRemoveAllWaiters(); | 440 data_.SignalAndRemoveAllWaiters(); |
353 } | 441 } |
354 | 442 |
355 } // namespace dart | 443 } // namespace dart |
356 | 444 |
357 #endif // defined(TARGET_OS_WINDOWS) | 445 #endif // defined(TARGET_OS_WINDOWS) |
OLD | NEW |