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