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