Threading.inc revision 353358
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
16344779Sdim#include "WindowsSupport.h"
17317017Sdim#include <process.h>
18317017Sdim
19317017Sdim// Windows will at times define MemoryFence.
20317017Sdim#ifdef MemoryFence
21317017Sdim#undef MemoryFence
22317017Sdim#endif
23317017Sdim
24317017Sdimnamespace {
25317017Sdim  struct ThreadInfo {
26317017Sdim    void(*func)(void*);
27317017Sdim    void *param;
28317017Sdim  };
29317017Sdim}
30317017Sdim
31317017Sdimstatic unsigned __stdcall ThreadCallback(void *param) {
32317017Sdim  struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param);
33317017Sdim  info->func(info->param);
34317017Sdim
35317017Sdim  return 0;
36317017Sdim}
37317017Sdim
38317017Sdimvoid llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData,
39317017Sdim  unsigned RequestedStackSize) {
40317017Sdim  struct ThreadInfo param = { Fn, UserData };
41317017Sdim
42317017Sdim  HANDLE hThread = (HANDLE)::_beginthreadex(NULL,
43317017Sdim    RequestedStackSize, ThreadCallback,
44317017Sdim    &param, 0, NULL);
45317017Sdim
46317017Sdim  if (hThread) {
47317017Sdim    // We actually don't care whether the wait succeeds or fails, in
48317017Sdim    // the same way we don't care whether the pthread_join call succeeds
49317017Sdim    // or fails.  There's not much we could do if this were to fail. But
50317017Sdim    // on success, this call will wait until the thread finishes executing
51317017Sdim    // before returning.
52317017Sdim    (void)::WaitForSingleObject(hThread, INFINITE);
53317017Sdim    ::CloseHandle(hThread);
54317017Sdim  }
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