1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 02:33:06 +01:00

Revert "Support: add llvm::thread class that supports specifying stack size."

It's causing build failures because DefaultStackSize isn't defined everywhere
it should be and I need time to investigate.
This commit is contained in:
Tim Northover 2021-07-08 14:59:47 +01:00
parent 43bfac999c
commit 1b885b1ce7
9 changed files with 141 additions and 286 deletions

View File

@ -87,7 +87,7 @@ public:
/// a protected context which is run in another thread (optionally with a
/// requested stack size).
///
/// See RunSafely().
/// See RunSafely() and llvm_execute_on_thread().
///
/// On Darwin, if PRIO_DARWIN_BG is set on the calling thread, it will be
/// propagated to the new thread as well.

View File

@ -55,6 +55,36 @@ class Twine;
/// false otherwise.
bool llvm_is_multithreaded();
/// Execute the given \p UserFn on a separate thread, passing it the provided \p
/// UserData and waits for thread completion.
///
/// This function does not guarantee that the code will actually be executed
/// on a separate thread or honoring the requested stack size, but tries to do
/// so where system support is available.
///
/// \param UserFn - The callback to execute.
/// \param UserData - An argument to pass to the callback function.
/// \param StackSizeInBytes - A requested size (in bytes) for the thread stack
/// (or None for default)
void llvm_execute_on_thread(
void (*UserFn)(void *), void *UserData,
llvm::Optional<unsigned> StackSizeInBytes = llvm::None);
/// Schedule the given \p Func for execution on a separate thread, then return
/// to the caller immediately. Roughly equivalent to
/// `std::thread(Func).detach()`, except it allows requesting a specific stack
/// size, if supported for the platform.
///
/// This function would report a fatal error if it can't execute the code
/// on a separate thread.
///
/// \param Func - The callback to execute.
/// \param StackSizeInBytes - A requested size (in bytes) for the thread stack
/// (or None for default)
void llvm_execute_on_thread_async(
llvm::unique_function<void()> Func,
llvm::Optional<unsigned> StackSizeInBytes = llvm::None);
#if LLVM_THREADING_USE_STD_CALL_ONCE
typedef std::once_flag once_flag;

View File

@ -16,215 +16,16 @@
#ifndef LLVM_SUPPORT_THREAD_H
#define LLVM_SUPPORT_THREAD_H
#include "llvm/ADT/Optional.h"
#include "llvm/Config/llvm-config.h"
#ifdef _WIN32
typedef unsigned long DWORD;
typedef void *PVOID;
typedef PVOID HANDLE;
#endif
#if LLVM_ENABLE_THREADS
#include <thread>
namespace llvm {
#if LLVM_ON_UNIX || _WIN32
/// LLVM thread following std::thread interface with added constructor to
/// specify stack size.
class thread {
template <typename FPtr, typename... Args, size_t... Indices>
static void Apply(std::tuple<FPtr, Args...> &Callee,
std::index_sequence<Indices...>) {
std::move(std::get<0>(Callee))(std::move(std::get<Indices + 1>(Callee))...);
}
template <typename CalleeTuple> static void GenericThreadProxy(void *Ptr) {
std::unique_ptr<CalleeTuple> Callee(static_cast<CalleeTuple *>(Ptr));
// FIXME: use std::apply when C++17 is allowed.
std::make_index_sequence<std::tuple_size<CalleeTuple>() - 1> Indices{};
Apply(*Callee.get(), Indices);
}
public:
#if LLVM_ON_UNIX
using native_handle_type = pthread_t;
using id = pthread_t;
using start_routine_type = void *(*)(void *);
template <typename CalleeTuple> static void *ThreadProxy(void *Ptr) {
GenericThreadProxy<CalleeTuple>(Ptr);
return nullptr;
}
#elif _WIN32
using native_handle_type = HANDLE;
using id = DWORD;
using start_routine_type = unsigned(__stdcall *)(void *);
template <typename CalleeTuple>
static unsigned __stdcall ThreadProxy(void *Ptr) {
GenericThreadProxy<CalleeTuple>(Ptr);
return 0;
}
#endif
#if defined(__APPLE__)
// Darwin's default stack size for threads except the main one is only 512KB,
// which is not enough for some/many normal LLVM compilations. This implements
// the same interface as std::thread but requests the same stack size as the
// main thread (8MB) before creation.
static const constexpr llvm::Optional<unsigned> DefaultStackSize =
8 * 1024 * 1024;
#else
static const constexpr llvm::Optional<unsigned> DefaultStackSize = None;
#endif
thread() : Thread(native_handle_type()) {}
thread(thread &&Other) noexcept
: Thread(std::exchange(Other.Thread, native_handle_type())) {}
template <class Function, class... Args>
explicit thread(Function &&f, Args &&...args)
: thread(DefaultStackSize, f, args...) {}
template <class Function, class... Args>
explicit thread(llvm::Optional<unsigned> StackSizeInBytes, Function &&f,
Args &&...args);
thread(const thread &) = delete;
~thread() {
if (joinable())
std::terminate();
}
thread &operator=(thread &&Other) noexcept {
if (joinable())
std::terminate();
Thread = std::exchange(Other.Thread, native_handle_type());
return *this;
}
bool joinable() const noexcept { return Thread != native_handle_type(); }
inline id get_id() const noexcept;
native_handle_type native_handle() const noexcept { return Thread; }
static unsigned hardware_concurrency() {
return std::thread::hardware_concurrency();
};
inline void join();
inline void detach();
void swap(llvm::thread &Other) noexcept { std::swap(Thread, Other.Thread); }
private:
native_handle_type Thread;
};
thread::native_handle_type
llvm_execute_on_thread_impl(thread::start_routine_type ThreadFunc, void *Arg,
llvm::Optional<unsigned> StackSizeInBytes);
void llvm_thread_join_impl(thread::native_handle_type Thread);
void llvm_thread_detach_impl(thread::native_handle_type Thread);
thread::id llvm_thread_get_id_impl(thread::native_handle_type Thread);
thread::id llvm_thread_get_current_id_impl();
template <class Function, class... Args>
thread::thread(llvm::Optional<unsigned> StackSizeInBytes, Function &&f,
Args &&...args) {
typedef std::tuple<typename std::decay<Function>::type,
typename std::decay<Args>::type...>
CalleeTuple;
std::unique_ptr<CalleeTuple> Callee(
new CalleeTuple(std::forward<Function>(f), std::forward<Args>(args)...));
Thread = llvm_execute_on_thread_impl(ThreadProxy<CalleeTuple>, Callee.get(),
StackSizeInBytes);
if (Thread != native_handle_type())
Callee.release();
typedef std::thread thread;
}
thread::id thread::get_id() const noexcept {
return llvm_thread_get_id_impl(Thread);
}
void thread::join() {
llvm_thread_join_impl(Thread);
Thread = native_handle_type();
}
void thread::detach() {
llvm_thread_detach_impl(Thread);
Thread = native_handle_type();
}
namespace this_thread {
inline thread::id get_id() { return llvm_thread_get_current_id_impl(); }
} // namespace this_thread
#else // !LLVM_ON_UNIX && !_WIN32
/// std::thread backed implementation of llvm::thread interface that ignores the
/// stack size request.
class thread {
public:
using native_handle_type = std::thread::native_handle_type;
using id = std::thread::id;
thread() : Thread(std::thread()) {}
thread(thread &&Other) noexcept
: Thread(std::exchange(Other.Thread, std::thread())) {}
template <class Function, class... Args>
explicit thread(llvm::Optional<unsigned> StackSizeInBytes, Function &&f,
Args &&...args)
: Thread(std::forward<Function>(f), std::forward<Args>(args)...) {}
template <class Function, class... Args>
explicit thread(Function &&f, Args &&...args) : Thread(f, args...) {}
thread(const thread &) = delete;
~thread() {}
thread &operator=(thread &&Other) noexcept {
Thread = std::exchange(Other.Thread, std::thread());
return *this;
}
bool joinable() const noexcept { return Thread.joinable(); }
id get_id() const noexcept { return Thread.get_id(); }
native_handle_type native_handle() noexcept { return Thread.native_handle(); }
static unsigned hardware_concurrency() {
return std::thread::hardware_concurrency();
};
inline void join() { Thread.join(); }
inline void detach() { Thread.detach(); }
void swap(llvm::thread &Other) noexcept { std::swap(Thread, Other.Thread); }
private:
std::thread Thread;
};
namespace this_thread {
inline thread::id get_id() { return std::this_thread::get_id(); }
}
#endif // LLVM_ON_UNIX || _WIN32
} // namespace llvm
#else // !LLVM_ENABLE_THREADS
#include <utility>
@ -235,26 +36,17 @@ struct thread {
thread() {}
thread(thread &&other) {}
template <class Function, class... Args>
explicit thread(llvm::Optional<unsigned> StackSizeInBytes, Function &&f,
Args &&...args) {
f(std::forward<Args>(args)...);
}
template <class Function, class... Args>
explicit thread(Function &&f, Args &&...args) {
explicit thread(Function &&f, Args &&... args) {
f(std::forward<Args>(args)...);
}
thread(const thread &) = delete;
void detach() {
report_fatal_error("Detaching from a thread does not make sense with no "
"threading support");
}
void join() {}
static unsigned hardware_concurrency() { return 1; };
};
} // namespace llvm
}
#endif // LLVM_ENABLE_THREADS
#endif // LLVM_SUPPORT_THREAD_H
#endif

View File

@ -13,7 +13,6 @@
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/ThreadLocal.h"
#include "llvm/Support/thread.h"
#include <mutex>
#include <setjmp.h>
@ -501,12 +500,10 @@ bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn,
unsigned RequestedStackSize) {
bool UseBackgroundPriority = hasThreadBackgroundPriority();
RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false };
llvm::thread Thread(RequestedStackSize == 0
? llvm::None
: llvm::Optional<unsigned>(RequestedStackSize),
RunSafelyOnThread_Dispatch, &Info);
Thread.join();
llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info,
RequestedStackSize == 0
? llvm::None
: llvm::Optional<unsigned>(RequestedStackSize));
if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
CRC->setSwitchedThread();
return Info.Result;

View File

@ -73,8 +73,8 @@ void ThreadPool::wait() {
}
bool ThreadPool::isWorkerThread() const {
llvm::thread::id CurrentThreadId = llvm::this_thread::get_id();
for (const llvm::thread &Thread : Threads)
std::thread::id CurrentThreadId = std::this_thread::get_id();
for (const std::thread &Thread : Threads)
if (CurrentThreadId == Thread.get_id())
return true;
return false;

View File

@ -15,7 +15,6 @@
#include "llvm/ADT/Optional.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/thread.h"
#include <cassert>
#include <errno.h>
@ -39,6 +38,13 @@ bool llvm::llvm_is_multithreaded() {
#if LLVM_ENABLE_THREADS == 0 || \
(!defined(_WIN32) && !defined(HAVE_PTHREAD_H))
// Support for non-Win32, non-pthread implementation.
void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData,
llvm::Optional<unsigned> StackSizeInBytes) {
(void)StackSizeInBytes;
Fn(UserData);
}
uint64_t llvm::get_threadid() { return 0; }
uint32_t llvm::get_max_thread_name_length() { return 0; }
@ -54,6 +60,25 @@ unsigned llvm::ThreadPoolStrategy::compute_thread_count() const {
return 1;
}
#if LLVM_ENABLE_THREADS == 0
void llvm::llvm_execute_on_thread_async(
llvm::unique_function<void()> Func,
llvm::Optional<unsigned> StackSizeInBytes) {
(void)Func;
(void)StackSizeInBytes;
report_fatal_error("Spawning a detached thread doesn't make sense with no "
"threading support");
}
#else
// Support for non-Win32, non-pthread implementation.
void llvm::llvm_execute_on_thread_async(
llvm::unique_function<void()> Func,
llvm::Optional<unsigned> StackSizeInBytes) {
(void)StackSizeInBytes;
std::thread(std::move(Func)).detach();
}
#endif
#else
int computeHostNumHardwareThreads();
@ -70,6 +95,17 @@ unsigned llvm::ThreadPoolStrategy::compute_thread_count() const {
return std::min((unsigned)MaxThreadCount, ThreadsRequested);
}
namespace {
struct SyncThreadInfo {
void (*UserFn)(void *);
void *UserData;
};
using AsyncThreadInfo = llvm::unique_function<void()>;
enum class JoiningPolicy { Join, Detach };
} // namespace
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Threading.inc"
@ -78,6 +114,22 @@ unsigned llvm::ThreadPoolStrategy::compute_thread_count() const {
#include "Windows/Threading.inc"
#endif
void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData,
llvm::Optional<unsigned> StackSizeInBytes) {
SyncThreadInfo Info = {Fn, UserData};
llvm_execute_on_thread_impl(threadFuncSync, &Info, StackSizeInBytes,
JoiningPolicy::Join);
}
void llvm::llvm_execute_on_thread_async(
llvm::unique_function<void()> Func,
llvm::Optional<unsigned> StackSizeInBytes) {
llvm_execute_on_thread_impl(&threadFuncAsync,
new AsyncThreadInfo(std::move(Func)),
StackSizeInBytes, JoiningPolicy::Detach);
}
#endif
Optional<ThreadPoolStrategy>

View File

@ -48,9 +48,22 @@
#include <unistd.h> // For syscall()
#endif
pthread_t
llvm::llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
llvm::Optional<unsigned> StackSizeInBytes) {
static void *threadFuncSync(void *Arg) {
SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg);
TI->UserFn(TI->UserData);
return nullptr;
}
static void *threadFuncAsync(void *Arg) {
std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg));
(*Info)();
return nullptr;
}
static void
llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
llvm::Optional<unsigned> StackSizeInBytes,
JoiningPolicy JP) {
int errnum;
// Construct the attributes object.
@ -77,33 +90,18 @@ llvm::llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0)
ReportErrnumFatal("pthread_create failed", errnum);
return Thread;
}
void llvm::llvm_thread_detach_impl(pthread_t Thread) {
int errnum;
if ((errnum = ::pthread_detach(Thread)) != 0) {
ReportErrnumFatal("pthread_detach failed", errnum);
if (JP == JoiningPolicy::Join) {
// Wait for the thread
if ((errnum = ::pthread_join(Thread, nullptr)) != 0) {
ReportErrnumFatal("pthread_join failed", errnum);
}
} else if (JP == JoiningPolicy::Detach) {
if ((errnum = ::pthread_detach(Thread)) != 0) {
ReportErrnumFatal("pthread_detach failed", errnum);
}
}
}
void llvm::llvm_thread_join_impl(pthread_t Thread) {
int errnum;
if ((errnum = ::pthread_join(Thread, nullptr)) != 0) {
ReportErrnumFatal("pthread_join failed", errnum);
}
}
pthread_t llvm::llvm_thread_get_id_impl(pthread_t Thread) {
return Thread;
}
pthread_t llvm::llvm_thread_get_current_id_impl() {
return ::pthread_self();
}
uint64_t llvm::get_threadid() {
#if defined(__APPLE__)
// Calling "mach_thread_self()" bumps the reference count on the thread

View File

@ -23,10 +23,22 @@
#undef MemoryFence
#endif
HANDLE
llvm::llvm_execute_on_thread_impl(unsigned(__stdcall *ThreadFunc)(void *),
void *Arg,
llvm::Optional<unsigned> StackSizeInBytes) {
static unsigned __stdcall threadFuncSync(void *Arg) {
SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg);
TI->UserFn(TI->UserData);
return 0;
}
static unsigned __stdcall threadFuncAsync(void *Arg) {
std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg));
(*Info)();
return 0;
}
static void
llvm_execute_on_thread_impl(unsigned (__stdcall *ThreadFunc)(void *), void *Arg,
llvm::Optional<unsigned> StackSizeInBytes,
JoiningPolicy JP) {
HANDLE hThread = (HANDLE)::_beginthreadex(
NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL);
@ -34,29 +46,16 @@ llvm::llvm_execute_on_thread_impl(unsigned(__stdcall *ThreadFunc)(void *),
ReportLastErrorFatal("_beginthreadex failed");
}
return hThread;
}
void llvm::llvm_thread_join_impl(HANDLE hThread) {
if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) {
ReportLastErrorFatal("WaitForSingleObject failed");
if (JP == JoiningPolicy::Join) {
if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) {
ReportLastErrorFatal("WaitForSingleObject failed");
}
}
}
void llvm::llvm_thread_detach_impl(HANDLE hThread) {
if (::CloseHandle(hThread) == FALSE) {
ReportLastErrorFatal("CloseHandle failed");
}
}
DWORD llvm::llvm_thread_get_id_impl(HANDLE hThread) {
return ::GetThreadId(hThread);
}
DWORD llvm::llvm_thread_get_current_id_impl() {
return ::GetCurrentThreadId();
}
uint64_t llvm::get_threadid() {
return uint64_t(::GetCurrentThreadId());
}

View File

@ -63,8 +63,7 @@ TEST(Threading, RunOnThreadSyncAsync) {
ThreadFinished.notify();
};
llvm::thread Thread(ThreadFunc);
Thread.detach();
llvm::llvm_execute_on_thread_async(ThreadFunc);
ASSERT_TRUE(ThreadStarted.wait());
ThreadAdvanced.notify();
ASSERT_TRUE(ThreadFinished.wait());
@ -72,23 +71,11 @@ TEST(Threading, RunOnThreadSyncAsync) {
TEST(Threading, RunOnThreadSync) {
std::atomic_bool Executed(false);
llvm::thread Thread(
llvm::llvm_execute_on_thread(
[](void *Arg) { *static_cast<std::atomic_bool *>(Arg) = true; },
&Executed);
Thread.join();
ASSERT_EQ(Executed, true);
}
#if defined(__APPLE__)
TEST(Threading, AppleStackSize) {
llvm::thread Thread([] {
volatile unsigned char Var[8 * 1024 * 1024 - 1024];
Var[0] = 0xff;
ASSERT_EQ(Var[0], 0xff);
});
Thread.join();
}
#endif
#endif
} // end anon namespace