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
20namespace dart {
21
22DEFINE_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.
29bool private_flag_windows_run_tls_destructors = true;
30
31class 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.
53static 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
82int 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
102const ThreadId OSThread::kInvalidThreadId = 0;
103const ThreadJoinId OSThread::kInvalidThreadJoinId = NULL;
104
105ThreadLocalKey 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
114void 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
123intptr_t OSThread::GetMaxStackSize() {
124 const int kStackSize = (128 * kWordSize * KB);
125 return kStackSize;
126}
127
128ThreadId OSThread::GetCurrentThreadId() {
129 return ::GetCurrentThreadId();
130}
131
132#ifdef SUPPORT_TIMELINE
133ThreadId OSThread::GetCurrentThreadTraceId() {
134 return ::GetCurrentThreadId();
135}
136#endif // PRODUCT
137
138ThreadJoinId 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
153void 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
161intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) {
162 ASSERT(sizeof(id) <= sizeof(intptr_t));
163 return static_cast<intptr_t>(id);
164}
165
166ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) {
167 return static_cast<ThreadId>(id);
168}
169
170bool OSThread::Compare(ThreadId a, ThreadId b) {
171 return a == b;
172}
173
174bool 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)
206NO_SANITIZE_ADDRESS
207NO_SANITIZE_SAFE_STACK
208uword OSThread::GetCurrentSafestackPointer() {
209#error "SAFE_STACK is unsupported on this platform"
210 return 0;
211}
212
213NO_SANITIZE_ADDRESS
214NO_SANITIZE_SAFE_STACK
215void OSThread::SetCurrentSafestackPointer(uword ssp) {
216#error "SAFE_STACK is unsupported on this platform"
217}
218#endif
219
220void 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
228Mutex::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
240Mutex::~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
247void 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
255bool 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
266void 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
275Monitor::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
284Monitor::~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
291bool 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
304void 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
314void 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
324Monitor::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
353Monitor::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
365void Monitor::Notify() {
366 // When running with assertions enabled we track the owner.
367 ASSERT(IsOwnedByCurrentThread());
368 WakeConditionVariable(&data_.cond_);
369}
370
371void Monitor::NotifyAll() {
372 // When running with assertions enabled we track the owner.
373 ASSERT(IsOwnedByCurrentThread());
374 WakeAllConditionVariable(&data_.cond_);
375}
376
377void 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
396void 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).
415void 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
433Mutex* ThreadLocalData::mutex_ = NULL;
434MallocGrowableArray<ThreadLocalEntry>* ThreadLocalData::thread_locals_ = NULL;
435
436void ThreadLocalData::Init() {
437 mutex_ = new Mutex();
438 thread_locals_ = new MallocGrowableArray<ThreadLocalEntry>();
439}
440
441void 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.
481void 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.
505extern "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.
516extern const PIMAGE_TLS_CALLBACK p_thread_callback_dart;
517const 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")
525PIMAGE_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