Skip to content

Commit

Permalink
Stackless coroutines now can refer to themselves (through get_self() …
Browse files Browse the repository at this point in the history
…and friends)
  • Loading branch information
hkaiser committed Oct 25, 2019
1 parent 414380e commit 541f336
Show file tree
Hide file tree
Showing 9 changed files with 345 additions and 136 deletions.
Expand Up @@ -31,20 +31,9 @@
#define HPX_RUNTIME_THREADS_COROUTINES_DETAIL_COROUTINE_ACCESSOR_HPP

namespace hpx { namespace threads { namespace coroutines { namespace detail {

struct coroutine_accessor
{
template <typename Coroutine>
static void acquire(Coroutine& x)
{
x.acquire();
}

template <typename Coroutine>
static void release(Coroutine& x)
{
x.release();
}

template <typename Coroutine>
static typename Coroutine::impl_ptr get_impl(Coroutine& x)
{
Expand Down
129 changes: 48 additions & 81 deletions libs/coroutines/include/hpx/coroutines/detail/coroutine_self.hpp
Expand Up @@ -44,12 +44,13 @@
#include <utility>

namespace hpx { namespace threads { namespace coroutines { namespace detail {

class coroutine_self
{
public:
HPX_NON_COPYABLE(coroutine_self);

private:
protected:
// store the current this and write it to the TSS on exit
struct reset_self_on_exit
{
Expand All @@ -68,17 +69,18 @@ namespace hpx { namespace threads { namespace coroutines { namespace detail {
};

public:
friend struct detail::coroutine_accessor;
using thread_id_type = hpx::threads::thread_id;

typedef coroutine_impl impl_type;
typedef impl_type* impl_ptr; // Note, no reference counting here.
typedef impl_type::thread_id_type thread_id_type;
using result_type = std::pair<thread_state_enum, thread_id_type>;
using arg_type = thread_state_ex_enum;

typedef impl_type::result_type result_type;
typedef impl_type::arg_type arg_type;
using yield_decorator_type =
util::function_nonser<arg_type(result_type)>;

typedef util::function_nonser<arg_type(result_type)>
yield_decorator_type;
explicit coroutine_self(coroutine_self* next_self = nullptr)
: next_self_(next_self)
{
}

arg_type yield(result_type arg = result_type())
{
Expand All @@ -87,20 +89,6 @@ namespace hpx { namespace threads { namespace coroutines { namespace detail {
yield_impl(std::move(arg));
}

arg_type yield_impl(result_type arg)
{
HPX_ASSERT(m_pimpl);

this->m_pimpl->bind_result(arg);

{
reset_self_on_exit on_exit(this);
this->m_pimpl->yield();
}

return *m_pimpl->args();
}

template <typename F>
yield_decorator_type decorate_yield(F&& f)
{
Expand Down Expand Up @@ -129,67 +117,33 @@ namespace hpx { namespace threads { namespace coroutines { namespace detail {
return tmp;
}

thread_id_type get_thread_id() const
{
HPX_ASSERT(m_pimpl);
return m_pimpl->get_thread_id();
}
virtual ~coroutine_self() = default;

std::size_t get_thread_phase() const
{
#if defined(HPX_HAVE_THREAD_PHASE_INFORMATION)
HPX_ASSERT(m_pimpl);
return m_pimpl->get_thread_phase();
#else
return 0;
#endif
}
virtual arg_type yield_impl(result_type arg) = 0;

std::ptrdiff_t get_available_stack_space()
{
#if defined(HPX_HAVE_THREADS_GET_STACK_POINTER)
return m_pimpl->get_available_stack_space();
#else
return (std::numeric_limits<std::ptrdiff_t>::max)();
#endif
}
virtual thread_id_type get_thread_id() const = 0;

explicit coroutine_self(
impl_type* pimpl, coroutine_self* next_self = nullptr)
: m_pimpl(pimpl)
, next_self_(next_self)
{
}
virtual std::size_t get_thread_phase() const = 0;

std::size_t get_thread_data() const
{
HPX_ASSERT(m_pimpl);
return m_pimpl->get_thread_data();
}
std::size_t set_thread_data(std::size_t data)
{
HPX_ASSERT(m_pimpl);
return m_pimpl->set_thread_data(data);
}
virtual std::ptrdiff_t get_available_stack_space() = 0;

#if defined(HPX_HAVE_THREAD_LOCAL_STORAGE)
tss_storage* get_thread_tss_data()
{
HPX_ASSERT(m_pimpl);
return m_pimpl->get_thread_tss_data(false);
}
virtual std::size_t get_thread_data() const = 0;
virtual std::size_t set_thread_data(std::size_t data) = 0;

tss_storage* get_or_create_thread_tss_data()
{
HPX_ASSERT(m_pimpl);
return m_pimpl->get_thread_tss_data(true);
}
#endif
virtual tss_storage* get_thread_tss_data() = 0;
virtual tss_storage* get_or_create_thread_tss_data() = 0;

virtual std::size_t& get_continuation_recursion_count() = 0;

// access coroutines context object
using impl_type = coroutine_impl;
using impl_ptr = impl_type*;

std::size_t& get_continuation_recursion_count()
private:
friend struct coroutine_accessor;
virtual impl_ptr get_impl()
{
HPX_ASSERT(m_pimpl);
return m_pimpl->get_continuation_recursion_count();
return nullptr;
}

public:
Expand All @@ -206,14 +160,27 @@ namespace hpx { namespace threads { namespace coroutines { namespace detail {

private:
yield_decorator_type yield_decorator_;
coroutine_self* next_self_;
};

impl_ptr get_impl()
////////////////////////////////////////////////////////////////////////////
struct reset_self_on_exit
{
reset_self_on_exit(
coroutine_self* val, coroutine_self* old_val = nullptr)
: old_self(old_val)
{
return m_pimpl;
coroutine_self::set_self(val);
}
impl_ptr m_pimpl;
coroutine_self* next_self_;

~reset_self_on_exit()
{
coroutine_self::set_self(old_self);
}

coroutine_self* old_self;
};

}}}} // namespace hpx::threads::coroutines::detail

#endif /*HPX_RUNTIME_THREADS_COROUTINES_DETAIL_SELF_HPP*/
#endif
@@ -0,0 +1,120 @@
// Copyright (c) 2019 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef HPX_RUNTIME_THREADS_COROUTINES_DETAIL_STACKFUL_SELF_HPP
#define HPX_RUNTIME_THREADS_COROUTINES_DETAIL_STACKFUL_SELF_HPP

#include <hpx/config.hpp>
#include <hpx/assertion.hpp>
#include <hpx/coroutines/detail/coroutine_impl.hpp>
#include <hpx/coroutines/detail/coroutine_self.hpp>
#include <hpx/coroutines/thread_enums.hpp>
#include <hpx/coroutines/thread_id_type.hpp>
#include <hpx/functional/function.hpp>

#include <cstddef>
#include <exception>
#include <limits>
#include <utility>

namespace hpx { namespace threads { namespace coroutines { namespace detail {

class coroutine_stackful_self : public coroutine_self
{
public:
explicit coroutine_stackful_self(
impl_type* pimpl, coroutine_self* next_self = nullptr)
: coroutine_self(next_self)
, pimpl_(pimpl)
{
}

arg_type yield_impl(result_type arg) override
{
HPX_ASSERT(pimpl_);

this->pimpl_->bind_result(arg);

{
reset_self_on_exit on_exit(this);
this->pimpl_->yield();
}

return *pimpl_->args();
}

thread_id_type get_thread_id() const override
{
HPX_ASSERT(pimpl_);
return pimpl_->get_thread_id();
}

std::size_t get_thread_phase() const override
{
#if defined(HPX_HAVE_THREAD_PHASE_INFORMATION)
HPX_ASSERT(pimpl_);
return pimpl_->get_thread_phase();
#else
return 0;
#endif
}

std::ptrdiff_t get_available_stack_space() override
{
#if defined(HPX_HAVE_THREADS_GET_STACK_POINTER)
return pimpl_->get_available_stack_space();
#else
return (std::numeric_limits<std::ptrdiff_t>::max)();
#endif
}

std::size_t get_thread_data() const override
{
HPX_ASSERT(pimpl_);
return pimpl_->get_thread_data();
}
std::size_t set_thread_data(std::size_t data) override
{
HPX_ASSERT(pimpl_);
return pimpl_->set_thread_data(data);
}

tss_storage* get_thread_tss_data() override
{
#if defined(HPX_HAVE_THREAD_LOCAL_STORAGE)
HPX_ASSERT(pimpl_);
return pimpl_->get_thread_tss_data(false);
#else
return nullptr;
#endif
}

tss_storage* get_or_create_thread_tss_data() override
{
#if defined(HPX_HAVE_THREAD_LOCAL_STORAGE)
HPX_ASSERT(pimpl_);
return pimpl_->get_thread_tss_data(true);
#else
return nullptr;
#endif
}

std::size_t& get_continuation_recursion_count() override
{
HPX_ASSERT(pimpl_);
return pimpl_->get_continuation_recursion_count();
}

private:
coroutine_impl* get_impl() override
{
return pimpl_;
}
coroutine_impl* pimpl_;
};
}}}} // namespace hpx::threads::coroutines::detail

#endif /*HPX_RUNTIME_THREADS_COROUTINES_DETAIL_SELF_HPP*/

0 comments on commit 541f336

Please sign in to comment.