// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" // NOLINT #if defined(DART_HOST_OS_WINDOWS) && !defined(DART_USE_ABSL) #include "vm/os_thread.h" #include #include #include "platform/address_sanitizer.h" #include "platform/assert.h" #include "platform/safe_stack.h" #include "vm/flags.h" #include "vm/growable_array.h" #include "vm/lockers.h" namespace dart { DEFINE_FLAG(int, worker_thread_priority, kMinInt, "The thread priority the VM should use for new worker threads."); // This flag is flipped by platform_win.cc when the process is exiting. // TODO(zra): Remove once VM shuts down cleanly. bool private_flag_windows_run_tls_destructors = true; class ThreadStartData { public: ThreadStartData(const char* name, OSThread::ThreadStartFunction function, uword parameter) : name_(name), function_(function), parameter_(parameter) {} const char* name() const { return name_; } OSThread::ThreadStartFunction function() const { return function_; } uword parameter() const { return parameter_; } private: const char* name_; OSThread::ThreadStartFunction function_; uword parameter_; DISALLOW_COPY_AND_ASSIGN(ThreadStartData); }; // Dispatch to the thread start function provided by the caller. This trampoline // is used to ensure that the thread is properly destroyed if the thread just // exits. static unsigned int __stdcall ThreadEntry(void* data_ptr) { if (FLAG_worker_thread_priority != kMinInt) { if (SetThreadPriority(GetCurrentThread(), FLAG_worker_thread_priority) == 0) { FATAL("Setting thread priority to %d failed: GetLastError() = %d\n", FLAG_worker_thread_priority, GetLastError()); } } ThreadStartData* data = reinterpret_cast(data_ptr); const char* name = data->name(); OSThread::ThreadStartFunction function = data->function(); uword parameter = data->parameter(); delete data; // Create new OSThread object and set as TLS for new thread. OSThread* thread = OSThread::CreateOSThread(); if (thread != nullptr) { OSThread::SetCurrent(thread); thread->SetName(name); // Call the supplied thread start function handing it its parameters. function(parameter); } return 0; } int OSThread::TryStart(const char* name, ThreadStartFunction function, uword parameter) { ThreadStartData* start_data = new ThreadStartData(name, function, parameter); uint32_t tid; uintptr_t thread = _beginthreadex(nullptr, OSThread::GetMaxStackSize(), ThreadEntry, start_data, 0, &tid); if (thread == -1L || thread == 0) { return errno; } // Close the handle, so we don't leak the thread object. CloseHandle(reinterpret_cast(thread)); return 0; } const ThreadJoinId OSThread::kInvalidThreadJoinId = nullptr; intptr_t OSThread::GetMaxStackSize() { const int kStackSize = (128 * kWordSize * KB); return kStackSize; } #ifdef SUPPORT_TIMELINE ThreadId OSThread::GetCurrentThreadTraceId() { return ::GetCurrentThreadId(); } #endif // SUPPORT_TIMELINE char* OSThread::GetCurrentThreadName() { // TODO(derekx): We aren't even setting the thread name on Windows, so we need // to figure out how to set/get the thread name on Windows. return nullptr; } ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) { ASSERT(thread != nullptr); // Make sure we're filling in the join id for the current thread. ThreadId id = GetCurrentThreadId(); ASSERT(thread->id() == id); // Make sure the join_id_ hasn't been set, yet. DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId); HANDLE handle = OpenThread(SYNCHRONIZE, false, id); ASSERT(handle != nullptr); #if defined(DEBUG) thread->join_id_ = handle; #endif return handle; } void OSThread::Join(ThreadJoinId id) { HANDLE handle = static_cast(id); ASSERT(handle != nullptr); DWORD res = WaitForSingleObject(handle, INFINITE); CloseHandle(handle); ASSERT(res == WAIT_OBJECT_0); } void OSThread::Detach(ThreadJoinId id) { HANDLE handle = static_cast(id); ASSERT(handle != nullptr); CloseHandle(handle); } intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) { COMPILE_ASSERT(sizeof(id) <= sizeof(intptr_t)); return static_cast(id); } ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) { return static_cast(id); } bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) { // PULONG and uword are sometimes different fundamental types. ::GetCurrentThreadStackLimits(reinterpret_cast(lower), reinterpret_cast(upper)); return true; } #if defined(USING_SAFE_STACK) NO_SANITIZE_ADDRESS NO_SANITIZE_SAFE_STACK uword OSThread::GetCurrentSafestackPointer() { #error "SAFE_STACK is unsupported on this platform" return 0; } NO_SANITIZE_ADDRESS NO_SANITIZE_SAFE_STACK void OSThread::SetCurrentSafestackPointer(uword ssp) { #error "SAFE_STACK is unsupported on this platform" } #endif } // namespace dart #endif // defined(DART_HOST_OS_WINDOWS) && !defined(DART_USE_ABSL)