1317017Sdim//===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===// 2317017Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6317017Sdim// 7317017Sdim//===----------------------------------------------------------------------===// 8317017Sdim// 9317017Sdim// This file provides the Win32 specific implementation of Threading functions. 10317017Sdim// 11317017Sdim//===----------------------------------------------------------------------===// 12317017Sdim 13317017Sdim#include "llvm/ADT/SmallString.h" 14317017Sdim#include "llvm/ADT/Twine.h" 15317017Sdim 16360784Sdim#include "llvm/Support/Windows/WindowsSupport.h" 17317017Sdim#include <process.h> 18317017Sdim 19317017Sdim// Windows will at times define MemoryFence. 20317017Sdim#ifdef MemoryFence 21317017Sdim#undef MemoryFence 22317017Sdim#endif 23317017Sdim 24360784Sdimstatic unsigned __stdcall threadFuncSync(void *Arg) { 25360784Sdim SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg); 26360784Sdim TI->UserFn(TI->UserData); 27360784Sdim return 0; 28317017Sdim} 29317017Sdim 30360784Sdimstatic unsigned __stdcall threadFuncAsync(void *Arg) { 31360784Sdim std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg)); 32360784Sdim (*Info)(); 33317017Sdim return 0; 34317017Sdim} 35317017Sdim 36360784Sdimstatic void 37360784Sdimllvm_execute_on_thread_impl(unsigned (__stdcall *ThreadFunc)(void *), void *Arg, 38360784Sdim llvm::Optional<unsigned> StackSizeInBytes, 39360784Sdim JoiningPolicy JP) { 40360784Sdim HANDLE hThread = (HANDLE)::_beginthreadex( 41360784Sdim NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL); 42317017Sdim 43360784Sdim if (!hThread) { 44360784Sdim ReportLastErrorFatal("_beginthreadex failed"); 45360784Sdim } 46317017Sdim 47360784Sdim if (JP == JoiningPolicy::Join) { 48360784Sdim if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) { 49360784Sdim ReportLastErrorFatal("WaitForSingleObject failed"); 50360784Sdim } 51317017Sdim } 52360784Sdim if (::CloseHandle(hThread) == FALSE) { 53360784Sdim ReportLastErrorFatal("CloseHandle failed"); 54360784Sdim } 55317017Sdim} 56317017Sdim 57317017Sdimuint64_t llvm::get_threadid() { 58317017Sdim return uint64_t(::GetCurrentThreadId()); 59317017Sdim} 60317017Sdim 61317017Sdimuint32_t llvm::get_max_thread_name_length() { return 0; } 62317017Sdim 63317017Sdim#if defined(_MSC_VER) 64317017Sdimstatic void SetThreadName(DWORD Id, LPCSTR Name) { 65317017Sdim constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; 66317017Sdim 67317017Sdim#pragma pack(push, 8) 68317017Sdim struct THREADNAME_INFO { 69317017Sdim DWORD dwType; // Must be 0x1000. 70317017Sdim LPCSTR szName; // Pointer to thread name 71317017Sdim DWORD dwThreadId; // Thread ID (-1 == current thread) 72317017Sdim DWORD dwFlags; // Reserved. Do not use. 73317017Sdim }; 74317017Sdim#pragma pack(pop) 75317017Sdim 76317017Sdim THREADNAME_INFO info; 77317017Sdim info.dwType = 0x1000; 78317017Sdim info.szName = Name; 79317017Sdim info.dwThreadId = Id; 80317017Sdim info.dwFlags = 0; 81317017Sdim 82317017Sdim __try { 83317017Sdim ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), 84317017Sdim (ULONG_PTR *)&info); 85317017Sdim } 86317017Sdim __except (EXCEPTION_EXECUTE_HANDLER) { 87317017Sdim } 88317017Sdim} 89317017Sdim#endif 90317017Sdim 91317017Sdimvoid llvm::set_thread_name(const Twine &Name) { 92317017Sdim#if defined(_MSC_VER) 93317017Sdim // Make sure the input is null terminated. 94317017Sdim SmallString<64> Storage; 95317017Sdim StringRef NameStr = Name.toNullTerminatedStringRef(Storage); 96317017Sdim SetThreadName(::GetCurrentThreadId(), NameStr.data()); 97317017Sdim#endif 98317017Sdim} 99317017Sdim 100317017Sdimvoid llvm::get_thread_name(SmallVectorImpl<char> &Name) { 101317017Sdim // "Name" is not an inherent property of a thread on Windows. In fact, when 102317017Sdim // you "set" the name, you are only firing a one-time message to a debugger 103317017Sdim // which it interprets as a program setting its threads' name. We may be 104317017Sdim // able to get fancy by creating a TLS entry when someone calls 105317017Sdim // set_thread_name so that subsequent calls to get_thread_name return this 106317017Sdim // value. 107317017Sdim Name.clear(); 108317017Sdim} 109353358Sdim 110353358SdimSetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { 111353358Sdim // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority 112353358Sdim // Begin background processing mode. The system lowers the resource scheduling 113353358Sdim // priorities of the thread so that it can perform background work without 114353358Sdim // significantly affecting activity in the foreground. 115353358Sdim // End background processing mode. The system restores the resource scheduling 116353358Sdim // priorities of the thread as they were before the thread entered background 117353358Sdim // processing mode. 118353358Sdim return SetThreadPriority(GetCurrentThread(), 119353358Sdim Priority == ThreadPriority::Background 120353358Sdim ? THREAD_MODE_BACKGROUND_BEGIN 121353358Sdim : THREAD_MODE_BACKGROUND_END) 122353358Sdim ? SetThreadPriorityResult::SUCCESS 123353358Sdim : SetThreadPriorityResult::FAILURE; 124353358Sdim} 125