mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
7c89253a7a
This adds a new llvm::thread class with the same interface as std::thread except there is an extra constructor that allows us to set the new thread's stack size. On Darwin even the default size is boosted to 8MB to match the main thread. It also switches all users of the older C-style `llvm_execute_on_thread` API family over to `llvm::thread` followed by either a `detach` or `join` call and removes the old API. Moved definition of DefaultStackSize into the .cpp file to hopefully fix the build on some (GCC-6?) machines.
252 lines
7.2 KiB
C++
252 lines
7.2 KiB
C++
//===-- llvm/Support/thread.h - Wrapper for <thread> ------------*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This header is a wrapper for <thread> that works around problems with the
|
|
// MSVC headers when exceptions are disabled. It also provides llvm::thread,
|
|
// which is either a typedef of std::thread or a replacement that calls the
|
|
// function synchronously depending on the value of LLVM_ENABLE_THREADS.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#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
|
|
|
|
static const llvm::Optional<unsigned> DefaultStackSize;
|
|
|
|
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();
|
|
}
|
|
|
|
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>
|
|
|
|
namespace llvm {
|
|
|
|
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) {
|
|
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
|