@@ -44,6 +44,24 @@ namespace resumef | |||
template<class... _Mutexes> | |||
using scoped_lock = std::lock_guard<_Mutexes...>; | |||
#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 | |||
{ |
@@ -5,9 +5,6 @@ | |||
namespace resumef | |||
{ | |||
template <typename T = void> | |||
struct promise_t; | |||
template <typename T> | |||
struct future_impl_t | |||
{ | |||
@@ -34,7 +31,7 @@ namespace resumef | |||
{ | |||
return _state->_ready; | |||
} | |||
void await_suspend(std::experimental::coroutine_handle<> resume_cb) | |||
void await_suspend(coroutine_handle<> resume_cb) | |||
{ | |||
_state->await_suspend(resume_cb); | |||
} | |||
@@ -147,6 +144,15 @@ namespace resumef | |||
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> | |||
struct promise_impl_t | |||
{ | |||
@@ -159,9 +165,22 @@ namespace resumef | |||
promise_impl_t() | |||
: _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 & operator = (const promise_impl_t&) = delete; | |||
@@ -196,37 +215,18 @@ namespace resumef | |||
// 2、通过await启动另外一个子函数 | |||
// (1)情况下,无法区分是否已经拥有的resume_cb,可以特殊处理 | |||
// (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的对象,本协程已经准备好了删除了 | |||
std::experimental::suspend_never final_suspend() noexcept | |||
auto final_suspend() noexcept | |||
{ | |||
_state->final_suspend(); | |||
return{}; | |||
return std::experimental::suspend_never{}; | |||
} | |||
//返回与之关联的future对象 | |||
@@ -326,7 +326,7 @@ namespace resumef | |||
{ | |||
return _state->_ready; | |||
} | |||
void await_suspend(std::experimental::coroutine_handle<> resume_cb) | |||
void await_suspend(coroutine_handle<> resume_cb) | |||
{ | |||
_state->await_suspend(resume_cb); | |||
} | |||
@@ -341,5 +341,42 @@ namespace resumef | |||
}; | |||
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 | |||
{ | |||
} | |||
} | |||
@@ -36,6 +36,7 @@ namespace resumef | |||
} | |||
virtual bool go_next(scheduler * schdler) override | |||
{ | |||
_state->current_scheduler(schdler); | |||
_state->resume(); | |||
return false; | |||
} | |||
@@ -61,7 +62,8 @@ namespace resumef | |||
// Set all members first as calling coroutine may reset stuff here. | |||
_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_) | |||
@@ -73,6 +75,7 @@ namespace resumef | |||
// Set all members first as calling coroutine may reset stuff here. | |||
_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)); | |||
} | |||
} |
@@ -112,6 +112,7 @@ namespace resumef | |||
virtual bool go_next(scheduler * schdler) override | |||
{ | |||
auto * _state = _future._state.get(); | |||
_state->current_scheduler(schdler); | |||
_state->resume(); | |||
return !_state->ready() && !_state->_done; | |||
} |
@@ -9,6 +9,7 @@ std::atomic<intptr_t> g_resumef_evtctx_count = 0; | |||
namespace resumef | |||
{ | |||
static const char * future_error_string[(size_t)future_error::max__] | |||
{ | |||
"none", |
@@ -6,13 +6,19 @@ | |||
namespace resumef | |||
{ | |||
template <typename T = void> | |||
struct promise_t; | |||
struct state_base | |||
{ | |||
protected: | |||
std::mutex _mtx; //for value, _exception | |||
RF_API void set_value_none_lock(); | |||
private: | |||
void * _this_promise = nullptr; | |||
scheduler * _current_scheduler = nullptr; | |||
public: | |||
std::experimental::coroutine_handle<> _coro; | |||
coroutine_handle<> _coro; | |||
std::atomic<intptr_t> _count = 0; // tracks reference count of state object | |||
std::exception_ptr _exception; | |||
@@ -75,9 +81,13 @@ namespace resumef | |||
{ | |||
if (_coro) | |||
{ | |||
std::cout << "scheduler=" << current_scheduler() | |||
<< ",coro=" << _coro.address() | |||
<< ",this_promise=" << this_promise() | |||
<< ",parent_promise=" << parent_promise() << std::endl; | |||
auto coro = _coro; | |||
_coro = nullptr; | |||
//std::cout << "resume from " << coro.address() << " on thread " << std::this_thread::get_id() << std::endl; | |||
coro(); | |||
} | |||
} | |||
@@ -94,6 +104,27 @@ namespace resumef | |||
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交互的接口 | |||
@@ -101,7 +132,7 @@ namespace resumef | |||
{ | |||
return _ready; | |||
} | |||
void await_suspend(std::experimental::coroutine_handle<> resume_cb) | |||
void await_suspend(coroutine_handle<> resume_cb) | |||
{ | |||
_coro = resume_cb; | |||
} | |||
@@ -162,6 +193,11 @@ namespace resumef | |||
state_base::reset_none_lock(); | |||
_value = value_type{}; | |||
} | |||
promise_t<_Ty> * parent_promise() const | |||
{ | |||
return reinterpret_cast<promise_t<_Ty> *>(state_base::parent_promise()); | |||
} | |||
}; | |||
template<> | |||
@@ -192,6 +228,11 @@ namespace resumef | |||
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 |
@@ -12,24 +12,31 @@ using namespace resumef; | |||
future_vt test_routine_use_timer() | |||
{ | |||
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); | |||
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() | |||
{ | |||
std::cout << "test_routine_use_timer_2" << std::endl; | |||
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(); | |||
std::cout << "2:frame=" << _coro_frame_ptr() << ",promise=" << _coro_promise_ptr(void) << std::endl << std::endl; | |||
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() | |||
{ | |||
go test_routine_use_timer_2(); | |||
//test_routine_use_timer(); | |||
//go test_routine_use_timer(); | |||
g_scheduler.run_until_notask(); | |||
} |
@@ -19,7 +19,7 @@ extern void resumable_main_benchmark_mem(); | |||
int main(int argc, const char * argv[]) | |||
{ | |||
resumable_main_exception(); | |||
resumable_main_routine(); | |||
return 0; | |||
resumable_main_yield_return(); |