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 |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "platform/globals.h" // NOLINT |
6 | #if defined(HOST_OS_WINDOWS) |
7 | |
8 | #include "vm/growable_array.h" |
9 | #include "vm/lockers.h" |
10 | #include "vm/os_thread.h" |
11 | |
12 | #include <process.h> // NOLINT |
13 | |
14 | #include "platform/address_sanitizer.h" |
15 | #include "platform/assert.h" |
16 | #include "platform/safe_stack.h" |
17 | |
18 | #include "vm/flags.h" |
19 | |
20 | namespace dart { |
21 | |
22 | DEFINE_FLAG(int, |
23 | worker_thread_priority, |
24 | kMinInt, |
25 | "The thread priority the VM should use for new worker threads." ); |
26 | |
27 | // This flag is flipped by platform_win.cc when the process is exiting. |
28 | // TODO(zra): Remove once VM shuts down cleanly. |
29 | bool private_flag_windows_run_tls_destructors = true; |
30 | |
31 | class ThreadStartData { |
32 | public: |
33 | ThreadStartData(const char* name, |
34 | OSThread::ThreadStartFunction function, |
35 | uword parameter) |
36 | : name_(name), function_(function), parameter_(parameter) {} |
37 | |
38 | const char* name() const { return name_; } |
39 | OSThread::ThreadStartFunction function() const { return function_; } |
40 | uword parameter() const { return parameter_; } |
41 | |
42 | private: |
43 | const char* name_; |
44 | OSThread::ThreadStartFunction function_; |
45 | uword parameter_; |
46 | |
47 | DISALLOW_COPY_AND_ASSIGN(ThreadStartData); |
48 | }; |
49 | |
50 | // Dispatch to the thread start function provided by the caller. This trampoline |
51 | // is used to ensure that the thread is properly destroyed if the thread just |
52 | // exits. |
53 | static unsigned int __stdcall ThreadEntry(void* data_ptr) { |
54 | if (FLAG_worker_thread_priority != kMinInt) { |
55 | if (SetThreadPriority(GetCurrentThread(), FLAG_worker_thread_priority) == |
56 | 0) { |
57 | FATAL2("Setting thread priority to %d failed: GetLastError() = %d\n" , |
58 | FLAG_worker_thread_priority, GetLastError()); |
59 | } |
60 | } |
61 | |
62 | ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr); |
63 | |
64 | const char* name = data->name(); |
65 | OSThread::ThreadStartFunction function = data->function(); |
66 | uword parameter = data->parameter(); |
67 | delete data; |
68 | |
69 | // Create new OSThread object and set as TLS for new thread. |
70 | OSThread* thread = OSThread::CreateOSThread(); |
71 | if (thread != NULL) { |
72 | OSThread::SetCurrent(thread); |
73 | thread->set_name(name); |
74 | |
75 | // Call the supplied thread start function handing it its parameters. |
76 | function(parameter); |
77 | } |
78 | |
79 | return 0; |
80 | } |
81 | |
82 | int OSThread::Start(const char* name, |
83 | ThreadStartFunction function, |
84 | uword parameter) { |
85 | ThreadStartData* start_data = new ThreadStartData(name, function, parameter); |
86 | uint32_t tid; |
87 | uintptr_t thread = _beginthreadex(NULL, OSThread::GetMaxStackSize(), |
88 | ThreadEntry, start_data, 0, &tid); |
89 | if (thread == -1L || thread == 0) { |
90 | #ifdef DEBUG |
91 | fprintf(stderr, "_beginthreadex error: %d (%s)\n" , errno, strerror(errno)); |
92 | #endif |
93 | return errno; |
94 | } |
95 | |
96 | // Close the handle, so we don't leak the thread object. |
97 | CloseHandle(reinterpret_cast<HANDLE>(thread)); |
98 | |
99 | return 0; |
100 | } |
101 | |
102 | const ThreadId OSThread::kInvalidThreadId = 0; |
103 | const ThreadJoinId OSThread::kInvalidThreadJoinId = NULL; |
104 | |
105 | ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) { |
106 | ThreadLocalKey key = TlsAlloc(); |
107 | if (key == kUnsetThreadLocalKey) { |
108 | FATAL1("TlsAlloc failed %d" , GetLastError()); |
109 | } |
110 | ThreadLocalData::AddThreadLocal(key, destructor); |
111 | return key; |
112 | } |
113 | |
114 | void OSThread::DeleteThreadLocal(ThreadLocalKey key) { |
115 | ASSERT(key != kUnsetThreadLocalKey); |
116 | BOOL result = TlsFree(key); |
117 | if (!result) { |
118 | FATAL1("TlsFree failed %d" , GetLastError()); |
119 | } |
120 | ThreadLocalData::RemoveThreadLocal(key); |
121 | } |
122 | |
123 | intptr_t OSThread::GetMaxStackSize() { |
124 | const int kStackSize = (128 * kWordSize * KB); |
125 | return kStackSize; |
126 | } |
127 | |
128 | ThreadId OSThread::GetCurrentThreadId() { |
129 | return ::GetCurrentThreadId(); |
130 | } |
131 | |
132 | #ifdef SUPPORT_TIMELINE |
133 | ThreadId OSThread::GetCurrentThreadTraceId() { |
134 | return ::GetCurrentThreadId(); |
135 | } |
136 | #endif // PRODUCT |
137 | |
138 | ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) { |
139 | ASSERT(thread != NULL); |
140 | // Make sure we're filling in the join id for the current thread. |
141 | ThreadId id = GetCurrentThreadId(); |
142 | ASSERT(thread->id() == id); |
143 | // Make sure the join_id_ hasn't been set, yet. |
144 | DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId); |
145 | HANDLE handle = OpenThread(SYNCHRONIZE, false, id); |
146 | ASSERT(handle != NULL); |
147 | #if defined(DEBUG) |
148 | thread->join_id_ = handle; |
149 | #endif |
150 | return handle; |
151 | } |
152 | |
153 | void OSThread::Join(ThreadJoinId id) { |
154 | HANDLE handle = static_cast<HANDLE>(id); |
155 | ASSERT(handle != NULL); |
156 | DWORD res = WaitForSingleObject(handle, INFINITE); |
157 | CloseHandle(handle); |
158 | ASSERT(res == WAIT_OBJECT_0); |
159 | } |
160 | |
161 | intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) { |
162 | ASSERT(sizeof(id) <= sizeof(intptr_t)); |
163 | return static_cast<intptr_t>(id); |
164 | } |
165 | |
166 | ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) { |
167 | return static_cast<ThreadId>(id); |
168 | } |
169 | |
170 | bool OSThread::Compare(ThreadId a, ThreadId b) { |
171 | return a == b; |
172 | } |
173 | |
174 | bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) { |
175 | // On Windows stack limits for the current thread are available in |
176 | // the thread information block (TIB). Its fields can be accessed through |
177 | // FS segment register on x86 and GS segment register on x86_64. |
178 | #ifdef _WIN64 |
179 | *upper = static_cast<uword>(__readgsqword(offsetof(NT_TIB64, StackBase))); |
180 | #else |
181 | *upper = static_cast<uword>(__readfsdword(offsetof(NT_TIB, StackBase))); |
182 | #endif |
183 | // Notice that we cannot use the TIB's StackLimit for the stack end, as it |
184 | // tracks the end of the committed range. We're after the end of the reserved |
185 | // stack area (most of which will be uncommitted, most times). |
186 | MEMORY_BASIC_INFORMATION stack_info; |
187 | memset(&stack_info, 0, sizeof(MEMORY_BASIC_INFORMATION)); |
188 | size_t result_size = |
189 | VirtualQuery(&stack_info, &stack_info, sizeof(MEMORY_BASIC_INFORMATION)); |
190 | ASSERT(result_size >= sizeof(MEMORY_BASIC_INFORMATION)); |
191 | *lower = reinterpret_cast<uword>(stack_info.AllocationBase); |
192 | ASSERT(*upper > *lower); |
193 | // When the third last page of the reserved stack is accessed as a |
194 | // guard page, the second last page will be committed (along with removing |
195 | // the guard bit on the third last) _and_ a stack overflow exception |
196 | // is raised. |
197 | // |
198 | // http://blogs.msdn.com/b/satyem/archive/2012/08/13/thread-s-stack-memory-management.aspx |
199 | // explains the details. |
200 | ASSERT((*upper - *lower) >= (4u * 0x1000)); |
201 | *lower += 4 * 0x1000; |
202 | return true; |
203 | } |
204 | |
205 | #if defined(USING_SAFE_STACK) |
206 | NO_SANITIZE_ADDRESS |
207 | NO_SANITIZE_SAFE_STACK |
208 | uword OSThread::GetCurrentSafestackPointer() { |
209 | #error "SAFE_STACK is unsupported on this platform" |
210 | return 0; |
211 | } |
212 | |
213 | NO_SANITIZE_ADDRESS |
214 | NO_SANITIZE_SAFE_STACK |
215 | void OSThread::SetCurrentSafestackPointer(uword ssp) { |
216 | #error "SAFE_STACK is unsupported on this platform" |
217 | } |
218 | #endif |
219 | |
220 | void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) { |
221 | ASSERT(key != kUnsetThreadLocalKey); |
222 | BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value)); |
223 | if (!result) { |
224 | FATAL1("TlsSetValue failed %d" , GetLastError()); |
225 | } |
226 | } |
227 | |
228 | Mutex::Mutex(NOT_IN_PRODUCT(const char* name)) |
229 | #if !defined(PRODUCT) |
230 | : name_(name) |
231 | #endif |
232 | { |
233 | InitializeSRWLock(&data_.lock_); |
234 | #if defined(DEBUG) |
235 | // When running with assertions enabled we do track the owner. |
236 | owner_ = OSThread::kInvalidThreadId; |
237 | #endif // defined(DEBUG) |
238 | } |
239 | |
240 | Mutex::~Mutex() { |
241 | #if defined(DEBUG) |
242 | // When running with assertions enabled we do track the owner. |
243 | ASSERT(owner_ == OSThread::kInvalidThreadId); |
244 | #endif // defined(DEBUG) |
245 | } |
246 | |
247 | void Mutex::Lock() { |
248 | AcquireSRWLockExclusive(&data_.lock_); |
249 | #if defined(DEBUG) |
250 | // When running with assertions enabled we do track the owner. |
251 | owner_ = OSThread::GetCurrentThreadId(); |
252 | #endif // defined(DEBUG) |
253 | } |
254 | |
255 | bool Mutex::TryLock() { |
256 | if (TryAcquireSRWLockExclusive(&data_.lock_) != 0) { |
257 | #if defined(DEBUG) |
258 | // When running with assertions enabled we do track the owner. |
259 | owner_ = OSThread::GetCurrentThreadId(); |
260 | #endif // defined(DEBUG) |
261 | return true; |
262 | } |
263 | return false; |
264 | } |
265 | |
266 | void Mutex::Unlock() { |
267 | #if defined(DEBUG) |
268 | // When running with assertions enabled we do track the owner. |
269 | ASSERT(IsOwnedByCurrentThread()); |
270 | owner_ = OSThread::kInvalidThreadId; |
271 | #endif // defined(DEBUG) |
272 | ReleaseSRWLockExclusive(&data_.lock_); |
273 | } |
274 | |
275 | Monitor::Monitor() { |
276 | InitializeSRWLock(&data_.lock_); |
277 | InitializeConditionVariable(&data_.cond_); |
278 | #if defined(DEBUG) |
279 | // When running with assertions enabled we track the owner. |
280 | owner_ = OSThread::kInvalidThreadId; |
281 | #endif // defined(DEBUG) |
282 | } |
283 | |
284 | Monitor::~Monitor() { |
285 | #if defined(DEBUG) |
286 | // When running with assertions enabled we track the owner. |
287 | ASSERT(owner_ == OSThread::kInvalidThreadId); |
288 | #endif // defined(DEBUG) |
289 | } |
290 | |
291 | bool Monitor::TryEnter() { |
292 | // Attempt to pass the semaphore but return immediately. |
293 | if (TryAcquireSRWLockExclusive(&data_.lock_) != 0) { |
294 | #if defined(DEBUG) |
295 | // When running with assertions enabled we do track the owner. |
296 | ASSERT(owner_ == OSThread::kInvalidThreadId); |
297 | owner_ = OSThread::GetCurrentThreadId(); |
298 | #endif // defined(DEBUG) |
299 | return true; |
300 | } |
301 | return false; |
302 | } |
303 | |
304 | void Monitor::Enter() { |
305 | AcquireSRWLockExclusive(&data_.lock_); |
306 | |
307 | #if defined(DEBUG) |
308 | // When running with assertions enabled we track the owner. |
309 | ASSERT(owner_ == OSThread::kInvalidThreadId); |
310 | owner_ = OSThread::GetCurrentThreadId(); |
311 | #endif // defined(DEBUG) |
312 | } |
313 | |
314 | void Monitor::Exit() { |
315 | #if defined(DEBUG) |
316 | // When running with assertions enabled we track the owner. |
317 | ASSERT(IsOwnedByCurrentThread()); |
318 | owner_ = OSThread::kInvalidThreadId; |
319 | #endif // defined(DEBUG) |
320 | |
321 | ReleaseSRWLockExclusive(&data_.lock_); |
322 | } |
323 | |
324 | Monitor::WaitResult Monitor::Wait(int64_t millis) { |
325 | #if defined(DEBUG) |
326 | // When running with assertions enabled we track the owner. |
327 | ASSERT(IsOwnedByCurrentThread()); |
328 | ThreadId saved_owner = owner_; |
329 | owner_ = OSThread::kInvalidThreadId; |
330 | #endif // defined(DEBUG) |
331 | |
332 | Monitor::WaitResult retval = kNotified; |
333 | if (millis == kNoTimeout) { |
334 | SleepConditionVariableSRW(&data_.cond_, &data_.lock_, INFINITE, 0); |
335 | } else { |
336 | // Wait for the given period of time for a Notify or a NotifyAll |
337 | // event. |
338 | if (!SleepConditionVariableSRW(&data_.cond_, &data_.lock_, millis, 0)) { |
339 | ASSERT(GetLastError() == ERROR_TIMEOUT); |
340 | retval = kTimedOut; |
341 | } |
342 | } |
343 | |
344 | #if defined(DEBUG) |
345 | // When running with assertions enabled we track the owner. |
346 | ASSERT(owner_ == OSThread::kInvalidThreadId); |
347 | owner_ = OSThread::GetCurrentThreadId(); |
348 | ASSERT(owner_ == saved_owner); |
349 | #endif // defined(DEBUG) |
350 | return retval; |
351 | } |
352 | |
353 | Monitor::WaitResult Monitor::WaitMicros(int64_t micros) { |
354 | // TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows. |
355 | int64_t millis = micros / kMicrosecondsPerMillisecond; |
356 | if ((millis * kMicrosecondsPerMillisecond) < micros) { |
357 | // We've been asked to sleep for a fraction of a millisecond, |
358 | // this isn't supported on Windows. Bumps milliseconds up by one |
359 | // so that we never return too early. We likely return late though. |
360 | millis += 1; |
361 | } |
362 | return Wait(millis); |
363 | } |
364 | |
365 | void Monitor::Notify() { |
366 | // When running with assertions enabled we track the owner. |
367 | ASSERT(IsOwnedByCurrentThread()); |
368 | WakeConditionVariable(&data_.cond_); |
369 | } |
370 | |
371 | void Monitor::NotifyAll() { |
372 | // When running with assertions enabled we track the owner. |
373 | ASSERT(IsOwnedByCurrentThread()); |
374 | WakeAllConditionVariable(&data_.cond_); |
375 | } |
376 | |
377 | void ThreadLocalData::AddThreadLocal(ThreadLocalKey key, |
378 | ThreadDestructor destructor) { |
379 | ASSERT(thread_locals_ != NULL); |
380 | if (destructor == NULL) { |
381 | // We only care about thread locals with destructors. |
382 | return; |
383 | } |
384 | MutexLocker ml(mutex_); |
385 | #if defined(DEBUG) |
386 | // Verify that we aren't added twice. |
387 | for (intptr_t i = 0; i < thread_locals_->length(); i++) { |
388 | const ThreadLocalEntry& entry = thread_locals_->At(i); |
389 | ASSERT(entry.key() != key); |
390 | } |
391 | #endif |
392 | // Add to list. |
393 | thread_locals_->Add(ThreadLocalEntry(key, destructor)); |
394 | } |
395 | |
396 | void ThreadLocalData::RemoveThreadLocal(ThreadLocalKey key) { |
397 | ASSERT(thread_locals_ != NULL); |
398 | MutexLocker ml(mutex_); |
399 | intptr_t i = 0; |
400 | for (; i < thread_locals_->length(); i++) { |
401 | const ThreadLocalEntry& entry = thread_locals_->At(i); |
402 | if (entry.key() == key) { |
403 | break; |
404 | } |
405 | } |
406 | if (i == thread_locals_->length()) { |
407 | // Not found. |
408 | return; |
409 | } |
410 | thread_locals_->RemoveAt(i); |
411 | } |
412 | |
413 | // This function is executed on the thread that is exiting. It is invoked |
414 | // by |OnDartThreadExit| (see below for notes on TLS destructors on Windows). |
415 | void ThreadLocalData::RunDestructors() { |
416 | // If an OS thread is created but ThreadLocalData::Init has not yet been |
417 | // called, this method still runs. If this happens, there's nothing to clean |
418 | // up here. See issue 33826. |
419 | if (thread_locals_ == NULL) { |
420 | return; |
421 | } |
422 | ASSERT(mutex_ != NULL); |
423 | MutexLocker ml(mutex_); |
424 | for (intptr_t i = 0; i < thread_locals_->length(); i++) { |
425 | const ThreadLocalEntry& entry = thread_locals_->At(i); |
426 | // We access the exiting thread's TLS variable here. |
427 | void* p = reinterpret_cast<void*>(OSThread::GetThreadLocal(entry.key())); |
428 | // We invoke the constructor here. |
429 | entry.destructor()(p); |
430 | } |
431 | } |
432 | |
433 | Mutex* ThreadLocalData::mutex_ = NULL; |
434 | MallocGrowableArray<ThreadLocalEntry>* ThreadLocalData::thread_locals_ = NULL; |
435 | |
436 | void ThreadLocalData::Init() { |
437 | mutex_ = new Mutex(); |
438 | thread_locals_ = new MallocGrowableArray<ThreadLocalEntry>(); |
439 | } |
440 | |
441 | void ThreadLocalData::Cleanup() { |
442 | if (mutex_ != NULL) { |
443 | delete mutex_; |
444 | mutex_ = NULL; |
445 | } |
446 | if (thread_locals_ != NULL) { |
447 | delete thread_locals_; |
448 | thread_locals_ = NULL; |
449 | } |
450 | } |
451 | |
452 | } // namespace dart |
453 | |
454 | // The following was adapted from Chromium: |
455 | // src/base/threading/thread_local_storage_win.cc |
456 | |
457 | // Thread Termination Callbacks. |
458 | // Windows doesn't support a per-thread destructor with its |
459 | // TLS primitives. So, we build it manually by inserting a |
460 | // function to be called on each thread's exit. |
461 | // This magic is from http://www.codeproject.com/threads/tls.asp |
462 | // and it works for VC++ 7.0 and later. |
463 | |
464 | // Force a reference to _tls_used to make the linker create the TLS directory |
465 | // if it's not already there. (e.g. if __declspec(thread) is not used). |
466 | // Force a reference to p_thread_callback_dart to prevent whole program |
467 | // optimization from discarding the variable. |
468 | #ifdef _WIN64 |
469 | |
470 | #pragma comment(linker, "/INCLUDE:_tls_used") |
471 | #pragma comment(linker, "/INCLUDE:p_thread_callback_dart") |
472 | |
473 | #else // _WIN64 |
474 | |
475 | #pragma comment(linker, "/INCLUDE:__tls_used") |
476 | #pragma comment(linker, "/INCLUDE:_p_thread_callback_dart") |
477 | |
478 | #endif // _WIN64 |
479 | |
480 | // Static callback function to call with each thread termination. |
481 | void NTAPI OnDartThreadExit(PVOID module, DWORD reason, PVOID reserved) { |
482 | if (!dart::private_flag_windows_run_tls_destructors) { |
483 | return; |
484 | } |
485 | // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+ |
486 | // and on W2K and W2K3. So don't assume it is sent. |
487 | if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason) { |
488 | dart::ThreadLocalData::RunDestructors(); |
489 | } |
490 | } |
491 | |
492 | // .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are |
493 | // called automatically by the OS loader code (not the CRT) when the module is |
494 | // loaded and on thread creation. They are NOT called if the module has been |
495 | // loaded by a LoadLibrary() call. It must have implicitly been loaded at |
496 | // process startup. |
497 | // By implicitly loaded, I mean that it is directly referenced by the main EXE |
498 | // or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being |
499 | // implicitly loaded. |
500 | // |
501 | // See VC\crt\src\tlssup.c for reference. |
502 | |
503 | // extern "C" suppresses C++ name mangling so we know the symbol name for the |
504 | // linker /INCLUDE:symbol pragma above. |
505 | extern "C" { |
506 | // The linker must not discard p_thread_callback_dart. (We force a reference |
507 | // to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If |
508 | // this variable is discarded, the OnDartThreadExit function will never be |
509 | // called. |
510 | #ifdef _WIN64 |
511 | |
512 | // .CRT section is merged with .rdata on x64 so it must be constant data. |
513 | #pragma const_seg(".CRT$XLB") |
514 | // When defining a const variable, it must have external linkage to be sure the |
515 | // linker doesn't discard it. |
516 | extern const PIMAGE_TLS_CALLBACK p_thread_callback_dart; |
517 | const PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnDartThreadExit; |
518 | |
519 | // Reset the default section. |
520 | #pragma const_seg() |
521 | |
522 | #else // _WIN64 |
523 | |
524 | #pragma data_seg(".CRT$XLB") |
525 | PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnDartThreadExit; |
526 | |
527 | // Reset the default section. |
528 | #pragma data_seg() |
529 | |
530 | #endif // _WIN64 |
531 | } // extern "C" |
532 | |
533 | #endif // defined(HOST_OS_WINDOWS) |
534 | |