1//===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file provides the Win32 specific implementation of Threading functions. 10// 11//===----------------------------------------------------------------------===// 12 13#include "llvm/ADT/SmallString.h" 14#include "llvm/ADT/Twine.h" 15 16#include "llvm/Support/Windows/WindowsSupport.h" 17#include <process.h> 18 19// Windows will at times define MemoryFence. 20#ifdef MemoryFence 21#undef MemoryFence 22#endif 23 24static unsigned __stdcall threadFuncSync(void *Arg) { 25 SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg); 26 TI->UserFn(TI->UserData); 27 return 0; 28} 29 30static unsigned __stdcall threadFuncAsync(void *Arg) { 31 std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg)); 32 (*Info)(); 33 return 0; 34} 35 36static void 37llvm_execute_on_thread_impl(unsigned (__stdcall *ThreadFunc)(void *), void *Arg, 38 llvm::Optional<unsigned> StackSizeInBytes, 39 JoiningPolicy JP) { 40 HANDLE hThread = (HANDLE)::_beginthreadex( 41 NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL); 42 43 if (!hThread) { 44 ReportLastErrorFatal("_beginthreadex failed"); 45 } 46 47 if (JP == JoiningPolicy::Join) { 48 if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) { 49 ReportLastErrorFatal("WaitForSingleObject failed"); 50 } 51 } 52 if (::CloseHandle(hThread) == FALSE) { 53 ReportLastErrorFatal("CloseHandle failed"); 54 } 55} 56 57uint64_t llvm::get_threadid() { 58 return uint64_t(::GetCurrentThreadId()); 59} 60 61uint32_t llvm::get_max_thread_name_length() { return 0; } 62 63#if defined(_MSC_VER) 64static void SetThreadName(DWORD Id, LPCSTR Name) { 65 constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; 66 67#pragma pack(push, 8) 68 struct THREADNAME_INFO { 69 DWORD dwType; // Must be 0x1000. 70 LPCSTR szName; // Pointer to thread name 71 DWORD dwThreadId; // Thread ID (-1 == current thread) 72 DWORD dwFlags; // Reserved. Do not use. 73 }; 74#pragma pack(pop) 75 76 THREADNAME_INFO info; 77 info.dwType = 0x1000; 78 info.szName = Name; 79 info.dwThreadId = Id; 80 info.dwFlags = 0; 81 82 __try { 83 ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), 84 (ULONG_PTR *)&info); 85 } 86 __except (EXCEPTION_EXECUTE_HANDLER) { 87 } 88} 89#endif 90 91void llvm::set_thread_name(const Twine &Name) { 92#if defined(_MSC_VER) 93 // Make sure the input is null terminated. 94 SmallString<64> Storage; 95 StringRef NameStr = Name.toNullTerminatedStringRef(Storage); 96 SetThreadName(::GetCurrentThreadId(), NameStr.data()); 97#endif 98} 99 100void llvm::get_thread_name(SmallVectorImpl<char> &Name) { 101 // "Name" is not an inherent property of a thread on Windows. In fact, when 102 // you "set" the name, you are only firing a one-time message to a debugger 103 // which it interprets as a program setting its threads' name. We may be 104 // able to get fancy by creating a TLS entry when someone calls 105 // set_thread_name so that subsequent calls to get_thread_name return this 106 // value. 107 Name.clear(); 108} 109 110SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { 111 // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority 112 // Begin background processing mode. The system lowers the resource scheduling 113 // priorities of the thread so that it can perform background work without 114 // significantly affecting activity in the foreground. 115 // End background processing mode. The system restores the resource scheduling 116 // priorities of the thread as they were before the thread entered background 117 // processing mode. 118 return SetThreadPriority(GetCurrentThread(), 119 Priority == ThreadPriority::Background 120 ? THREAD_MODE_BACKGROUND_BEGIN 121 : THREAD_MODE_BACKGROUND_END) 122 ? SetThreadPriorityResult::SUCCESS 123 : SetThreadPriorityResult::FAILURE; 124} 125