| //===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file provides the Win32 specific implementation of Threading functions. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/ADT/SmallString.h" | |
| #include "llvm/ADT/Twine.h" | |
| #include "llvm/Support/Windows/WindowsSupport.h" | |
| #include <process.h> | |
| // Windows will at times define MemoryFence. | |
| #ifdef MemoryFence | |
| #undef MemoryFence | |
| #endif | |
| static unsigned __stdcall threadFuncSync(void *Arg) { | |
| SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg); | |
| TI->UserFn(TI->UserData); | |
| return 0; | |
| } | |
| static unsigned __stdcall threadFuncAsync(void *Arg) { | |
| std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg)); | |
| (*Info)(); | |
| return 0; | |
| } | |
| static void | |
| llvm_execute_on_thread_impl(unsigned (__stdcall *ThreadFunc)(void *), void *Arg, | |
| llvm::Optional<unsigned> StackSizeInBytes, | |
| JoiningPolicy JP) { | |
| HANDLE hThread = (HANDLE)::_beginthreadex( | |
| NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL); | |
| if (!hThread) { | |
| ReportLastErrorFatal("_beginthreadex failed"); | |
| } | |
| if (JP == JoiningPolicy::Join) { | |
| if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) { | |
| ReportLastErrorFatal("WaitForSingleObject failed"); | |
| } | |
| } | |
| if (::CloseHandle(hThread) == FALSE) { | |
| ReportLastErrorFatal("CloseHandle failed"); | |
| } | |
| } | |
| uint64_t llvm::get_threadid() { | |
| return uint64_t(::GetCurrentThreadId()); | |
| } | |
| uint32_t llvm::get_max_thread_name_length() { return 0; } | |
| #if defined(_MSC_VER) | |
| static void SetThreadName(DWORD Id, LPCSTR Name) { | |
| constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; | |
| #pragma pack(push, 8) | |
| struct THREADNAME_INFO { | |
| DWORD dwType; // Must be 0x1000. | |
| LPCSTR szName; // Pointer to thread name | |
| DWORD dwThreadId; // Thread ID (-1 == current thread) | |
| DWORD dwFlags; // Reserved. Do not use. | |
| }; | |
| #pragma pack(pop) | |
| THREADNAME_INFO info; | |
| info.dwType = 0x1000; | |
| info.szName = Name; | |
| info.dwThreadId = Id; | |
| info.dwFlags = 0; | |
| __try { | |
| ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), | |
| (ULONG_PTR *)&info); | |
| } | |
| __except (EXCEPTION_EXECUTE_HANDLER) { | |
| } | |
| } | |
| #endif | |
| void llvm::set_thread_name(const Twine &Name) { | |
| #if defined(_MSC_VER) | |
| // Make sure the input is null terminated. | |
| SmallString<64> Storage; | |
| StringRef NameStr = Name.toNullTerminatedStringRef(Storage); | |
| SetThreadName(::GetCurrentThreadId(), NameStr.data()); | |
| #endif | |
| } | |
| void llvm::get_thread_name(SmallVectorImpl<char> &Name) { | |
| // "Name" is not an inherent property of a thread on Windows. In fact, when | |
| // you "set" the name, you are only firing a one-time message to a debugger | |
| // which it interprets as a program setting its threads' name. We may be | |
| // able to get fancy by creating a TLS entry when someone calls | |
| // set_thread_name so that subsequent calls to get_thread_name return this | |
| // value. | |
| Name.clear(); | |
| } | |
| SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { | |
| // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority | |
| // Begin background processing mode. The system lowers the resource scheduling | |
| // priorities of the thread so that it can perform background work without | |
| // significantly affecting activity in the foreground. | |
| // End background processing mode. The system restores the resource scheduling | |
| // priorities of the thread as they were before the thread entered background | |
| // processing mode. | |
| return SetThreadPriority(GetCurrentThread(), | |
| Priority == ThreadPriority::Background | |
| ? THREAD_MODE_BACKGROUND_BEGIN | |
| : THREAD_MODE_BACKGROUND_END) | |
| ? SetThreadPriorityResult::SUCCESS | |
| : SetThreadPriorityResult::FAILURE; | |
| } |