File pthread.cpp

File List > modules > system > pthread.cpp

Go to the documentation of this file.

#include <coroutine/pthread.h>

namespace coro {
using namespace std;

void* continue_on_pthread::on_pthread(void* ptr) noexcept(false) {
    // assume we will receive an address of the coroutine frame
    auto task = coroutine_handle<void>::from_address(ptr);
    if (task.done() == false)
        task.resume();

    return task.address(); // coroutine_handle<void>::address();
}

uint32_t
continue_on_pthread::spawn(pthread_t& tid, const pthread_attr_t* attr,
                           coroutine_handle<void> coro) noexcept(false) {
    return ::pthread_create(&tid, attr, on_pthread, coro.address());
}

pthread_joiner::pthread_joiner(promise_type* p) noexcept(false) : promise{p} {
    if (p == nullptr)
        throw invalid_argument{"nullptr for promise_type*"};
}

pthread_joiner::~pthread_joiner() noexcept(false) {
    pthread_t tid = *this;
    if (tid == pthread_t{}) // spawned no threads. nothing to do
        return;

    void* ptr{};
    // we must acquire `tid` before the destruction
    if (auto ec = pthread_join(tid, &ptr)) {
        throw system_error{ec, system_category(), "pthread_join"};
    }
    if (auto frame = coroutine_handle<void>::from_address(ptr)) {
        frame.destroy();
    }
}

pthread_detacher::pthread_detacher(promise_type* p) noexcept(false)
    : promise{p} {
    if (p == nullptr)
        throw invalid_argument{"nullptr for promise_type*"};
}

pthread_detacher::~pthread_detacher() noexcept(false) {
    pthread_t tid = *this;
    if (tid == pthread_t{}) // spawned no threads. nothing to do
        return;

    if (auto ec = pthread_detach(tid)) {
        throw system_error{ec, system_category(), "pthread_join"};
    }
}

} // namespace coro