template<class... _Mutexes> | template<class... _Mutexes> | ||||
using scoped_lock = std::lock_guard<_Mutexes...>; | using scoped_lock = std::lock_guard<_Mutexes...>; | ||||
#endif | #endif | ||||
template<typename _PromiseT = void> | |||||
using coroutine_handle = std::experimental::coroutine_handle<_PromiseT>; | |||||
template<typename _PromiseT = void> | |||||
inline void * _coro_function_ptr(coroutine_handle<> coro) | |||||
{ | |||||
auto frame_prefix = (coroutine_handle<void>::_Resumable_frame_prefix*)coro.address(); | |||||
return reinterpret_cast<void *>(frame_prefix->_Fn); | |||||
} | |||||
template<typename _PromiseT> | |||||
inline _PromiseT * _coro_promise_ptr__(void * _Ptr) | |||||
{ | |||||
using coroutine_instance = coroutine_handle<_PromiseT>; | |||||
return reinterpret_cast<_PromiseT *>(reinterpret_cast<char *>(_Ptr) - coroutine_instance::_ALIGNED_SIZE); | |||||
} | |||||
#define _coro_promise_ptr(T) _coro_promise_ptr__<resumef::promise_t<T> >(_coro_frame_ptr()) | |||||
enum struct future_error | enum struct future_error | ||||
{ | { |
namespace resumef | namespace resumef | ||||
{ | { | ||||
template <typename T = void> | |||||
struct promise_t; | |||||
template <typename T> | template <typename T> | ||||
struct future_impl_t | struct future_impl_t | ||||
{ | { | ||||
{ | { | ||||
return _state->_ready; | return _state->_ready; | ||||
} | } | ||||
void await_suspend(std::experimental::coroutine_handle<> resume_cb) | |||||
void await_suspend(coroutine_handle<> resume_cb) | |||||
{ | { | ||||
_state->await_suspend(resume_cb); | _state->await_suspend(resume_cb); | ||||
} | } | ||||
using future_vt = future_t<void>; | using future_vt = future_t<void>; | ||||
template<class state_type> | |||||
struct awaitor_initial_suspend | |||||
{ | |||||
counted_ptr<state_type> _state; | |||||
bool await_ready() noexcept; | |||||
void await_suspend(coroutine_handle<> resume_cb) noexcept; | |||||
void await_resume() noexcept; | |||||
}; | |||||
template <typename T> | template <typename T> | ||||
struct promise_impl_t | struct promise_impl_t | ||||
{ | { | ||||
promise_impl_t() | promise_impl_t() | ||||
: _state(make_counted<state_type>()) | : _state(make_counted<state_type>()) | ||||
{ | { | ||||
_state->this_promise(this); | |||||
} | |||||
promise_impl_t(promise_impl_t&& _Right) | |||||
: _state(std::move(_Right._state)) | |||||
{ | |||||
_state->this_promise(this); | |||||
} | |||||
promise_impl_t & operator = (promise_impl_t&& _Right) | |||||
{ | |||||
if (this != _Right) | |||||
{ | |||||
_state = std::move(_Right._state); | |||||
_state->this_promise(this); | |||||
} | |||||
return *this; | |||||
} | } | ||||
promise_impl_t(promise_impl_t&&) = default; | |||||
promise_impl_t & operator = (promise_impl_t&&) = default; | |||||
promise_impl_t(const promise_impl_t&) = delete; | promise_impl_t(const promise_impl_t&) = delete; | ||||
promise_impl_t & operator = (const promise_impl_t&) = delete; | promise_impl_t & operator = (const promise_impl_t&) = delete; | ||||
// 2、通过await启动另外一个子函数 | // 2、通过await启动另外一个子函数 | ||||
// (1)情况下,无法区分是否已经拥有的resume_cb,可以特殊处理 | // (1)情况下,无法区分是否已经拥有的resume_cb,可以特殊处理 | ||||
// (2)情况下,返回准备好了,让编译器继续运行 | // (2)情况下,返回准备好了,让编译器继续运行 | ||||
std::experimental::suspend_never initial_suspend() noexcept | |||||
auto initial_suspend() noexcept | |||||
{ | { | ||||
return {}; | |||||
/* | |||||
struct AWaitor | |||||
{ | |||||
counted_ptr<state_tt> _state; | |||||
bool await_ready() _NOEXCEPT | |||||
{ | |||||
return false; | |||||
} | |||||
void await_suspend(std::experimental::coroutine_handle<> resume_cb) _NOEXCEPT | |||||
{ | |||||
_state->await_suspend(resume_cb); | |||||
_state->run_in_coroutine(this_coroutine()); | |||||
} | |||||
void await_resume() _NOEXCEPT | |||||
{ | |||||
} | |||||
}; | |||||
return AWaitor{ _state }; | |||||
*/ | |||||
return std::experimental::suspend_never{}; | |||||
//return awaitor_initial_suspend<state_type>{ _state }; | |||||
} | } | ||||
//这在一个协程被销毁之时调用。 | //这在一个协程被销毁之时调用。 | ||||
//我们选择不挂起协程,只是通知state的对象,本协程已经准备好了删除了 | //我们选择不挂起协程,只是通知state的对象,本协程已经准备好了删除了 | ||||
std::experimental::suspend_never final_suspend() noexcept | |||||
auto final_suspend() noexcept | |||||
{ | { | ||||
_state->final_suspend(); | _state->final_suspend(); | ||||
return{}; | |||||
return std::experimental::suspend_never{}; | |||||
} | } | ||||
//返回与之关联的future对象 | //返回与之关联的future对象 | ||||
{ | { | ||||
return _state->_ready; | return _state->_ready; | ||||
} | } | ||||
void await_suspend(std::experimental::coroutine_handle<> resume_cb) | |||||
void await_suspend(coroutine_handle<> resume_cb) | |||||
{ | { | ||||
_state->await_suspend(resume_cb); | _state->await_suspend(resume_cb); | ||||
} | } | ||||
}; | }; | ||||
using awaitable_vt = awaitable_t<void>; | using awaitable_vt = awaitable_t<void>; | ||||
inline promise_t<void> * state_base::parent_promise() const | |||||
{ | |||||
if (_coro) return _coro_promise_ptr__<promise_t<void>>(_coro.address()); | |||||
return nullptr; | |||||
} | |||||
inline scheduler * state_base::parent_scheduler() const | |||||
{ | |||||
auto promise_ = parent_promise(); | |||||
if (promise_) | |||||
return promise_->_state->current_scheduler(); | |||||
return nullptr; | |||||
} | |||||
template<class state_type> | |||||
bool awaitor_initial_suspend<state_type>::await_ready() noexcept | |||||
{ | |||||
return false; | |||||
} | |||||
template<class state_type> | |||||
void awaitor_initial_suspend<state_type>::await_suspend(coroutine_handle<> resume_cb) noexcept | |||||
{ | |||||
_state->await_suspend(resume_cb); | |||||
scheduler * sch_ = _state->parent_scheduler(); | |||||
if (sch_ != nullptr) | |||||
{ | |||||
_state->current_scheduler(sch_); | |||||
_state->resume(); | |||||
} | |||||
} | |||||
template<class state_type> | |||||
void awaitor_initial_suspend<state_type>::await_resume() noexcept | |||||
{ | |||||
} | |||||
} | } | ||||
} | } | ||||
virtual bool go_next(scheduler * schdler) override | virtual bool go_next(scheduler * schdler) override | ||||
{ | { | ||||
_state->current_scheduler(schdler); | |||||
_state->resume(); | _state->resume(); | ||||
return false; | return false; | ||||
} | } | ||||
// Set all members first as calling coroutine may reset stuff here. | // Set all members first as calling coroutine may reset stuff here. | ||||
_ready = true; | _ready = true; | ||||
this_scheduler()->push_task_internal(new awaitable_task_t<state_base>(this)); | |||||
auto sch_ = this->parent_scheduler(); | |||||
sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||||
} | } | ||||
void state_base::set_exception(std::exception_ptr && e_) | void state_base::set_exception(std::exception_ptr && e_) | ||||
// Set all members first as calling coroutine may reset stuff here. | // Set all members first as calling coroutine may reset stuff here. | ||||
_ready = true; | _ready = true; | ||||
this_scheduler()->push_task_internal(new awaitable_task_t<state_base>(this)); | |||||
auto sch_ = this->parent_scheduler(); | |||||
sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||||
} | } | ||||
} | } |
virtual bool go_next(scheduler * schdler) override | virtual bool go_next(scheduler * schdler) override | ||||
{ | { | ||||
auto * _state = _future._state.get(); | auto * _state = _future._state.get(); | ||||
_state->current_scheduler(schdler); | |||||
_state->resume(); | _state->resume(); | ||||
return !_state->ready() && !_state->_done; | return !_state->ready() && !_state->_done; | ||||
} | } |
namespace resumef | namespace resumef | ||||
{ | { | ||||
static const char * future_error_string[(size_t)future_error::max__] | static const char * future_error_string[(size_t)future_error::max__] | ||||
{ | { | ||||
"none", | "none", |
namespace resumef | namespace resumef | ||||
{ | { | ||||
template <typename T = void> | |||||
struct promise_t; | |||||
struct state_base | struct state_base | ||||
{ | { | ||||
protected: | protected: | ||||
std::mutex _mtx; //for value, _exception | std::mutex _mtx; //for value, _exception | ||||
RF_API void set_value_none_lock(); | RF_API void set_value_none_lock(); | ||||
private: | |||||
void * _this_promise = nullptr; | |||||
scheduler * _current_scheduler = nullptr; | |||||
public: | public: | ||||
std::experimental::coroutine_handle<> _coro; | |||||
coroutine_handle<> _coro; | |||||
std::atomic<intptr_t> _count = 0; // tracks reference count of state object | std::atomic<intptr_t> _count = 0; // tracks reference count of state object | ||||
std::exception_ptr _exception; | std::exception_ptr _exception; | ||||
{ | { | ||||
if (_coro) | if (_coro) | ||||
{ | { | ||||
std::cout << "scheduler=" << current_scheduler() | |||||
<< ",coro=" << _coro.address() | |||||
<< ",this_promise=" << this_promise() | |||||
<< ",parent_promise=" << parent_promise() << std::endl; | |||||
auto coro = _coro; | auto coro = _coro; | ||||
_coro = nullptr; | _coro = nullptr; | ||||
//std::cout << "resume from " << coro.address() << " on thread " << std::this_thread::get_id() << std::endl; | |||||
coro(); | coro(); | ||||
} | } | ||||
} | } | ||||
delete this; | delete this; | ||||
} | } | ||||
promise_t<void> * parent_promise() const; | |||||
scheduler * parent_scheduler() const; | |||||
void * this_promise() const | |||||
{ | |||||
return _this_promise; | |||||
} | |||||
void this_promise(void * promise_) | |||||
{ | |||||
_this_promise = promise_; | |||||
} | |||||
scheduler * current_scheduler() const | |||||
{ | |||||
return _current_scheduler; | |||||
} | |||||
void current_scheduler(scheduler * sch_) | |||||
{ | |||||
_current_scheduler = sch_; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | //------------------------------------------------------------------------------------------ | ||||
//以下是通过future_t/promise_t, 与编译器生成的resumable function交互的接口 | //以下是通过future_t/promise_t, 与编译器生成的resumable function交互的接口 | ||||
{ | { | ||||
return _ready; | return _ready; | ||||
} | } | ||||
void await_suspend(std::experimental::coroutine_handle<> resume_cb) | |||||
void await_suspend(coroutine_handle<> resume_cb) | |||||
{ | { | ||||
_coro = resume_cb; | _coro = resume_cb; | ||||
} | } | ||||
state_base::reset_none_lock(); | state_base::reset_none_lock(); | ||||
_value = value_type{}; | _value = value_type{}; | ||||
} | } | ||||
promise_t<_Ty> * parent_promise() const | |||||
{ | |||||
return reinterpret_cast<promise_t<_Ty> *>(state_base::parent_promise()); | |||||
} | |||||
}; | }; | ||||
template<> | template<> | ||||
reset_none_lock(); | reset_none_lock(); | ||||
} | } | ||||
promise_t<void> * parent_promise() const | |||||
{ | |||||
return reinterpret_cast<promise_t<void> *>(state_base::parent_promise()); | |||||
} | |||||
}; | }; | ||||
// counted_ptr is similar to shared_ptr but allows explicit control | // counted_ptr is similar to shared_ptr but allows explicit control |
future_vt test_routine_use_timer() | future_vt test_routine_use_timer() | ||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
std::cout << "test_routine_use_timer" << std::endl; | |||||
for (size_t i = 0; i < 10; ++i) | |||||
for (size_t i = 0; i < 3; ++i) | |||||
{ | { | ||||
co_await resumef::sleep_for(100ms); | co_await resumef::sleep_for(100ms); | ||||
std::cout << "timer after 100ms." << std::endl; | |||||
std::cout << "timer after 100ms" << std::endl; | |||||
std::cout << "1:frame=" << _coro_frame_ptr() << ",promise=" << _coro_promise_ptr(void) << std::endl << std::endl; | |||||
} | } | ||||
} | } | ||||
future_vt test_routine_use_timer_2() | future_vt test_routine_use_timer_2() | ||||
{ | { | ||||
std::cout << "test_routine_use_timer_2" << std::endl; | |||||
co_await test_routine_use_timer(); | co_await test_routine_use_timer(); | ||||
std::cout << "2:frame=" << _coro_frame_ptr() << ",promise=" << _coro_promise_ptr(void) << std::endl << std::endl; | |||||
co_await test_routine_use_timer(); | co_await test_routine_use_timer(); | ||||
std::cout << "2:frame=" << _coro_frame_ptr() << ",promise=" << _coro_promise_ptr(void) << std::endl << std::endl; | |||||
co_await test_routine_use_timer(); | co_await test_routine_use_timer(); | ||||
std::cout << "2:frame=" << _coro_frame_ptr() << ",promise=" << _coro_promise_ptr(void) << std::endl << std::endl; | |||||
} | } | ||||
void resumable_main_routine() | void resumable_main_routine() | ||||
{ | { | ||||
go test_routine_use_timer_2(); | go test_routine_use_timer_2(); | ||||
//test_routine_use_timer(); | |||||
//go test_routine_use_timer(); | |||||
g_scheduler.run_until_notask(); | g_scheduler.run_until_notask(); | ||||
} | } |
int main(int argc, const char * argv[]) | int main(int argc, const char * argv[]) | ||||
{ | { | ||||
resumable_main_exception(); | |||||
resumable_main_routine(); | |||||
return 0; | return 0; | ||||
resumable_main_yield_return(); | resumable_main_yield_return(); |