mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
Support: add llvm::thread class that supports specifying stack size.
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.
This commit is contained in:
parent
4bda00e90e
commit
43bfac999c
@ -87,7 +87,7 @@ public:
|
|||||||
/// a protected context which is run in another thread (optionally with a
|
/// a protected context which is run in another thread (optionally with a
|
||||||
/// requested stack size).
|
/// requested stack size).
|
||||||
///
|
///
|
||||||
/// See RunSafely() and llvm_execute_on_thread().
|
/// See RunSafely().
|
||||||
///
|
///
|
||||||
/// On Darwin, if PRIO_DARWIN_BG is set on the calling thread, it will be
|
/// On Darwin, if PRIO_DARWIN_BG is set on the calling thread, it will be
|
||||||
/// propagated to the new thread as well.
|
/// propagated to the new thread as well.
|
||||||
|
@ -55,36 +55,6 @@ class Twine;
|
|||||||
/// false otherwise.
|
/// false otherwise.
|
||||||
bool llvm_is_multithreaded();
|
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
|
#if LLVM_THREADING_USE_STD_CALL_ONCE
|
||||||
|
|
||||||
typedef std::once_flag once_flag;
|
typedef std::once_flag once_flag;
|
||||||
|
@ -16,16 +16,215 @@
|
|||||||
#ifndef LLVM_SUPPORT_THREAD_H
|
#ifndef LLVM_SUPPORT_THREAD_H
|
||||||
#define LLVM_SUPPORT_THREAD_H
|
#define LLVM_SUPPORT_THREAD_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/Optional.h"
|
||||||
#include "llvm/Config/llvm-config.h"
|
#include "llvm/Config/llvm-config.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef unsigned long DWORD;
|
||||||
|
typedef void *PVOID;
|
||||||
|
typedef PVOID HANDLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LLVM_ENABLE_THREADS
|
#if LLVM_ENABLE_THREADS
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
typedef std::thread thread;
|
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
#else // !LLVM_ENABLE_THREADS
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -36,17 +235,26 @@ struct thread {
|
|||||||
thread() {}
|
thread() {}
|
||||||
thread(thread &&other) {}
|
thread(thread &&other) {}
|
||||||
template <class Function, class... Args>
|
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)...);
|
f(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
thread(const thread &) = delete;
|
thread(const thread &) = delete;
|
||||||
|
|
||||||
|
void detach() {
|
||||||
|
report_fatal_error("Detaching from a thread does not make sense with no "
|
||||||
|
"threading support");
|
||||||
|
}
|
||||||
void join() {}
|
void join() {}
|
||||||
static unsigned hardware_concurrency() { return 1; };
|
static unsigned hardware_concurrency() { return 1; };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace llvm
|
||||||
|
|
||||||
#endif // LLVM_ENABLE_THREADS
|
#endif // LLVM_ENABLE_THREADS
|
||||||
|
|
||||||
#endif
|
#endif // LLVM_SUPPORT_THREAD_H
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "llvm/Support/ManagedStatic.h"
|
#include "llvm/Support/ManagedStatic.h"
|
||||||
#include "llvm/Support/Signals.h"
|
#include "llvm/Support/Signals.h"
|
||||||
#include "llvm/Support/ThreadLocal.h"
|
#include "llvm/Support/ThreadLocal.h"
|
||||||
|
#include "llvm/Support/thread.h"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
@ -500,10 +501,12 @@ bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn,
|
|||||||
unsigned RequestedStackSize) {
|
unsigned RequestedStackSize) {
|
||||||
bool UseBackgroundPriority = hasThreadBackgroundPriority();
|
bool UseBackgroundPriority = hasThreadBackgroundPriority();
|
||||||
RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false };
|
RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false };
|
||||||
llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info,
|
llvm::thread Thread(RequestedStackSize == 0
|
||||||
RequestedStackSize == 0
|
|
||||||
? llvm::None
|
? llvm::None
|
||||||
: llvm::Optional<unsigned>(RequestedStackSize));
|
: llvm::Optional<unsigned>(RequestedStackSize),
|
||||||
|
RunSafelyOnThread_Dispatch, &Info);
|
||||||
|
Thread.join();
|
||||||
|
|
||||||
if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
|
if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
|
||||||
CRC->setSwitchedThread();
|
CRC->setSwitchedThread();
|
||||||
return Info.Result;
|
return Info.Result;
|
||||||
|
@ -73,8 +73,8 @@ void ThreadPool::wait() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadPool::isWorkerThread() const {
|
bool ThreadPool::isWorkerThread() const {
|
||||||
std::thread::id CurrentThreadId = std::this_thread::get_id();
|
llvm::thread::id CurrentThreadId = llvm::this_thread::get_id();
|
||||||
for (const std::thread &Thread : Threads)
|
for (const llvm::thread &Thread : Threads)
|
||||||
if (CurrentThreadId == Thread.get_id())
|
if (CurrentThreadId == Thread.get_id())
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "llvm/ADT/Optional.h"
|
#include "llvm/ADT/Optional.h"
|
||||||
#include "llvm/Config/config.h"
|
#include "llvm/Config/config.h"
|
||||||
#include "llvm/Support/Host.h"
|
#include "llvm/Support/Host.h"
|
||||||
|
#include "llvm/Support/thread.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -38,13 +39,6 @@ bool llvm::llvm_is_multithreaded() {
|
|||||||
|
|
||||||
#if LLVM_ENABLE_THREADS == 0 || \
|
#if LLVM_ENABLE_THREADS == 0 || \
|
||||||
(!defined(_WIN32) && !defined(HAVE_PTHREAD_H))
|
(!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; }
|
uint64_t llvm::get_threadid() { return 0; }
|
||||||
|
|
||||||
uint32_t llvm::get_max_thread_name_length() { return 0; }
|
uint32_t llvm::get_max_thread_name_length() { return 0; }
|
||||||
@ -60,25 +54,6 @@ unsigned llvm::ThreadPoolStrategy::compute_thread_count() const {
|
|||||||
return 1;
|
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
|
#else
|
||||||
|
|
||||||
int computeHostNumHardwareThreads();
|
int computeHostNumHardwareThreads();
|
||||||
@ -95,17 +70,6 @@ unsigned llvm::ThreadPoolStrategy::compute_thread_count() const {
|
|||||||
return std::min((unsigned)MaxThreadCount, ThreadsRequested);
|
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.
|
// Include the platform-specific parts of this class.
|
||||||
#ifdef LLVM_ON_UNIX
|
#ifdef LLVM_ON_UNIX
|
||||||
#include "Unix/Threading.inc"
|
#include "Unix/Threading.inc"
|
||||||
@ -114,22 +78,6 @@ enum class JoiningPolicy { Join, Detach };
|
|||||||
#include "Windows/Threading.inc"
|
#include "Windows/Threading.inc"
|
||||||
#endif
|
#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
|
#endif
|
||||||
|
|
||||||
Optional<ThreadPoolStrategy>
|
Optional<ThreadPoolStrategy>
|
||||||
|
@ -48,22 +48,9 @@
|
|||||||
#include <unistd.h> // For syscall()
|
#include <unistd.h> // For syscall()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void *threadFuncSync(void *Arg) {
|
pthread_t
|
||||||
SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg);
|
llvm::llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
|
||||||
TI->UserFn(TI->UserData);
|
llvm::Optional<unsigned> StackSizeInBytes) {
|
||||||
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;
|
int errnum;
|
||||||
|
|
||||||
// Construct the attributes object.
|
// Construct the attributes object.
|
||||||
@ -90,16 +77,31 @@ llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
|
|||||||
if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0)
|
if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0)
|
||||||
ReportErrnumFatal("pthread_create failed", errnum);
|
ReportErrnumFatal("pthread_create failed", errnum);
|
||||||
|
|
||||||
if (JP == JoiningPolicy::Join) {
|
return Thread;
|
||||||
// Wait for the thread
|
|
||||||
if ((errnum = ::pthread_join(Thread, nullptr)) != 0) {
|
|
||||||
ReportErrnumFatal("pthread_join failed", errnum);
|
|
||||||
}
|
}
|
||||||
} else if (JP == JoiningPolicy::Detach) {
|
|
||||||
|
void llvm::llvm_thread_detach_impl(pthread_t Thread) {
|
||||||
|
int errnum;
|
||||||
|
|
||||||
if ((errnum = ::pthread_detach(Thread)) != 0) {
|
if ((errnum = ::pthread_detach(Thread)) != 0) {
|
||||||
ReportErrnumFatal("pthread_detach failed", errnum);
|
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() {
|
uint64_t llvm::get_threadid() {
|
||||||
|
@ -23,22 +23,10 @@
|
|||||||
#undef MemoryFence
|
#undef MemoryFence
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static unsigned __stdcall threadFuncSync(void *Arg) {
|
HANDLE
|
||||||
SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg);
|
llvm::llvm_execute_on_thread_impl(unsigned(__stdcall *ThreadFunc)(void *),
|
||||||
TI->UserFn(TI->UserData);
|
void *Arg,
|
||||||
return 0;
|
llvm::Optional<unsigned> StackSizeInBytes) {
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
HANDLE hThread = (HANDLE)::_beginthreadex(
|
||||||
NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL);
|
NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL);
|
||||||
|
|
||||||
@ -46,16 +34,29 @@ llvm_execute_on_thread_impl(unsigned (__stdcall *ThreadFunc)(void *), void *Arg,
|
|||||||
ReportLastErrorFatal("_beginthreadex failed");
|
ReportLastErrorFatal("_beginthreadex failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JP == JoiningPolicy::Join) {
|
return hThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void llvm::llvm_thread_join_impl(HANDLE hThread) {
|
||||||
if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) {
|
if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) {
|
||||||
ReportLastErrorFatal("WaitForSingleObject failed");
|
ReportLastErrorFatal("WaitForSingleObject failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void llvm::llvm_thread_detach_impl(HANDLE hThread) {
|
||||||
if (::CloseHandle(hThread) == FALSE) {
|
if (::CloseHandle(hThread) == FALSE) {
|
||||||
ReportLastErrorFatal("CloseHandle failed");
|
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() {
|
uint64_t llvm::get_threadid() {
|
||||||
return uint64_t(::GetCurrentThreadId());
|
return uint64_t(::GetCurrentThreadId());
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,8 @@ TEST(Threading, RunOnThreadSyncAsync) {
|
|||||||
ThreadFinished.notify();
|
ThreadFinished.notify();
|
||||||
};
|
};
|
||||||
|
|
||||||
llvm::llvm_execute_on_thread_async(ThreadFunc);
|
llvm::thread Thread(ThreadFunc);
|
||||||
|
Thread.detach();
|
||||||
ASSERT_TRUE(ThreadStarted.wait());
|
ASSERT_TRUE(ThreadStarted.wait());
|
||||||
ThreadAdvanced.notify();
|
ThreadAdvanced.notify();
|
||||||
ASSERT_TRUE(ThreadFinished.wait());
|
ASSERT_TRUE(ThreadFinished.wait());
|
||||||
@ -71,11 +72,23 @@ TEST(Threading, RunOnThreadSyncAsync) {
|
|||||||
|
|
||||||
TEST(Threading, RunOnThreadSync) {
|
TEST(Threading, RunOnThreadSync) {
|
||||||
std::atomic_bool Executed(false);
|
std::atomic_bool Executed(false);
|
||||||
llvm::llvm_execute_on_thread(
|
llvm::thread Thread(
|
||||||
[](void *Arg) { *static_cast<std::atomic_bool *>(Arg) = true; },
|
[](void *Arg) { *static_cast<std::atomic_bool *>(Arg) = true; },
|
||||||
&Executed);
|
&Executed);
|
||||||
|
Thread.join();
|
||||||
ASSERT_EQ(Executed, true);
|
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
|
#endif
|
||||||
|
|
||||||
} // end anon namespace
|
} // end anon namespace
|
||||||
|
Loading…
Reference in New Issue
Block a user