for (;;) | for (;;) | ||||
{ | { | ||||
intptr_t value = co_await *rd; | intptr_t value = co_await *rd; | ||||
co_await (*wr << (value + 1)); | |||||
co_await wr->write(value + 1); | |||||
} | } | ||||
} | } | ||||
}; | }; | ||||
template<class _Ty> | template<class _Ty> | ||||
struct awaitable_t : public awaitable_impl_t<_Ty> | |||||
struct [[nodiscard]] awaitable_t : public awaitable_impl_t<_Ty> | |||||
{ | { | ||||
using typename awaitable_impl_t<_Ty>::value_type; | using typename awaitable_impl_t<_Ty>::value_type; | ||||
using awaitable_impl_t<_Ty>::awaitable_impl_t; | using awaitable_impl_t<_Ty>::awaitable_impl_t; | ||||
} | } | ||||
}; | }; | ||||
template<class _Ty> | |||||
struct [[nodiscard]] awaitable_t<_Ty&> : public awaitable_impl_t<_Ty&> | |||||
{ | |||||
using typename awaitable_impl_t<_Ty&>::value_type; | |||||
using awaitable_impl_t<_Ty&>::awaitable_impl_t; | |||||
void set_value(_Ty& value) const | |||||
{ | |||||
this->_state->set_value(value); | |||||
this->_state = nullptr; | |||||
} | |||||
}; | |||||
template<> | template<> | ||||
struct awaitable_t<void> : public awaitable_impl_t<void> | |||||
struct [[nodiscard]] awaitable_t<void> : public awaitable_impl_t<void> | |||||
{ | { | ||||
using awaitable_impl_t<void>::awaitable_impl_t; | using awaitable_impl_t<void>::awaitable_impl_t; | ||||
#pragma once | #pragma once | ||||
#define LIB_RESUMEF_VERSION 20303 // 2.3.3 | |||||
#define LIB_RESUMEF_VERSION 20304 // 2.3.4 | |||||
#if defined(RESUMEF_MODULE_EXPORT) | #if defined(RESUMEF_MODULE_EXPORT) | ||||
#define RESUMEF_NS export namespace resumef | #define RESUMEF_NS export namespace resumef |
return awaitable.get_future(); | return awaitable.get_future(); | ||||
} | } | ||||
void async_manual_reset_event::set() noexcept | |||||
{ | |||||
// Needs to be 'release' so that subsequent 'co_await' has | |||||
// visibility of our prior writes. | |||||
// Needs to be 'acquire' so that we have visibility of prior | |||||
// writes by awaiting coroutines. | |||||
void* oldValue = m_state.exchange(this, std::memory_order_acq_rel); | |||||
if (oldValue != this) | |||||
{ | |||||
// Wasn't already in 'set' state. | |||||
// Treat old value as head of a linked-list of waiters | |||||
// which we have now acquired and need to resume. | |||||
auto* waiters = static_cast<awaiter*>(oldValue); | |||||
while (waiters != nullptr) | |||||
{ | |||||
// Read m_next before resuming the coroutine as resuming | |||||
// the coroutine will likely destroy the awaiter object. | |||||
auto* next = waiters->m_next; | |||||
waiters->m_awaitingCoroutine.resume(); | |||||
waiters = next; | |||||
} | |||||
} | |||||
} | |||||
bool async_manual_reset_event::awaiter::await_suspend( | |||||
coroutine_handle<> awaitingCoroutine) noexcept | |||||
{ | |||||
// Special m_state value that indicates the event is in the 'set' state. | |||||
const void* const setState = &m_event; | |||||
// Remember the handle of the awaiting coroutine. | |||||
m_awaitingCoroutine = awaitingCoroutine; | |||||
// Try to atomically push this awaiter onto the front of the list. | |||||
void* oldValue = m_event.m_state.load(std::memory_order_acquire); | |||||
do | |||||
{ | |||||
// Resume immediately if already in 'set' state. | |||||
if (oldValue == setState) return false; | |||||
// Update linked list to point at current head. | |||||
m_next = static_cast<awaiter*>(oldValue); | |||||
// Finally, try to swap the old list head, inserting this awaiter | |||||
// as the new list head. | |||||
} while (!m_event.m_state.compare_exchange_weak( | |||||
oldValue, | |||||
this, | |||||
std::memory_order_release, | |||||
std::memory_order_acquire)); | |||||
// Successfully enqueued. Remain suspended. | |||||
return true; | |||||
} | |||||
} | } |
static future_t<bool> wait_all_until_(const clock_type::time_point& tp, std::vector<event_impl_ptr>&& evts); | static future_t<bool> wait_all_until_(const clock_type::time_point& tp, std::vector<event_impl_ptr>&& evts); | ||||
}; | }; | ||||
class async_manual_reset_event | |||||
{ | |||||
public: | |||||
async_manual_reset_event(bool initiallySet = false) noexcept | |||||
: m_state(initiallySet ? this : nullptr) | |||||
{} | |||||
// No copying/moving | |||||
async_manual_reset_event(const async_manual_reset_event&) = delete; | |||||
async_manual_reset_event(async_manual_reset_event&&) = delete; | |||||
async_manual_reset_event& operator=(const async_manual_reset_event&) = delete; | |||||
async_manual_reset_event& operator=(async_manual_reset_event&&) = delete; | |||||
bool is_set() const noexcept | |||||
{ | |||||
return m_state.load(std::memory_order_acquire) == this; | |||||
} | |||||
struct awaiter; | |||||
awaiter operator co_await() const noexcept; | |||||
void set() noexcept; | |||||
void reset() noexcept | |||||
{ | |||||
void* oldValue = this; | |||||
m_state.compare_exchange_strong(oldValue, nullptr, std::memory_order_acquire); | |||||
} | |||||
private: | |||||
friend struct awaiter; | |||||
// - 'this' => set state | |||||
// - otherwise => not set, head of linked list of awaiter*. | |||||
mutable std::atomic<void*> m_state; | |||||
}; | |||||
struct async_manual_reset_event::awaiter | |||||
{ | |||||
awaiter(const async_manual_reset_event& event) noexcept | |||||
: m_event(event) | |||||
{} | |||||
bool await_ready() const noexcept | |||||
{ | |||||
return m_event.is_set(); | |||||
} | |||||
bool await_suspend(coroutine_handle<> awaitingCoroutine) noexcept; | |||||
void await_resume() noexcept {} | |||||
private: | |||||
friend class async_manual_reset_event; | |||||
const async_manual_reset_event& m_event; | |||||
coroutine_handle<> m_awaitingCoroutine; | |||||
awaiter* m_next; | |||||
}; | |||||
inline async_manual_reset_event::awaiter async_manual_reset_event::operator co_await() const noexcept | |||||
{ | |||||
return awaiter{ *this }; | |||||
} | |||||
} | } |
RESUMEF_NS | RESUMEF_NS | ||||
{ | { | ||||
template<class _Ty> | template<class _Ty> | ||||
struct future_t | |||||
struct [[nodiscard]] future_t | |||||
{ | { | ||||
using value_type = _Ty; | using value_type = _Ty; | ||||
using state_type = state_t<value_type>; | using state_type = state_t<value_type>; |
std::experimental::suspend_always yield_value(U&& val); | std::experimental::suspend_always yield_value(U&& val); | ||||
}; | }; | ||||
template<class _Ty> | |||||
struct promise_t<_Ty&> final : public promise_impl_t<_Ty&> | |||||
{ | |||||
using typename promise_impl_t<_Ty&>::value_type; | |||||
using promise_impl_t<_Ty&>::get_return_object; | |||||
void return_value(_Ty& val); //co_return val | |||||
std::experimental::suspend_always yield_value(_Ty& val); | |||||
}; | |||||
template<> | template<> | ||||
struct promise_t<void> final : public promise_impl_t<void> | struct promise_t<void> final : public promise_impl_t<void> | ||||
{ | { |
return {}; | return {}; | ||||
} | } | ||||
template<class _Ty> | |||||
inline void promise_t<_Ty&>::return_value(_Ty& val) | |||||
{ | |||||
this->get_state()->set_value(val); | |||||
} | |||||
template<class _Ty> | |||||
inline std::experimental::suspend_always promise_t<_Ty&>::yield_value(_Ty& val) | |||||
{ | |||||
this->get_state()->promise_yield_value(this, val); | |||||
return {}; | |||||
} | |||||
inline void promise_t<void>::return_void() | inline void promise_t<void>::return_void() | ||||
{ | { | ||||
this->get_state()->set_value(); | this->get_state()->set_value(); |
return has_handler_skip_lock(); | return has_handler_skip_lock(); | ||||
} | } | ||||
void state_future_t::set_exception(std::exception_ptr e) | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
this->_exception = std::move(e); | |||||
scheduler_t* sch = this->get_scheduler(); | |||||
if (sch != nullptr) | |||||
{ | |||||
if (this->has_handler_skip_lock()) | |||||
sch->add_generator(this); | |||||
else | |||||
sch->del_final(this); | |||||
} | |||||
} | |||||
bool state_future_t::switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<> handler) | bool state_future_t::switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<> handler) | ||||
{ | { | ||||
assert(sch != nullptr); | assert(sch != nullptr); | ||||
if (this->_exception) | if (this->_exception) | ||||
std::rethrow_exception(std::move(this->_exception)); | std::rethrow_exception(std::move(this->_exception)); | ||||
if (!this->_has_value.load(std::memory_order_acquire)) | |||||
if (this->_has_value.load(std::memory_order_acquire) == result_type::None) | |||||
std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready})); | std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready})); | ||||
} | } | ||||
void state_t<void>::set_value() | void state_t<void>::set_value() | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | scoped_lock<lock_type> __guard(this->_mtx); | ||||
this->_has_value.store(true, std::memory_order_release); | |||||
this->_has_value.store(result_type::Value, std::memory_order_release); | |||||
scheduler_t* sch = this->get_scheduler(); | |||||
if (sch != nullptr) | |||||
{ | |||||
if (this->has_handler_skip_lock()) | |||||
sch->add_generator(this); | |||||
else | |||||
sch->del_final(this); | |||||
} | |||||
} | |||||
void state_t<void>::set_exception(std::exception_ptr e) | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
this->_exception = std::move(e); | |||||
scheduler_t* sch = this->get_scheduler(); | scheduler_t* sch = this->get_scheduler(); | ||||
if (sch != nullptr) | if (sch != nullptr) |
Initial, | Initial, | ||||
Final | Final | ||||
}; | }; | ||||
enum struct result_type : uint8_t | |||||
{ | |||||
None, | |||||
Value, | |||||
Exception, | |||||
}; | |||||
//typedef std::recursive_mutex lock_type; | //typedef std::recursive_mutex lock_type; | ||||
typedef spinlock lock_type; | typedef spinlock lock_type; | ||||
protected: | protected: | ||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
intptr_t _id; | intptr_t _id; | ||||
#endif | #endif | ||||
std::exception_ptr _exception; | |||||
uint32_t _alloc_size = 0; | uint32_t _alloc_size = 0; | ||||
std::atomic<bool> _has_value{ false }; | |||||
std::atomic<result_type> _has_value{ result_type::None }; | |||||
bool _is_awaitor; | bool _is_awaitor; | ||||
initor_type _is_initor = initor_type::None; | initor_type _is_initor = initor_type::None; | ||||
public: | public: | ||||
inline bool is_ready() const | inline bool is_ready() const | ||||
{ | { | ||||
return _exception != nullptr || _has_value.load(std::memory_order_acquire) || !_is_awaitor; | |||||
return _has_value.load(std::memory_order_acquire) != result_type::None || !_is_awaitor; | |||||
} | } | ||||
inline bool has_handler_skip_lock() const | inline bool has_handler_skip_lock() const | ||||
{ | { | ||||
return _alloc_size; | return _alloc_size; | ||||
} | } | ||||
void set_exception(std::exception_ptr e); | |||||
template<class _Exp> | |||||
inline void throw_exception(_Exp e) | |||||
{ | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | |||||
inline bool future_await_ready() | inline bool future_await_ready() | ||||
{ | { | ||||
//scoped_lock<lock_type> __guard(this->_mtx); | //scoped_lock<lock_type> __guard(this->_mtx); | ||||
return _has_value.load(std::memory_order_acquire); | |||||
return _has_value.load(std::memory_order_acquire) != result_type::None; | |||||
} | } | ||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | ||||
void future_await_suspend(coroutine_handle<_PromiseT> handler); | void future_await_suspend(coroutine_handle<_PromiseT> handler); | ||||
public: | public: | ||||
~state_t() | ~state_t() | ||||
{ | { | ||||
if (_has_value.load(std::memory_order_acquire)) | |||||
cast_value_ptr()->~value_type(); | |||||
switch (_has_value.load(std::memory_order_acquire)) | |||||
{ | |||||
case result_type::Value: | |||||
_value.~value_type(); | |||||
break; | |||||
case result_type::Exception: | |||||
_exception.~exception_ptr(); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} | } | ||||
auto future_await_resume() -> value_type; | auto future_await_resume() -> value_type; | ||||
template<class _PromiseT, typename U, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | template<class _PromiseT, typename U, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | ||||
void promise_yield_value(_PromiseT* promise, U&& val); | void promise_yield_value(_PromiseT* promise, U&& val); | ||||
void set_exception(std::exception_ptr e); | |||||
template<typename U> | template<typename U> | ||||
void set_value(U&& val); | void set_value(U&& val); | ||||
template<class _Exp> | |||||
inline void throw_exception(_Exp e) | |||||
{ | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | |||||
private: | private: | ||||
value_type * cast_value_ptr() | |||||
union | |||||
{ | { | ||||
return static_cast<value_type*>(static_cast<void*>(_value)); | |||||
std::exception_ptr _exception; | |||||
value_type _value; | |||||
}; | |||||
template<typename U> | |||||
void set_value_internal(U&& val); | |||||
void set_exception_internal(std::exception_ptr e); | |||||
}; | |||||
template <typename _Ty> | |||||
struct state_t<_Ty&> final : public state_future_t | |||||
{ | |||||
friend state_future_t; | |||||
using state_future_t::lock_type; | |||||
using value_type = _Ty; | |||||
using reference_type = _Ty&; | |||||
explicit state_t(size_t alloc_size) :state_future_t() | |||||
{ | |||||
_alloc_size = static_cast<uint32_t>(alloc_size); | |||||
} | } | ||||
explicit state_t(bool awaitor) :state_future_t(awaitor) | |||||
{ | |||||
_alloc_size = sizeof(*this); | |||||
} | |||||
public: | |||||
~state_t() | |||||
{ | |||||
if (_has_value.load(std::memory_order_acquire) == result_type::Exception) | |||||
_exception.~exception_ptr(); | |||||
} | |||||
auto future_await_resume()->reference_type; | |||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | |||||
void promise_yield_value(_PromiseT* promise, reference_type val); | |||||
alignas(value_type) unsigned char _value[sizeof(value_type)] = {0}; | |||||
void set_exception(std::exception_ptr e); | |||||
void set_value(reference_type val); | |||||
template<class _Exp> | |||||
inline void throw_exception(_Exp e) | |||||
{ | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | |||||
private: | |||||
union | |||||
{ | |||||
std::exception_ptr _exception; | |||||
value_type* _value; | |||||
}; | |||||
void set_value_internal(reference_type val); | |||||
void set_exception_internal(std::exception_ptr e); | |||||
}; | }; | ||||
template<> | template<> | ||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | ||||
void promise_yield_value(_PromiseT* promise); | void promise_yield_value(_PromiseT* promise); | ||||
void set_exception(std::exception_ptr e); | |||||
void set_value(); | void set_value(); | ||||
template<class _Exp> | |||||
inline void throw_exception(_Exp e) | |||||
{ | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | |||||
private: | |||||
std::exception_ptr _exception; | |||||
}; | }; | ||||
} | } | ||||
sch->add_generator(this); | sch->add_generator(this); | ||||
} | } | ||||
//------------------------------------------------------------------------------------------------ | |||||
template<class _PromiseT, typename _Enable > | template<class _PromiseT, typename _Enable > | ||||
void state_t<void>::promise_yield_value(_PromiseT* promise) | void state_t<void>::promise_yield_value(_PromiseT* promise) | ||||
{ | { | ||||
this->_coro = handler; | this->_coro = handler; | ||||
} | } | ||||
this->_has_value.store(true, std::memory_order_release); | |||||
this->_has_value.store(result_type::Value, std::memory_order_release); | |||||
if (!handler.done()) | if (!handler.done()) | ||||
{ | { | ||||
} | } | ||||
} | } | ||||
//------------------------------------------------------------------------------------------------ | |||||
template<typename _Ty> | template<typename _Ty> | ||||
template<class _PromiseT, typename U, typename _Enable > | template<class _PromiseT, typename U, typename _Enable > | ||||
void state_t<_Ty>::promise_yield_value(_PromiseT* promise, U&& val) | void state_t<_Ty>::promise_yield_value(_PromiseT* promise, U&& val) | ||||
this->_coro = handler; | this->_coro = handler; | ||||
} | } | ||||
if (this->_has_value.load(std::memory_order_acquire)) | |||||
{ | |||||
*this->cast_value_ptr() = std::forward<U>(val); | |||||
} | |||||
else | |||||
{ | |||||
new (this->cast_value_ptr()) value_type(std::forward<U>(val)); | |||||
this->_has_value.store(true, std::memory_order_release); | |||||
} | |||||
set_value_internal(std::forward<U>(val)); | |||||
if (!handler.done()) | if (!handler.done()) | ||||
{ | { | ||||
auto state_t<_Ty>::future_await_resume() -> value_type | auto state_t<_Ty>::future_await_resume() -> value_type | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | scoped_lock<lock_type> __guard(this->_mtx); | ||||
if (this->_exception) | |||||
switch (this->_has_value.load(std::memory_order_acquire)) | |||||
{ | |||||
case result_type::None: | |||||
std::rethrow_exception(std::make_exception_ptr(future_exception{ error_code::not_ready })); | |||||
break; | |||||
case result_type::Exception: | |||||
std::rethrow_exception(std::move(this->_exception)); | std::rethrow_exception(std::move(this->_exception)); | ||||
if (!this->_has_value.load(std::memory_order_acquire)) | |||||
std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready})); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
return std::move(this->_value); | |||||
} | |||||
template<typename _Ty> | |||||
template<typename U> | |||||
void state_t<_Ty>::set_value_internal(U&& val) | |||||
{ | |||||
switch (_has_value.load(std::memory_order_acquire)) | |||||
{ | |||||
case result_type::Value: | |||||
_value = std::forward<U>(val); | |||||
break; | |||||
case result_type::Exception: | |||||
_exception.~exception_ptr(); | |||||
default: | |||||
new (&this->_value) value_type(std::forward<U>(val)); | |||||
this->_has_value.store(result_type::Value, std::memory_order_release); | |||||
break; | |||||
} | |||||
} | |||||
return std::move(*this->cast_value_ptr()); | |||||
template<typename _Ty> | |||||
void state_t<_Ty>::set_exception_internal(std::exception_ptr e) | |||||
{ | |||||
switch (_has_value.load(std::memory_order_acquire)) | |||||
{ | |||||
case result_type::Exception: | |||||
_exception = std::move(e); | |||||
break; | |||||
case result_type::Value: | |||||
_value.~value_type(); | |||||
default: | |||||
new (&this->_exception) std::exception_ptr(std::move(e)); | |||||
this->_has_value.store(result_type::Exception, std::memory_order_release); | |||||
break; | |||||
} | |||||
} | } | ||||
template<typename _Ty> | template<typename _Ty> | ||||
void state_t<_Ty>::set_value(U&& val) | void state_t<_Ty>::set_value(U&& val) | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | scoped_lock<lock_type> __guard(this->_mtx); | ||||
set_value_internal(std::forward<U>(val)); | |||||
scheduler_t* sch = this->get_scheduler(); | |||||
if (sch != nullptr) | |||||
{ | |||||
if (this->has_handler_skip_lock()) | |||||
sch->add_generator(this); | |||||
else | |||||
sch->del_final(this); | |||||
} | |||||
} | |||||
template<typename _Ty> | |||||
void state_t<_Ty>::set_exception(std::exception_ptr e) | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
set_exception_internal(std::move(e)); | |||||
scheduler_t* sch = this->get_scheduler(); | |||||
if (sch != nullptr) | |||||
{ | |||||
if (this->has_handler_skip_lock()) | |||||
sch->add_generator(this); | |||||
else | |||||
sch->del_final(this); | |||||
} | |||||
} | |||||
//------------------------------------------------------------------------------------------------ | |||||
template<typename _Ty> | |||||
template<class _PromiseT, typename _Enable > | |||||
void state_t<_Ty&>::promise_yield_value(_PromiseT* promise, reference_type val) | |||||
{ | |||||
coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise); | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
if (!handler.done()) | |||||
{ | |||||
if (this->_coro == nullptr) | |||||
this->_coro = handler; | |||||
} | |||||
set_value_internal(val); | |||||
if (!handler.done()) | |||||
{ | |||||
scheduler_t* sch = this->get_scheduler(); | |||||
if (sch != nullptr) | |||||
sch->add_generator(this); | |||||
} | |||||
} | |||||
template<typename _Ty> | |||||
auto state_t<_Ty&>::future_await_resume() -> reference_type | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
switch (this->_has_value.load(std::memory_order_acquire)) | |||||
{ | |||||
case result_type::None: | |||||
std::rethrow_exception(std::make_exception_ptr(future_exception{ error_code::not_ready })); | |||||
break; | |||||
case result_type::Exception: | |||||
std::rethrow_exception(std::move(this->_exception)); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
return static_cast<reference_type>(*this->_value); | |||||
} | |||||
if (this->_has_value.load(std::memory_order_acquire)) | |||||
template<typename _Ty> | |||||
void state_t<_Ty&>::set_value_internal(reference_type val) | |||||
{ | |||||
switch (_has_value.load(std::memory_order_acquire)) | |||||
{ | { | ||||
*this->cast_value_ptr() = std::forward<U>(val); | |||||
case result_type::Exception: | |||||
_exception.~exception_ptr(); | |||||
default: | |||||
this->_value = &val; | |||||
this->_has_value.store(result_type::Value, std::memory_order_release); | |||||
break; | |||||
} | } | ||||
else | |||||
} | |||||
template<typename _Ty> | |||||
void state_t<_Ty&>::set_exception_internal(std::exception_ptr e) | |||||
{ | |||||
switch (_has_value.load(std::memory_order_acquire)) | |||||
{ | |||||
case result_type::Exception: | |||||
_exception = std::move(e); | |||||
break; | |||||
default: | |||||
new (&this->_exception) std::exception_ptr(std::move(e)); | |||||
this->_has_value.store(result_type::Exception, std::memory_order_release); | |||||
break; | |||||
} | |||||
} | |||||
template<typename _Ty> | |||||
void state_t<_Ty&>::set_value(reference_type val) | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
set_value_internal(val); | |||||
scheduler_t* sch = this->get_scheduler(); | |||||
if (sch != nullptr) | |||||
{ | { | ||||
new (this->cast_value_ptr()) value_type(std::forward<U>(val)); | |||||
this->_has_value.store(true, std::memory_order_release); | |||||
if (this->has_handler_skip_lock()) | |||||
sch->add_generator(this); | |||||
else | |||||
sch->del_final(this); | |||||
} | } | ||||
} | |||||
template<typename _Ty> | |||||
void state_t<_Ty&>::set_exception(std::exception_ptr e) | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
set_exception_internal(std::move(e)); | |||||
scheduler_t* sch = this->get_scheduler(); | scheduler_t* sch = this->get_scheduler(); | ||||
if (sch != nullptr) | if (sch != nullptr) |
//这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | //这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | ||||
static future_t<int64_t> async_get_long(int64_t val) | static future_t<int64_t> async_get_long(int64_t val) | ||||
{ | { | ||||
resumef::awaitable_t<int64_t> awaitable; | |||||
awaitable_t<int64_t> awaitable; | |||||
callback_get_long(val, [awaitable](int64_t val) | callback_get_long(val, [awaitable](int64_t val) | ||||
{ | { | ||||
awaitable.set_value(val); | awaitable.set_value(val); | ||||
co_return val; | co_return val; | ||||
} | } | ||||
static future_t<std::string&> async_get_string(std::string & ref_string) | |||||
{ | |||||
awaitable_t<std::string&> awaitable; | |||||
callback_get_long(std::stoi(ref_string), [awaitable, &ref_string](int64_t val) | |||||
{ | |||||
ref_string = std::to_string(val); | |||||
awaitable.set_value(ref_string); | |||||
}); | |||||
return awaitable.get_future(); | |||||
} | |||||
static future_t<std::string&> resumable_get_string(std::string& val) | |||||
{ | |||||
std::cout << val << std::endl; | |||||
val = co_await async_get_string(val); | |||||
std::cout << val << std::endl; | |||||
val = co_await async_get_string(val); | |||||
std::cout << val << std::endl; | |||||
val = co_await async_get_string(val); | |||||
std::cout << val << std::endl; | |||||
co_return static_cast<std::string&>(val); | |||||
} | |||||
void resumable_main_cb() | void resumable_main_cb() | ||||
{ | { | ||||
//由于使用者可能不能明确的区分是resume function返回的awaitor还是awaitable function返回的awaitor | //由于使用者可能不能明确的区分是resume function返回的awaitor还是awaitable function返回的awaitor | ||||
//导致均有可能加入到协程里去调度。 | //导致均有可能加入到协程里去调度。 | ||||
//所以,协程调度器应该需要能处理这种情况。 | //所以,协程调度器应该需要能处理这种情况。 | ||||
go async_get_long(3); | go async_get_long(3); | ||||
resumef::this_scheduler()->run_until_notask(); | |||||
this_scheduler()->run_until_notask(); | |||||
std::string ref_string{"2"}; | |||||
go resumable_get_string(ref_string); | |||||
this_scheduler()->run_until_notask(); | |||||
GO | GO | ||||
{ | { | ||||
}; | }; | ||||
go loop_get_long(3); | go loop_get_long(3); | ||||
resumef::this_scheduler()->run_until_notask(); | |||||
this_scheduler()->run_until_notask(); | |||||
} | } |
promise_type* promise = &handler.promise(); | promise_type* promise = &handler.promise(); | ||||
state_type* state = handler.promise().get_state(); | state_type* state = handler.promise().get_state(); | ||||
std::cout << " future size=" << _Align_size<future_type>() << std::endl; | |||||
std::cout << " promise size=" << _Align_size<promise_type>() << std::endl; | |||||
std::cout << " state size=" << _Align_size<state_type>() << std::endl; | |||||
std::cout << " future size=" << sizeof(future_type) << " / " << _Align_size<future_type>() << std::endl; | |||||
std::cout << " promise size=" << sizeof(promise_type) << " / " << _Align_size<promise_type>() << std::endl; | |||||
std::cout << " state size=" << sizeof(state_type) << " / "<< _Align_size<state_type>() << std::endl; | |||||
std::cout << " frame size=" << _coro_frame_size() << ", alloc size=" << state->get_alloc_size() << std::endl; | std::cout << " frame size=" << _coro_frame_size() << ", alloc size=" << state->get_alloc_size() << std::endl; | ||||
std::cout << " frame ptr=" << frame_ptr << "," << (void*)&frame_ptr << std::endl; | std::cout << " frame ptr=" << frame_ptr << "," << (void*)&frame_ptr << std::endl; | ||||
promise_type * promise = &handler.promise(); | promise_type * promise = &handler.promise(); | ||||
state_type * state = handler.promise().get_state(); | state_type * state = handler.promise().get_state(); | ||||
std::cout << " future size=" << _Align_size<future_type>() << std::endl; | |||||
std::cout << " promise size=" << _Align_size<promise_type>() << std::endl; | |||||
std::cout << " state size=" << _Align_size<state_type>() << std::endl; | |||||
std::cout << " future size=" << sizeof(future_type) << " / " << _Align_size<future_type>() << std::endl; | |||||
std::cout << " promise size=" << sizeof(promise_type) << " / " << _Align_size<promise_type>() << std::endl; | |||||
std::cout << " state size=" << sizeof(state_type) << " / "<< _Align_size<state_type>() << std::endl; | |||||
std::cout << " frame size=" << _coro_frame_size() << ", alloc size=" << state->get_alloc_size() << std::endl; | std::cout << " frame size=" << _coro_frame_size() << ", alloc size=" << state->get_alloc_size() << std::endl; | ||||
std::cout << " frame ptr=" << frame_ptr << ","<< (void*)&frame_ptr << std::endl; | std::cout << " frame ptr=" << frame_ptr << ","<< (void*)&frame_ptr << std::endl; |
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
resumef::sleep_for(100ms); //incorrect!!! | |||||
(void)resumef::sleep_for(100ms); //incorrect!!! | |||||
co_await resumef::sleep_for(100ms); | co_await resumef::sleep_for(100ms); | ||||
std::cout << "sleep_for 100ms." << std::endl; | std::cout << "sleep_for 100ms." << std::endl; |
local_scheduler my_scheduler; //产生本线程唯一的调度器 | local_scheduler my_scheduler; //产生本线程唯一的调度器 | ||||
sch_in_thread = this_scheduler(); //本线程唯一的调度器赋值给sch_in_thread,以便于后续测试直接访问此线程的调度器 | sch_in_thread = this_scheduler(); //本线程唯一的调度器赋值给sch_in_thread,以便于后续测试直接访问此线程的调度器 | ||||
c_done << true; //数据都准备好了,通过channel通知其他协程可以启动后续依赖sch_in_thread变量的协程了 | |||||
(void)c_done.write(true); //数据都准备好了,通过channel通知其他协程可以启动后续依赖sch_in_thread变量的协程了 | |||||
//循环直到sch_in_thread为nullptr | //循环直到sch_in_thread为nullptr | ||||
for (;;) | for (;;) | ||||
val = co_await async_get_long(val); | val = co_await async_get_long(val); | ||||
std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl; | std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl; | ||||
c_done << true; | |||||
(void)c_done.write(true); | |||||
} | } | ||||
void resumable_main_switch_scheduler() | void resumable_main_switch_scheduler() |
{ | { | ||||
(void)argc; | (void)argc; | ||||
(void)argv; | (void)argv; | ||||
//resumable_main_resumable(); | |||||
//resumable_main_layout(); | |||||
//return 0; | //return 0; | ||||
//if (argc > 1) | //if (argc > 1) | ||||
resumable_main_switch_scheduler(); | resumable_main_switch_scheduler(); | ||||
std::cout << "ALL OK!" << std::endl; | std::cout << "ALL OK!" << std::endl; | ||||
#if !defined(__clang__) || defined(_WIN64) | |||||
benchmark_main_channel_passing_next(); //这是一个死循环测试 | benchmark_main_channel_passing_next(); //这是一个死循环测试 | ||||
#endif | |||||
return 0; | return 0; | ||||
} | } |
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> | ||||
<ConfigurationType>Application</ConfigurationType> | <ConfigurationType>Application</ConfigurationType> | ||||
<UseDebugLibraries>false</UseDebugLibraries> | <UseDebugLibraries>false</UseDebugLibraries> | ||||
<PlatformToolset>v142</PlatformToolset> | |||||
<PlatformToolset>ClangCL</PlatformToolset> | |||||
<WholeProgramOptimization>true</WholeProgramOptimization> | <WholeProgramOptimization>true</WholeProgramOptimization> | ||||
<CharacterSet>NotSet</CharacterSet> | <CharacterSet>NotSet</CharacterSet> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | ||||
<ConfigurationType>Application</ConfigurationType> | <ConfigurationType>Application</ConfigurationType> | ||||
<PlatformToolset>v142</PlatformToolset> | |||||
<PlatformToolset>ClangCL</PlatformToolset> | |||||
<UseDebugLibraries>true</UseDebugLibraries> | <UseDebugLibraries>true</UseDebugLibraries> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | ||||
<ConfigurationType>Application</ConfigurationType> | <ConfigurationType>Application</ConfigurationType> | ||||
<UseDebugLibraries>false</UseDebugLibraries> | <UseDebugLibraries>false</UseDebugLibraries> | ||||
<PlatformToolset>v142</PlatformToolset> | |||||
<PlatformToolset>ClangCL</PlatformToolset> | |||||
<WholeProgramOptimization>true</WholeProgramOptimization> | <WholeProgramOptimization>true</WholeProgramOptimization> | ||||
<CharacterSet>NotSet</CharacterSet> | <CharacterSet>NotSet</CharacterSet> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | ||||
<LinkIncremental>true</LinkIncremental> | <LinkIncremental>true</LinkIncremental> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |||||
<LinkIncremental>false</LinkIncremental> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" /> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | ||||
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet> | <CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet> | ||||
<EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> | <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> | ||||
<CLanguageStandard>c11</CLanguageStandard> | <CLanguageStandard>c11</CLanguageStandard> | ||||
<CppLanguageStandard>c++1y</CppLanguageStandard> | <CppLanguageStandard>c++1y</CppLanguageStandard> | ||||
<DisableSpecificWarnings>4834</DisableSpecificWarnings> | <DisableSpecificWarnings>4834</DisableSpecificWarnings> | ||||
<TreatWarningAsError>true</TreatWarningAsError> | |||||
</ClCompile> | </ClCompile> | ||||
<Link> | <Link> | ||||
<SubSystem>Console</SubSystem> | <SubSystem>Console</SubSystem> | ||||
<LanguageStandard>stdcpplatest</LanguageStandard> | <LanguageStandard>stdcpplatest</LanguageStandard> | ||||
<StringPooling>true</StringPooling> | <StringPooling>true</StringPooling> | ||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed> | <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> | ||||
<OmitFramePointers /> | |||||
<OmitFramePointers>true</OmitFramePointers> | |||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> | |||||
<BufferSecurityCheck>false</BufferSecurityCheck> | |||||
</ClCompile> | </ClCompile> | ||||
<Link> | <Link> | ||||
<SubSystem>Console</SubSystem> | <SubSystem>Console</SubSystem> | ||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;ASIO_STANDALONE;RESUMEF_ENABLE_MULT_SCHEDULER=1;_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING=1;ASIO_DISABLE_CONCEPTS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> | <PreprocessorDefinitions>NDEBUG;_CONSOLE;ASIO_STANDALONE;RESUMEF_ENABLE_MULT_SCHEDULER=1;_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING=1;ASIO_DISABLE_CONCEPTS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> | ||||
<AdditionalIncludeDirectories>..\librf;..\..\asio\asio\include;..\..\asio-1.10.6\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | <AdditionalIncludeDirectories>..\librf;..\..\asio\asio\include;..\..\asio-1.10.6\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||||
<AdditionalOptions>/await</AdditionalOptions> | <AdditionalOptions>/await</AdditionalOptions> | ||||
<ExceptionHandling>Sync</ExceptionHandling> | |||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed> | <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> | ||||
<StringPooling>true</StringPooling> | <StringPooling>true</StringPooling> | ||||
<LanguageStandard>stdcpplatest</LanguageStandard> | <LanguageStandard>stdcpplatest</LanguageStandard> | ||||
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations> | <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations> | ||||
<BufferSecurityCheck>false</BufferSecurityCheck> | <BufferSecurityCheck>false</BufferSecurityCheck> | ||||
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration> | <EnableParallelCodeGeneration>true</EnableParallelCodeGeneration> | ||||
<TreatWarningAsError>true</TreatWarningAsError> | |||||
</ClCompile> | </ClCompile> | ||||
<Link> | <Link> | ||||
<SubSystem>Console</SubSystem> | <SubSystem>Console</SubSystem> | ||||
</Link> | </Link> | ||||
</ItemDefinitionGroup> | </ItemDefinitionGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp" /> | |||||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\benchmark\benchmark_async_mem.cpp" /> | <ClCompile Include="..\benchmark\benchmark_async_mem.cpp" /> | ||||
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" /> | |||||
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\event.cpp" /> | <ClCompile Include="..\librf\src\event.cpp" /> | ||||
<ClCompile Include="..\librf\src\mutex.cpp" /> | <ClCompile Include="..\librf\src\mutex.cpp" /> | ||||
<ClCompile Include="..\librf\src\rf_task.cpp" /> | <ClCompile Include="..\librf\src\rf_task.cpp" /> |