2017-03-03 18:15:17 +01:00
|
|
|
//===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-03-03 18:15:17 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file provides the Win32 specific implementation of Threading functions.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "llvm/ADT/Twine.h"
|
|
|
|
|
2019-01-08 22:05:34 +01:00
|
|
|
#include "WindowsSupport.h"
|
2017-03-03 18:15:17 +01:00
|
|
|
#include <process.h>
|
|
|
|
|
|
|
|
// Windows will at times define MemoryFence.
|
|
|
|
#ifdef MemoryFence
|
|
|
|
#undef MemoryFence
|
|
|
|
#endif
|
|
|
|
|
2019-10-23 15:34:48 +02:00
|
|
|
static unsigned __stdcall threadFuncSync(void *Arg) {
|
|
|
|
SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg);
|
|
|
|
TI->UserFn(TI->UserData);
|
|
|
|
return 0;
|
2017-03-03 18:15:17 +01:00
|
|
|
}
|
|
|
|
|
2019-10-23 15:34:48 +02:00
|
|
|
static unsigned __stdcall threadFuncAsync(void *Arg) {
|
|
|
|
std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg));
|
|
|
|
(*Info)();
|
2017-03-03 18:15:17 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-23 15:34:48 +02:00
|
|
|
static void
|
|
|
|
llvm_execute_on_thread_impl(_beginthreadex_proc_type ThreadFunc, void *Arg,
|
|
|
|
llvm::Optional<unsigned> StackSizeInBytes,
|
|
|
|
JoiningPolicy JP) {
|
|
|
|
HANDLE hThread = (HANDLE)::_beginthreadex(
|
|
|
|
NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL);
|
2017-03-03 18:15:17 +01:00
|
|
|
|
2019-10-23 15:34:48 +02:00
|
|
|
if (!hThread) {
|
|
|
|
ReportLastErrorFatal("_beginthreadex failed");
|
|
|
|
}
|
2017-03-03 18:15:17 +01:00
|
|
|
|
2019-10-23 15:34:48 +02:00
|
|
|
if (JP == JoiningPolicy::Join) {
|
|
|
|
if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) {
|
|
|
|
ReportLastErrorFatal("WaitForSingleObject failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (::CloseHandle(hThread) == FALSE) {
|
|
|
|
ReportLastErrorFatal("CloseHandle failed");
|
2017-03-03 18:15:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t llvm::get_threadid() {
|
|
|
|
return uint64_t(::GetCurrentThreadId());
|
|
|
|
}
|
|
|
|
|
2017-03-04 19:53:09 +01:00
|
|
|
uint32_t llvm::get_max_thread_name_length() { return 0; }
|
2017-03-04 17:42:25 +01:00
|
|
|
|
2017-03-03 18:15:17 +01:00
|
|
|
#if defined(_MSC_VER)
|
2017-03-07 21:09:46 +01:00
|
|
|
static void SetThreadName(DWORD Id, LPCSTR Name) {
|
2017-03-03 18:15:17 +01:00
|
|
|
constexpr DWORD MS_VC_EXCEPTION = 0x406D1388;
|
|
|
|
|
|
|
|
#pragma pack(push, 8)
|
|
|
|
struct THREADNAME_INFO {
|
|
|
|
DWORD dwType; // Must be 0x1000.
|
|
|
|
LPCSTR szName; // Pointer to thread name
|
|
|
|
DWORD dwThreadId; // Thread ID (-1 == current thread)
|
|
|
|
DWORD dwFlags; // Reserved. Do not use.
|
|
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
THREADNAME_INFO info;
|
|
|
|
info.dwType = 0x1000;
|
2017-03-07 21:09:46 +01:00
|
|
|
info.szName = Name;
|
|
|
|
info.dwThreadId = Id;
|
2017-03-03 18:15:17 +01:00
|
|
|
info.dwFlags = 0;
|
|
|
|
|
|
|
|
__try {
|
|
|
|
::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR),
|
|
|
|
(ULONG_PTR *)&info);
|
|
|
|
}
|
|
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
}
|
2017-03-07 21:09:46 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void llvm::set_thread_name(const Twine &Name) {
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
// Make sure the input is null terminated.
|
|
|
|
SmallString<64> Storage;
|
|
|
|
StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
|
|
|
|
SetThreadName(::GetCurrentThreadId(), NameStr.data());
|
2017-03-03 18:15:17 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
|
|
|
|
// "Name" is not an inherent property of a thread on Windows. In fact, when
|
|
|
|
// you "set" the name, you are only firing a one-time message to a debugger
|
|
|
|
// which it interprets as a program setting its threads' name. We may be
|
|
|
|
// able to get fancy by creating a TLS entry when someone calls
|
|
|
|
// set_thread_name so that subsequent calls to get_thread_name return this
|
|
|
|
// value.
|
|
|
|
Name.clear();
|
|
|
|
}
|
2019-04-16 16:32:43 +02:00
|
|
|
|
|
|
|
SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
|
|
|
|
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority
|
|
|
|
// Begin background processing mode. The system lowers the resource scheduling
|
|
|
|
// priorities of the thread so that it can perform background work without
|
|
|
|
// significantly affecting activity in the foreground.
|
|
|
|
// End background processing mode. The system restores the resource scheduling
|
|
|
|
// priorities of the thread as they were before the thread entered background
|
|
|
|
// processing mode.
|
|
|
|
return SetThreadPriority(GetCurrentThread(),
|
|
|
|
Priority == ThreadPriority::Background
|
|
|
|
? THREAD_MODE_BACKGROUND_BEGIN
|
|
|
|
: THREAD_MODE_BACKGROUND_END)
|
|
|
|
? SetThreadPriorityResult::SUCCESS
|
|
|
|
: SetThreadPriorityResult::FAILURE;
|
|
|
|
}
|