#include "src/scheduler.h" | #include "src/scheduler.h" | ||||
#include "src/promise.inl" | #include "src/promise.inl" | ||||
#include "src/state.inl" | #include "src/state.inl" | ||||
#include "src/generator.h" | |||||
#include "src/sleep.h" | #include "src/sleep.h" | ||||
#include "src/when.h" | #include "src/when.h" | ||||
namespace resumef | namespace resumef | ||||
{ | { | ||||
template<class _Derived> | |||||
struct counted_t | |||||
{ | |||||
std::atomic<intptr_t> _count{ 0 }; | |||||
void lock() | |||||
{ | |||||
++_count; | |||||
} | |||||
void unlock() | |||||
{ | |||||
if (--_count == 0) | |||||
delete static_cast<_Derived*>(this); | |||||
} | |||||
}; | |||||
template <typename T> | template <typename T> | ||||
struct counted_ptr | struct counted_ptr | ||||
{ | { |
#include <experimental/coroutine> | #include <experimental/coroutine> | ||||
//#include <experimental/generator> | //#include <experimental/generator> | ||||
//替代<experimental/generator>,因为VS2015/VS2017的generator<>未实现return_value,导致yield后不能return | |||||
#include "generator.h" | |||||
#define LIB_RESUMEF_VERSION 200000 // 2.0.0 | #define LIB_RESUMEF_VERSION 200000 // 2.0.0 | ||||
struct future_t; | struct future_t; | ||||
using future_vt [[deprecated]] = future_t<>; | using future_vt [[deprecated]] = future_t<>; | ||||
template <typename _Ty = std::nullptr_t, typename _Alloc = std::allocator<char>> | |||||
struct generator_t; | |||||
template<class _Ty = void> | template<class _Ty = void> | ||||
struct promise_t; | struct promise_t; | ||||
//获得当前线程下的调度器 | //获得当前线程下的调度器 | ||||
scheduler_t* this_scheduler(); | scheduler_t* this_scheduler(); | ||||
template <typename _Ty = std::nullptr_t, typename _Alloc = std::allocator<char>> | |||||
using generator_t = std::experimental::generator<_Ty, _Alloc>; | |||||
template<typename _PromiseT = void> | template<typename _PromiseT = void> | ||||
using coroutine_handle = std::experimental::coroutine_handle<_PromiseT>; | using coroutine_handle = std::experimental::coroutine_handle<_PromiseT>; | ||||
/*** | |||||
*generator | |||||
* | |||||
* Copyright (c) Microsoft Corporation. All rights reserved. | |||||
* | |||||
* Purpose: Library support of coroutines. generator class | |||||
* http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0057r0.pdf | |||||
* | |||||
* [Public] | |||||
* | |||||
****/ | |||||
/* | |||||
* Modify from <experimental/generator_t.h> | |||||
* Purpose: Library support of coroutines. generator_t class | |||||
* http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0057r0.pdf | |||||
*/ | |||||
#pragma once | #pragma once | ||||
#ifndef _EXPERIMENTAL_GENERATOR_ | |||||
#define _EXPERIMENTAL_GENERATOR_ | |||||
#ifndef RC_INVOKED | |||||
#include <experimental/coroutine> | |||||
#pragma pack(push,_CRT_PACKING) | #pragma pack(push,_CRT_PACKING) | ||||
#pragma push_macro("new") | #pragma push_macro("new") | ||||
#undef new | #undef new | ||||
namespace std { | |||||
namespace experimental { | |||||
namespace resumef | |||||
{ | |||||
template <typename _Ty, typename promise_type> | |||||
struct generator_iterator; | |||||
template<typename promise_type> | |||||
struct generator_iterator<void, promise_type> | |||||
{ | |||||
typedef std::input_iterator_tag iterator_category; | |||||
typedef ptrdiff_t difference_type; | |||||
template <typename _Ty, typename promise_type> | |||||
struct generator_iterator; | |||||
coroutine_handle<promise_type> _Coro; | |||||
template<typename promise_type> | |||||
struct generator_iterator<void, promise_type> | |||||
generator_iterator(nullptr_t) : _Coro(nullptr) | |||||
{ | { | ||||
typedef std::input_iterator_tag iterator_category; | |||||
typedef ptrdiff_t difference_type; | |||||
} | |||||
coroutine_handle<promise_type> _Coro; | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : _Coro(_CoroArg) | |||||
{ | |||||
} | |||||
generator_iterator(nullptr_t) : _Coro(nullptr) | |||||
{ | |||||
} | |||||
generator_iterator& operator++() | |||||
{ | |||||
_Coro.resume(); | |||||
if (_Coro.done()) | |||||
_Coro = nullptr; | |||||
return *this; | |||||
} | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : _Coro(_CoroArg) | |||||
{ | |||||
} | |||||
void operator++(int) | |||||
{ | |||||
// This postincrement operator meets the requirements of the Ranges TS | |||||
// InputIterator concept, but not those of Standard C++ InputIterator. | |||||
++* this; | |||||
} | |||||
bool operator==(generator_iterator const& right_) const | |||||
{ | |||||
return _Coro == right_._Coro; | |||||
} | |||||
bool operator!=(generator_iterator const& right_) const | |||||
{ | |||||
return !(*this == right_); | |||||
} | |||||
}; | |||||
template <typename promise_type> | |||||
struct generator_iterator<nullptr_t, promise_type> : public generator_iterator<void, promise_type> | |||||
{ | |||||
generator_iterator(nullptr_t) : generator_iterator<void, promise_type>(nullptr) | |||||
{ | |||||
} | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : generator_iterator<void, promise_type>(_CoroArg) | |||||
{ | |||||
} | |||||
}; | |||||
template <typename _Ty, typename promise_type> | |||||
struct generator_iterator : public generator_iterator<void, promise_type> | |||||
{ | |||||
using value_type = _Ty; | |||||
using reference = _Ty const&; | |||||
using pointer = _Ty const*; | |||||
generator_iterator& operator++() | |||||
generator_iterator(nullptr_t) : generator_iterator<void, promise_type>(nullptr) | |||||
{ | |||||
} | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : generator_iterator<void, promise_type>(_CoroArg) | |||||
{ | |||||
} | |||||
reference operator*() const | |||||
{ | |||||
return *this->_Coro.promise()._CurrentValue; | |||||
} | |||||
pointer operator->() const | |||||
{ | |||||
return this->_Coro.promise()._CurrentValue; | |||||
} | |||||
}; | |||||
template <typename _Ty, typename _Alloc> | |||||
struct generator_t | |||||
{ | |||||
using value_type = _Ty; | |||||
using state_type = state_generator_t; | |||||
struct promise_type | |||||
{ | |||||
using value_type = _Ty; | |||||
using state_type = state_generator_t; | |||||
using future_type = generator_t<value_type>; | |||||
_Ty const* _CurrentValue; | |||||
promise_type& get_return_object() | |||||
{ | { | ||||
_Coro.resume(); | |||||
if (_Coro.done()) | |||||
_Coro = nullptr; | |||||
return *this; | return *this; | ||||
} | } | ||||
void operator++(int) | |||||
bool initial_suspend() | |||||
{ | { | ||||
// This postincrement operator meets the requirements of the Ranges TS | |||||
// InputIterator concept, but not those of Standard C++ InputIterator. | |||||
++* this; | |||||
return (true); | |||||
} | } | ||||
bool operator==(generator_iterator const& right_) const | |||||
bool final_suspend() | |||||
{ | { | ||||
return _Coro == right_._Coro; | |||||
return (true); | |||||
} | } | ||||
bool operator!=(generator_iterator const& right_) const | |||||
void yield_value(_Ty const& _Value) | |||||
{ | { | ||||
return !(*this == right_); | |||||
_CurrentValue = std::addressof(_Value); | |||||
} | } | ||||
}; | |||||
template <typename promise_type> | |||||
struct generator_iterator<nullptr_t, promise_type> : public generator_iterator<void, promise_type> | |||||
{ | |||||
generator_iterator(nullptr_t) : generator_iterator<void, promise_type>(nullptr) | |||||
template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>> | |||||
void return_value(_Ty const& _Value) | |||||
{ | { | ||||
_CurrentValue = std::addressof(_Value); | |||||
} | } | ||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : generator_iterator<void, promise_type>(_CoroArg) | |||||
template<class = std::enable_if_t<std::is_same_v<_Ty, void>, _Ty>> | |||||
void return_value() | |||||
{ | { | ||||
_CurrentValue = nullptr; | |||||
} | } | ||||
}; | |||||
template <typename _Ty, typename promise_type> | |||||
struct generator_iterator : public generator_iterator<void, promise_type> | |||||
{ | |||||
using value_type = _Ty; | |||||
using reference = _Ty const&; | |||||
using pointer = _Ty const*; | |||||
generator_iterator(nullptr_t) : generator_iterator<void, promise_type>(nullptr) | |||||
{ | |||||
} | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : generator_iterator<void, promise_type>(_CoroArg) | |||||
template <typename _Uty> | |||||
_Uty&& await_transform(_Uty&& _Whatever) | |||||
{ | { | ||||
static_assert(std::is_same_v<_Uty, void>, | |||||
"co_await is not supported in coroutines of type std::experiemental::generator_t"); | |||||
return std::forward<_Uty>(_Whatever); | |||||
} | } | ||||
reference operator*() const | |||||
using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc<char>; | |||||
static_assert(std::is_same_v<char*, typename std::allocator_traits<_Alloc_char>::pointer>, | |||||
"generator_t does not support allocators with fancy pointer types"); | |||||
static_assert(std::allocator_traits<_Alloc_char>::is_always_equal::value, | |||||
"generator_t only supports stateless allocators"); | |||||
void* operator new(size_t _Size) | |||||
{ | { | ||||
return *this->_Coro.promise()._CurrentValue; | |||||
_Alloc_char _Al; | |||||
void* ptr = _Al.allocate(_Size); | |||||
return ptr; | |||||
} | } | ||||
pointer operator->() const | |||||
void operator delete(void* _Ptr, size_t _Size) | |||||
{ | { | ||||
return this->_Coro.promise()._CurrentValue; | |||||
_Alloc_char _Al; | |||||
return _Al.deallocate(static_cast<char*>(_Ptr), _Size); | |||||
} | } | ||||
}; | }; | ||||
template <typename _Ty, typename _Alloc = allocator<char>> | |||||
struct generator | |||||
typedef generator_iterator<_Ty, promise_type> iterator; | |||||
iterator begin() | |||||
{ | { | ||||
struct promise_type | |||||
if (_Coro) | |||||
{ | { | ||||
_Ty const* _CurrentValue; | |||||
promise_type& get_return_object() | |||||
{ | |||||
return *this; | |||||
} | |||||
bool initial_suspend() | |||||
{ | |||||
return (true); | |||||
} | |||||
bool final_suspend() | |||||
{ | |||||
return (true); | |||||
} | |||||
void yield_value(_Ty const& _Value) | |||||
{ | |||||
_CurrentValue = std::addressof(_Value); | |||||
} | |||||
template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>> | |||||
void return_value(_Ty const& _Value) | |||||
{ | |||||
_CurrentValue = std::addressof(_Value); | |||||
} | |||||
template<class = std::enable_if_t<std::is_same_v<_Ty, void>, _Ty>> | |||||
void return_value() | |||||
{ | |||||
_CurrentValue = nullptr; | |||||
} | |||||
template <typename _Uty> | |||||
_Uty&& await_transform(_Uty&& _Whatever) | |||||
{ | |||||
static_assert(std::is_same_v<_Uty, void>, | |||||
"co_await is not supported in coroutines of type std::experiemental::generator"); | |||||
return std::forward<_Uty>(_Whatever); | |||||
} | |||||
using _Alloc_char = typename allocator_traits<_Alloc>::template rebind_alloc<char>; | |||||
static_assert(std::is_same_v<char*, typename std::allocator_traits<_Alloc_char>::pointer>, | |||||
"generator does not support allocators with fancy pointer types"); | |||||
static_assert(std::allocator_traits<_Alloc_char>::is_always_equal::value, | |||||
"generator only supports stateless allocators"); | |||||
void* operator new(size_t _Size) | |||||
{ | |||||
_Alloc_char _Al; | |||||
return _Al.allocate(_Size); | |||||
} | |||||
void operator delete(void* _Ptr, size_t _Size) | |||||
{ | |||||
_Alloc_char _Al; | |||||
return _Al.deallocate(static_cast<char*>(_Ptr), _Size); | |||||
} | |||||
}; | |||||
typedef generator_iterator<_Ty, promise_type> iterator; | |||||
iterator begin() | |||||
{ | |||||
if (_Coro) | |||||
{ | |||||
_Coro.resume(); | |||||
if (_Coro.done()) | |||||
return{ nullptr }; | |||||
} | |||||
return { _Coro }; | |||||
_Coro.resume(); | |||||
if (_Coro.done()) | |||||
return{ nullptr }; | |||||
} | } | ||||
return { _Coro }; | |||||
} | |||||
iterator end() | |||||
{ | |||||
return{ nullptr }; | |||||
} | |||||
iterator end() | |||||
{ | |||||
return{ nullptr }; | |||||
} | |||||
explicit generator(promise_type& _Prom) | |||||
: _Coro(coroutine_handle<promise_type>::from_promise(_Prom)) | |||||
{ | |||||
} | |||||
explicit generator_t(promise_type& _Prom) | |||||
: _Coro(coroutine_handle<promise_type>::from_promise(_Prom)) | |||||
{ | |||||
} | |||||
generator() = default; | |||||
generator_t() = default; | |||||
generator(generator const&) = delete; | |||||
generator_t(generator_t const&) = delete; | |||||
generator& operator=(generator const&) = delete; | |||||
generator_t& operator=(generator_t const&) = delete; | |||||
generator(generator&& right_) noexcept | |||||
: _Coro(right_._Coro) | |||||
{ | |||||
right_._Coro = nullptr; | |||||
} | |||||
generator_t(generator_t&& right_) noexcept | |||||
: _Coro(right_._Coro) | |||||
{ | |||||
right_._Coro = nullptr; | |||||
} | |||||
generator& operator=(generator&& right_) noexcept | |||||
{ | |||||
if (this != std::addressof(right_)) { | |||||
_Coro = right_._Coro; | |||||
right_._Coro = nullptr; | |||||
} | |||||
return *this; | |||||
generator_t& operator=(generator_t&& right_) noexcept | |||||
{ | |||||
if (this != std::addressof(right_)) { | |||||
_Coro = right_._Coro; | |||||
right_._Coro = nullptr; | |||||
} | } | ||||
return *this; | |||||
} | |||||
~generator() | |||||
{ | |||||
if (_Coro) { | |||||
_Coro.destroy(); | |||||
} | |||||
~generator_t() | |||||
{ | |||||
if (_Coro) { | |||||
_Coro.destroy(); | |||||
} | } | ||||
} | |||||
coroutine_handle<promise_type> detach() | |||||
{ | |||||
auto t = _Coro; | |||||
_Coro = nullptr; | |||||
return t; | |||||
} | |||||
coroutine_handle<promise_type> detach() | |||||
{ | |||||
auto t = _Coro; | |||||
_Coro = nullptr; | |||||
return t; | |||||
} | |||||
private: | |||||
coroutine_handle<promise_type> _Coro = nullptr; | |||||
}; | |||||
private: | |||||
coroutine_handle<promise_type> _Coro = nullptr; | |||||
}; | |||||
} // namespace experimental | |||||
} // namespace std | |||||
} // namespace resumef | |||||
#pragma pop_macro("new") | #pragma pop_macro("new") | ||||
#pragma pack(pop) | #pragma pack(pop) | ||||
#endif /* RC_INVOKED */ | |||||
#endif /* _EXPERIMENTAL_GENERATOR_ */ |
using state_type = state_t<value_type>; | using state_type = state_t<value_type>; | ||||
using promise_type = promise_t<value_type>; | using promise_type = promise_t<value_type>; | ||||
using future_type = future_t<value_type>; | using future_type = future_t<value_type>; | ||||
using lock_type = typename state_type::lock_type; | |||||
counted_ptr<state_type> _state = make_counted<state_type>(false); | counted_ptr<state_type> _state = make_counted<state_type>(false); | ||||
char __xxx[16]; | |||||
promise_impl_t() {} | promise_impl_t() {} | ||||
promise_impl_t(promise_impl_t&& _Right) noexcept = default; | promise_impl_t(promise_impl_t&& _Right) noexcept = default; | ||||
#endif | #endif | ||||
future_type get_return_object(); | future_type get_return_object(); | ||||
void cancellation_requested(); | void cancellation_requested(); | ||||
static const size_t _ALIGN_REQ = sizeof(void*) * 2; | |||||
using _Alloc_char = std::allocator<char>; | |||||
void* operator new(size_t _Size) | |||||
{ | |||||
std::cout << "promise::new, size=" << _Size << std::endl; | |||||
_Alloc_char _Al; | |||||
size_t _State_size = ((sizeof(state_type) + _ALIGN_REQ - 1) & ~(_ALIGN_REQ - 1)); | |||||
char* ptr = _Al.allocate(_Size + _State_size); | |||||
return ptr + _State_size; | |||||
} | |||||
void operator delete(void* _Ptr, size_t _Size) | |||||
{ | |||||
_Alloc_char _Al; | |||||
return _Al.deallocate(static_cast<char*>(_Ptr), _Size); | |||||
} | |||||
}; | }; | ||||
template<class _Ty> | template<class _Ty> | ||||
void yield_value(); | void yield_value(); | ||||
}; | }; | ||||
template<class _Ty = void> | |||||
constexpr size_t promise_align_size() | |||||
{ | |||||
return (sizeof(promise_t<_Ty>) + promise_t<_Ty>::_ALIGN_REQ - 1) & ~(promise_t<_Ty>::_ALIGN_REQ - 1); | |||||
} | |||||
} | } | ||||
void state_future_t::resume() | void state_future_t::resume() | ||||
{ | { | ||||
coroutine_handle<> handler; | |||||
scoped_lock<lock_type> __guard(_mtx); | scoped_lock<lock_type> __guard(_mtx); | ||||
if (_initor != nullptr) | if (_initor != nullptr) | ||||
{ | { | ||||
handler = _initor; | |||||
coroutine_handle<> handler = _initor; | |||||
_initor = nullptr; | _initor = nullptr; | ||||
handler(); | |||||
handler.resume(); | |||||
} | } | ||||
else if (_coro != nullptr) | else if (_coro != nullptr) | ||||
{ | { | ||||
handler = _coro; | |||||
coroutine_handle<> handler = _coro; | |||||
_coro = nullptr; | _coro = nullptr; | ||||
handler(); | |||||
handler.resume(); | |||||
} | } | ||||
} | } | ||||
bool state_future_t::has_handler() const | bool state_future_t::has_handler() const | ||||
{ | { | ||||
return _initor != nullptr || _coro != nullptr; | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
return _coro != nullptr || _initor != nullptr; | |||||
} | |||||
bool state_future_t::is_ready() const | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
return _exception != nullptr || _has_value || !_is_awaitor; | |||||
} | } | ||||
void state_future_t::set_exception(std::exception_ptr e) | void state_future_t::set_exception(std::exception_ptr e) | ||||
if (sch != nullptr) | if (sch != nullptr) | ||||
sch->add_ready(this); | sch->add_ready(this); | ||||
} | } | ||||
bool state_t<void>::is_ready() const | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
return _is_awaitor == false || _has_value || _exception != nullptr; | |||||
} | |||||
void state_t<void>::future_await_resume() | void state_t<void>::future_await_resume() | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | scoped_lock<lock_type> __guard(this->_mtx); | ||||
if (this->_exception) | if (this->_exception) | ||||
std::rethrow_exception(std::move(this->_exception)); | std::rethrow_exception(std::move(this->_exception)); | ||||
if (!this->_has_value) | |||||
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() |
namespace resumef | namespace resumef | ||||
{ | { | ||||
struct state_base_t : public counted_t<state_base_t> | |||||
struct state_base_t | |||||
{ | { | ||||
RF_API virtual ~state_base_t(); | RF_API virtual ~state_base_t(); | ||||
private: | |||||
std::atomic<intptr_t> _count{ 0 }; | |||||
public: | |||||
void lock() | |||||
{ | |||||
++_count; | |||||
} | |||||
void unlock() | |||||
{ | |||||
if (--_count == 0) | |||||
delete this; | |||||
} | |||||
protected: | protected: | ||||
scheduler_t* _scheduler = nullptr; | scheduler_t* _scheduler = nullptr; | ||||
//可能来自协程里的promise产生的,则经过co_await操作后,_coro在初始时不会为nullptr。 | //可能来自协程里的promise产生的,则经过co_await操作后,_coro在初始时不会为nullptr。 | ||||
protected: | protected: | ||||
mutable lock_type _mtx; | mutable lock_type _mtx; | ||||
coroutine_handle<> _initor; | coroutine_handle<> _initor; | ||||
std::exception_ptr _exception; | |||||
state_future_t* _parent = nullptr; | state_future_t* _parent = nullptr; | ||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
intptr_t _id; | intptr_t _id; | ||||
#endif | #endif | ||||
std::exception_ptr _exception; | |||||
bool _has_value = false; | |||||
bool _is_awaitor; | bool _is_awaitor; | ||||
public: | public: | ||||
state_future_t() | state_future_t() | ||||
virtual void resume() override; | virtual void resume() override; | ||||
virtual bool has_handler() const override; | virtual bool has_handler() const override; | ||||
virtual bool is_ready() const override; | |||||
scheduler_t* get_scheduler() const | scheduler_t* get_scheduler() const | ||||
{ | { | ||||
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); | ||||
bool future_await_ready() | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
return _has_value; | |||||
} | |||||
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_initial_suspend(coroutine_handle<_PromiseT> handler); | void promise_initial_suspend(coroutine_handle<_PromiseT> handler); | ||||
using state_future_t::state_future_t; | using state_future_t::state_future_t; | ||||
using state_future_t::lock_type; | using state_future_t::lock_type; | ||||
using value_type = _Ty; | using value_type = _Ty; | ||||
protected: | |||||
std::optional<value_type> _value; | |||||
public: | |||||
virtual bool is_ready() const override | |||||
private: | |||||
union union_value_type | |||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
return _is_awaitor == false || _value.has_value() || _exception != nullptr; | |||||
} | |||||
value_type _value; | |||||
char _[1]; | |||||
bool future_await_ready() | |||||
union_value_type() {} | |||||
~union_value_type() {} | |||||
}; | |||||
union_value_type uv; | |||||
public: | |||||
~state_t() | |||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
return _value.has_value(); | |||||
if (_has_value) | |||||
uv._value.~value_type(); | |||||
} | } | ||||
auto future_await_resume() -> value_type; | auto future_await_resume() -> value_type; | ||||
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, value_type val); | void promise_yield_value(_PromiseT* promise, value_type val); | ||||
{ | { | ||||
using state_future_t::state_future_t; | using state_future_t::state_future_t; | ||||
using state_future_t::lock_type; | using state_future_t::lock_type; | ||||
protected: | |||||
std::atomic<bool> _has_value{ false }; | |||||
public: | public: | ||||
virtual bool is_ready() const override; | |||||
bool future_await_ready() | |||||
{ | |||||
return _has_value; | |||||
} | |||||
void future_await_resume(); | void future_await_resume(); | ||||
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); |
this->_parent = parent_state; | this->_parent = parent_state; | ||||
this->_scheduler = sch; | this->_scheduler = sch; | ||||
} | } | ||||
if (this->_coro == nullptr) | |||||
if (_coro == nullptr) | |||||
this->_coro = handler; | this->_coro = handler; | ||||
if (sch != nullptr) | if (sch != nullptr) | ||||
sch->add_await(this); | sch->add_await(this); | ||||
} | } | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | scoped_lock<lock_type> __guard(this->_mtx); | ||||
this->_value = std::move(val); | |||||
if (this->_has_value) | |||||
{ | |||||
this->uv._value = std::move(val); | |||||
} | |||||
else | |||||
{ | |||||
this->_has_value = true; | |||||
new(&this->uv._value) value_type(std::move(val)); | |||||
} | |||||
coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise); | coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise); | ||||
if (!handler.done()) | if (!handler.done()) | ||||
scoped_lock<lock_type> __guard(this->_mtx); | scoped_lock<lock_type> __guard(this->_mtx); | ||||
if (this->_exception) | if (this->_exception) | ||||
std::rethrow_exception(std::move(this->_exception)); | std::rethrow_exception(std::move(this->_exception)); | ||||
return std::move(this->_value.value()); | |||||
if (!this->_has_value) | |||||
std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready})); | |||||
return std::move(this->uv._value); | |||||
} | } | ||||
template<typename _Ty> | template<typename _Ty> | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(this->_mtx); | scoped_lock<lock_type> __guard(this->_mtx); | ||||
this->_value = std::move(val); | |||||
if (this->_has_value) | |||||
{ | |||||
this->uv._value = std::move(val); | |||||
} | |||||
else | |||||
{ | |||||
this->_has_value = true; | |||||
new(&this->uv._value) value_type(std::move(val)); | |||||
} | |||||
scheduler_t* sch = this->get_scheduler(); | scheduler_t* sch = this->get_scheduler(); | ||||
if (sch != nullptr) | if (sch != nullptr) | ||||
sch->add_ready(this); | sch->add_ready(this); |
#include "librf.h" | #include "librf.h" | ||||
using namespace resumef; | |||||
template<class _Ctype> | template<class _Ctype> | ||||
void callback_get_long(int64_t val, _Ctype&& cb) | void callback_get_long(int64_t val, _Ctype&& cb) | ||||
{ | { | ||||
} | } | ||||
//这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | //这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | ||||
auto async_get_long(int64_t val) | |||||
future_t<int64_t> async_get_long(int64_t val) | |||||
{ | { | ||||
resumef::awaitable_t<int64_t> st; | |||||
callback_get_long(val, [st](int64_t val) | |||||
/* | |||||
void* frame_ptr = _coro_frame_ptr(); | |||||
size_t frame_size = _coro_frame_size(); | |||||
std::cout << "test_routine_use_timer" << std::endl; | |||||
std::cout << "frame point=" << frame_ptr << ", size=" << frame_size << ", promise_size=" << promise_align_size<>() << std::endl; | |||||
auto handler = coroutine_handle<promise_t<>>::from_address(frame_ptr); | |||||
auto st = handler.promise()._state; | |||||
scheduler_t* sch = st->get_scheduler(); | |||||
auto parent = st->get_parent(); | |||||
std::cout << "st=" << st.get() << ", scheduler=" << sch << ", parent=" << parent << std::endl; | |||||
*/ | |||||
resumef::awaitable_t<int64_t> awaitable; | |||||
callback_get_long(val, [awaitable](int64_t val) | |||||
{ | { | ||||
st.set_value(val); | |||||
awaitable.set_value(val); | |||||
}); | }); | ||||
return st.get_future(); | |||||
return awaitable.get_future(); | |||||
} | } | ||||
resumef::future_t<> wait_get_long(int64_t val) | |||||
future_t<> wait_get_long(int64_t val) | |||||
{ | { | ||||
co_await async_get_long(val); | co_await async_get_long(val); | ||||
} | } | ||||
//这种情况下,会生成对应的 frame-context,一个promise_type被内嵌在frame-context里 | //这种情况下,会生成对应的 frame-context,一个promise_type被内嵌在frame-context里 | ||||
resumef::future_t<> resumable_get_long(int64_t val) | |||||
future_t<> resumable_get_long(int64_t val) | |||||
{ | { | ||||
std::cout << val << std::endl; | std::cout << val << std::endl; | ||||
val = co_await async_get_long(val); | val = co_await async_get_long(val); | ||||
std::cout << val << std::endl; | std::cout << val << std::endl; | ||||
} | } | ||||
resumef::future_t<int64_t> loop_get_long(int64_t val) | |||||
future_t<int64_t> loop_get_long(int64_t val) | |||||
{ | { | ||||
std::cout << val << std::endl; | std::cout << val << std::endl; | ||||
for (int i = 0; i < 5; ++i) | for (int i = 0; i < 5; ++i) |
static const intptr_t N = 3000000; | static const intptr_t N = 3000000; | ||||
//static const int N = 10; | //static const int N = 10; | ||||
auto yield_switch(intptr_t coro) -> std::experimental::generator<intptr_t> | |||||
auto yield_switch(intptr_t coro) -> resumef::generator_t<intptr_t> | |||||
{ | { | ||||
for (intptr_t i = 0; i < N / coro; ++i) | for (intptr_t i = 0; i < N / coro; ++i) | ||||
co_yield i; | co_yield i; | ||||
for (intptr_t i = 0; i < coro; ++i) | for (intptr_t i = 0; i < coro; ++i) | ||||
{ | { | ||||
//go yield_switch(coro); | //go yield_switch(coro); | ||||
go [=] ()->std::experimental::generator<intptr_t> | |||||
go [=] ()->resumef::generator_t<intptr_t> | |||||
{ | { | ||||
for (intptr_t i = 0; i < N / coro; ++i) | for (intptr_t i = 0; i < N / coro; ++i) | ||||
co_yield i; | co_yield i; |
future_t<> test_routine_use_timer() | future_t<> test_routine_use_timer() | ||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
void* frame_ptr = _coro_frame_ptr(); | |||||
size_t frame_size = _coro_frame_size(); | |||||
std::cout << "test_routine_use_timer" << std::endl; | std::cout << "test_routine_use_timer" << std::endl; | ||||
std::cout << "frame point=" << frame_ptr << ", size=" << frame_size << ", promise_size=" << promise_align_size<>() << std::endl; | |||||
auto handler = coroutine_handle<promise_t<>>::from_address(frame_ptr); | |||||
auto st = handler.promise()._state; | |||||
scheduler_t* sch = st->get_scheduler(); | |||||
auto parent = st->get_parent(); | |||||
std::cout << "st=" << st.get() << ", scheduler=" << sch << ", parent=" << parent << std::endl; | |||||
for (size_t i = 0; i < 3; ++i) | for (size_t i = 0; i < 3; ++i) | ||||
{ | { | ||||
void resumable_main_routine() | void resumable_main_routine() | ||||
{ | { | ||||
go test_routine_use_timer_2(); | |||||
//go test_routine_use_timer(); | |||||
//go test_routine_use_timer_2(); | |||||
go test_routine_use_timer(); | |||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); | ||||
} | } |
{ | { | ||||
(void)argc; | (void)argc; | ||||
(void)argv; | (void)argv; | ||||
//resumable_main_routine(); | |||||
if (argc > 1) | |||||
resumable_main_benchmark_asio_client(atoi(argv[1])); | |||||
else | |||||
resumable_main_benchmark_asio_server(); | |||||
//if (argc > 1) | |||||
// resumable_main_benchmark_asio_client(atoi(argv[1])); | |||||
//else | |||||
// resumable_main_benchmark_asio_server(); | |||||
//resumable_main_cb(); | |||||
resumable_main_cb(); | |||||
//resumable_main_modern_cb(); | //resumable_main_modern_cb(); | ||||
//resumable_main_suspend_always(); | //resumable_main_suspend_always(); | ||||
//resumable_main_yield_return(); | //resumable_main_yield_return(); |