2015-08-27 23:52:31 +02:00
|
|
|
//===-- llvm/Support/thread.h - Wrapper for <thread> ------------*- 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
|
2015-08-27 23:52:31 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This header is a wrapper for <thread> that works around problems with the
|
2015-08-31 02:09:01 +02:00
|
|
|
// 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.
|
2015-08-27 23:52:31 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_SUPPORT_THREAD_H
|
|
|
|
#define LLVM_SUPPORT_THREAD_H
|
|
|
|
|
2021-05-26 12:25:11 +02:00
|
|
|
#include "llvm/ADT/Optional.h"
|
2015-08-31 02:09:01 +02:00
|
|
|
#include "llvm/Config/llvm-config.h"
|
|
|
|
|
2021-05-26 12:25:11 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
typedef unsigned long DWORD;
|
|
|
|
typedef void *PVOID;
|
|
|
|
typedef PVOID HANDLE;
|
|
|
|
#endif
|
|
|
|
|
2015-08-31 02:09:01 +02:00
|
|
|
#if LLVM_ENABLE_THREADS
|
|
|
|
|
2015-08-27 23:52:31 +02:00
|
|
|
#include <thread>
|
|
|
|
|
2015-08-31 02:09:01 +02:00
|
|
|
namespace llvm {
|
2021-05-26 12:25:11 +02:00
|
|
|
|
|
|
|
#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();
|
2015-08-31 02:09:01 +02:00
|
|
|
}
|
|
|
|
|
2021-05-26 12:25:11 +02:00
|
|
|
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
|
|
|
|
|
2015-08-31 02:09:01 +02:00
|
|
|
#else // !LLVM_ENABLE_THREADS
|
|
|
|
|
2015-12-15 01:59:19 +01:00
|
|
|
#include <utility>
|
|
|
|
|
2015-08-31 02:09:01 +02:00
|
|
|
namespace llvm {
|
|
|
|
|
|
|
|
struct thread {
|
|
|
|
thread() {}
|
|
|
|
thread(thread &&other) {}
|
|
|
|
template <class Function, class... Args>
|
2021-05-26 12:25:11 +02:00
|
|
|
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) {
|
2015-08-31 02:09:01 +02:00
|
|
|
f(std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
thread(const thread &) = delete;
|
|
|
|
|
2021-05-26 12:25:11 +02:00
|
|
|
void detach() {
|
|
|
|
report_fatal_error("Detaching from a thread does not make sense with no "
|
|
|
|
"threading support");
|
|
|
|
}
|
2015-08-31 02:09:01 +02:00
|
|
|
void join() {}
|
2016-03-04 01:25:54 +01:00
|
|
|
static unsigned hardware_concurrency() { return 1; };
|
2015-08-31 02:09:01 +02:00
|
|
|
};
|
|
|
|
|
2021-05-26 12:25:11 +02:00
|
|
|
} // namespace llvm
|
2015-08-31 02:09:01 +02:00
|
|
|
|
|
|
|
#endif // LLVM_ENABLE_THREADS
|
|
|
|
|
2021-05-26 12:25:11 +02:00
|
|
|
#endif // LLVM_SUPPORT_THREAD_H
|