9#include <cosmos/error/ApiError.hxx> 
   10#include <cosmos/error/UsageError.hxx> 
   11#include <cosmos/formatting.hxx> 
   12#include <cosmos/private/cosmos.hxx> 
   13#include <cosmos/thread/PosixThread.hxx> 
   15using namespace cosmos::pthread;
 
   21        std::atomic<size_t> num_threads = 0;
 
   24                std::variant<PosixThread::PosixEntry, PosixThread::Entry> entry;
 
   28        Context fetch_context(
void *par) {
 
   29                auto ctx = 
reinterpret_cast<Context*
>(par);
 
   35        void* thread_entry(
void *par) {
 
   37                Context ctx = fetch_context(par);
 
   39                if (std::holds_alternative<PosixThread::PosixEntry>(ctx.entry)) {
 
   40                        auto entry = std::get<PosixThread::PosixEntry>(ctx.entry);
 
   41                        auto ret = entry(ctx.arg);
 
   42                        return reinterpret_cast<void*
>(ret);
 
   44                        auto entry = std::get<PosixThread::Entry>(ctx.entry);
 
   50        void create_thread(pthread_t &thread, Context *ctx) {
 
   52                const auto res = ::pthread_create(
 
   56                        reinterpret_cast<void*
>(ctx)
 
   59                if (
const auto error = 
Errno{res}; error != Errno::NO_ERROR) {
 
   67                m_name{buildName(name, ++num_threads)} {
 
   71                create_thread(
m_pthread.value(), 
new Context{entry, arg});
 
 
   78                m_name{buildName(name, ++num_threads)} {
 
   81                create_thread(
m_pthread.value(), 
new Context{entry, pthread::ThreadArg{0}});
 
 
   87PosixThread::PosixThread(
PosixThread &&other) 
noexcept {
 
   88        *
this = std::move(other);
 
   91PosixThread::~PosixThread() {
 
   93                fatal_error(sprintf(
"Thread %s destroyed but not joined!", name().c_str()));
 
   99                fatal_error(
"moving into not-yet-joined thread");
 
  101        m_name = other.m_name;
 
  102        m_pthread = *(other.m_pthread);
 
  104        other.m_pthread.reset();
 
  105        other.m_name.clear();
 
  109void PosixThread::assertJoinConditions() {
 
  111                cosmos_throw (
UsageError(
"Attempted to join non-joinable thread (empty or detached)"));
 
  112        } 
else if (isCallerThread()) {
 
  113                cosmos_throw (
UsageError(
"Attempted to join self"));
 
  117void PosixThread::reset() {
 
  126        assertJoinConditions();
 
  129        const auto join_res = ::pthread_join(*m_pthread, &res);
 
  131        if (
const auto error = 
Errno{join_res}; error != Errno::NO_ERROR) {
 
  132                cosmos_throw (
ApiError(
"pthread_join()", error));
 
 
  140std::optional<pthread::ExitValue> PosixThread::tryJoin() {
 
  141        assertJoinConditions();
 
  144        const auto join_res = ::pthread_tryjoin_np(*m_pthread, &res);
 
  146        if (
const auto error = 
Errno{join_res}; error != Errno::NO_ERROR) {
 
  147                if (error == Errno::BUSY) {
 
  152                cosmos_throw (
ApiError(
"pthread_tryjoin_np()", error));
 
 
  160std::optional<pthread::ExitValue> PosixThread::joinTimed(
const RealTime ts) {
 
  161        assertJoinConditions();
 
  164        const auto join_res = ::pthread_timedjoin_np(*m_pthread, &res, &ts);
 
  166        if (
const auto error = 
Errno{join_res}; error != Errno::NO_ERROR) {
 
  167                if (error == Errno::TIMEDOUT) {
 
  172                cosmos_throw (
ApiError(
"pthread_timedjoin_np()", error));
 
 
  180void PosixThread::detach() {
 
  184                cosmos_throw (
UsageError(
"Attempted to detach a non-joinable thread (empty or already detached)"));
 
  187        const auto res = ::pthread_detach(*m_pthread);
 
  189        if (
const auto error = 
Errno{res}; error != Errno::NO_ERROR) {
 
  190                cosmos_throw (
ApiError(
"pthread_detach()", error));
 
 
  196std::string PosixThread::buildName(
const std::string_view name, 
size_t nr)
 const {
 
  198                return std::string{name};
 
  199        return std::string{
"thread<" + std::to_string(nr) + 
">"};
 
Specialized exception type used when system APIs fail.
A class representing a basic POSIX thread.
std::optional< pthread_t > m_pthread
POSIX thread handle.
PosixThread() noexcept
Creates an empty thread object.
std::function< pthread::ExitValue(pthread::ThreadArg)> PosixEntry
POSIX style entry function with a single input parameter and return value.
std::function< void(void)> Entry
Entry function without parameters for use with member functions or lambdas.
A C++ wrapper around the POSIX struct timespec coupled to a specific CLOCK type.
Exception type for logical usage errors within the application.
Errno
Strong enum type representing errno error constants.
ExitValue
An integer or pointer return value from a pthread.
ThreadArg
An integer or pointer value supplied to a pthread's entry function.