std::atomic<intptr_t> g_echo_count = 0; | std::atomic<intptr_t> g_echo_count = 0; | ||||
future_vt RunEchoSession(tcp::socket socket) | |||||
future_t<> RunEchoSession(tcp::socket socket) | |||||
{ | { | ||||
std::size_t bytes_transferred = 0; | std::size_t bytes_transferred = 0; | ||||
std::array<char, BUF_SIZE> buffer; | std::array<char, BUF_SIZE> buffer; | ||||
{ | { | ||||
for (size_t idx = 0; idx < socketes.c.size(); ++idx) | for (size_t idx = 0; idx < socketes.c.size(); ++idx) | ||||
{ | { | ||||
go[&, idx]() -> future_vt | |||||
go[&, idx]() -> future_t<> | |||||
{ | { | ||||
for (;;) | for (;;) | ||||
{ | { | ||||
//---------------------------------------------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------------------------------------------- | ||||
future_vt RunPipelineEchoClient(asio::io_service & ios, tcp::resolver::iterator ep) | |||||
future_t<> RunPipelineEchoClient(asio::io_service & ios, tcp::resolver::iterator ep) | |||||
{ | { | ||||
std::shared_ptr<tcp::socket> sptr = std::make_shared<tcp::socket>(ios); | std::shared_ptr<tcp::socket> sptr = std::make_shared<tcp::socket>(ios); | ||||
#if _HAS_CXX17 | #if _HAS_CXX17 | ||||
future_vt RunPingPongEchoClient(asio::io_service & ios, tcp::resolver::iterator ep) | |||||
future_t<> RunPingPongEchoClient(asio::io_service & ios, tcp::resolver::iterator ep) | |||||
{ | { | ||||
tcp::socket socket_{ ios }; | tcp::socket socket_{ ios }; | ||||
const static auto MaxNum = 20000; | const static auto MaxNum = 20000; | ||||
using int_channel_ptr = std::shared_ptr<channel_t<intptr_t>>; | using int_channel_ptr = std::shared_ptr<channel_t<intptr_t>>; | ||||
static future_vt passing_next(int_channel_ptr rd, int_channel_ptr wr) | |||||
static future_t<> passing_next(int_channel_ptr rd, int_channel_ptr wr) | |||||
{ | { | ||||
for (;;) | for (;;) | ||||
{ | { |
#include "src/mutex.h" | #include "src/mutex.h" | ||||
#include "src/channel.h" | #include "src/channel.h" | ||||
#include "src/scheduler.h" | #include "src/scheduler.h" | ||||
#include "src/promise.inl" | |||||
#include "src/sleep.h" | #include "src/sleep.h" | ||||
#include "src/awaitable.h" | |||||
#if _HAS_CXX17 || RESUMEF_USE_BOOST_ANY | #if _HAS_CXX17 || RESUMEF_USE_BOOST_ANY | ||||
#include "src/when.h" | #include "src/when.h" | ||||
#endif | |||||
#endif |
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 | ||||
{ | { | ||||
{ | { | ||||
if (&cp != this) | if (&cp != this) | ||||
{ | { | ||||
_unlock(); | |||||
_lock(cp._p); | |||||
counted_ptr t = cp; | |||||
std::swap(_p, t._p); | |||||
} | } | ||||
return *this; | return *this; | ||||
} | } |
#include <map> | #include <map> | ||||
#include <unordered_map> | #include <unordered_map> | ||||
#include <unordered_set> | #include <unordered_set> | ||||
#include <optional> | |||||
#include <assert.h> | #include <assert.h> | ||||
template<typename _PromiseT = void> | template<typename _PromiseT = void> | ||||
using coroutine_handle = std::experimental::coroutine_handle<_PromiseT>; | 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 error_code | enum struct error_code | ||||
{ | { | ||||
none, | none, | ||||
}; | }; | ||||
const char * get_error_string(error_code fe, const char * classname); | const char * get_error_string(error_code fe, const char * classname); | ||||
//const char * future_error_string[size_t(future_error::max__)]; | |||||
struct future_exception : std::exception | struct future_exception : std::exception | ||||
{ | { | ||||
} | } | ||||
}; | }; | ||||
struct scheduler; | |||||
struct state_base; | |||||
struct scheduler_t; | |||||
struct state_base_t; | |||||
template<class _Ty = void> | |||||
struct future_t; | |||||
using future_vt = future_t<>; | |||||
template<class _Ty = void> | |||||
struct promise_t; | |||||
template<class _Ty = void> | |||||
struct awaitable_t; | |||||
template<class _PromiseT> | |||||
struct is_promise : std::false_type {}; | |||||
template<class _Ty> | |||||
struct is_promise<promise_t<_Ty>> : std::true_type {}; | |||||
template<class _Ty> | |||||
_INLINE_VAR constexpr bool is_promise_v = is_promise<std::remove_cvref_t<_Ty>>::value; | |||||
template<class _PromiseT> | |||||
struct is_future : std::false_type {}; | |||||
template<class _Ty> | |||||
struct is_future<future_t<_Ty>> : std::true_type {}; | |||||
template<class _Ty> | |||||
_INLINE_VAR constexpr bool is_future_v = is_future<std::remove_cvref_t<_Ty>>::value; | |||||
//获得当前线程下的调度器 | //获得当前线程下的调度器 | ||||
scheduler * this_scheduler(); | |||||
scheduler_t* this_scheduler(); | |||||
} | } | ||||
#define co_yield_void co_yield nullptr | #define co_yield_void co_yield nullptr |
namespace resumef | namespace resumef | ||||
{ | { | ||||
template <typename T> | |||||
template<class _Ty> | |||||
struct future_impl_t | struct future_impl_t | ||||
{ | { | ||||
typedef T value_type; | |||||
typedef promise_t<T> promise_type; | |||||
typedef state_t<T> state_type; | |||||
counted_ptr<state_type> _state; | |||||
using value_type = _Ty; | |||||
using state_type = state_t<value_type>; | |||||
using promise_type = promise_t<value_type>; | |||||
using future_type = future_t<value_type>; | |||||
future_impl_t(const counted_ptr<state_type>& state) : _state(state) | |||||
{ | |||||
} | |||||
counted_ptr<state_type> _state; | |||||
// movable, but not copyable | |||||
future_impl_t() = default; | |||||
future_impl_t(future_impl_t&& f) = default; | |||||
future_impl_t & operator = (future_impl_t&& f) = default; | |||||
future_impl_t(counted_ptr<state_type> _st) | |||||
:_state(std::move(_st)) {} | |||||
future_impl_t(const future_impl_t&) = default; | future_impl_t(const future_impl_t&) = default; | ||||
future_impl_t & operator = (const future_impl_t&) = default; | |||||
future_impl_t(future_impl_t&&) = default; | |||||
//------------------------------------------------------------------------------------------ | |||||
//以下是与编译器生成的resumable function交互的接口 | |||||
future_impl_t& operator = (const future_impl_t&) = default; | |||||
future_impl_t& operator = (future_impl_t&&) = default; | |||||
bool await_ready() | bool await_ready() | ||||
{ | { | ||||
return _state->ready(); | |||||
} | |||||
void await_suspend(coroutine_handle<> resume_cb) | |||||
{ | |||||
_state->await_suspend(resume_cb); | |||||
} | |||||
//return_value, return_void只能由派生类去实现 | |||||
//以上是与编译器生成的resumable function交互的接口 | |||||
//------------------------------------------------------------------------------------------ | |||||
//if ready, can get value | |||||
bool ready() | |||||
{ | |||||
return _state->ready(); | |||||
} | |||||
auto & get_value() | |||||
{ | |||||
return _state->get_value(); | |||||
} | |||||
bool is_suspend() const | |||||
{ | |||||
return _state->is_suspend(); | |||||
} | |||||
bool cancellation_requested() const | |||||
{ | |||||
return _state->cancellation_requested(); | |||||
return _state->has_value(); | |||||
} | } | ||||
void set_exception(std::exception_ptr e_) | |||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | |||||
void await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | { | ||||
_state->set_exception(std::move(e_)); | |||||
} | |||||
void cancel() | |||||
{ | |||||
_state->cancel(); | |||||
_PromiseT& promise = handler.promise(); | |||||
scheduler_t* sch = promise._state->_scheduler; | |||||
sch->add_await(_state.get(), handler); | |||||
} | } | ||||
}; | }; | ||||
template <typename T = void> | |||||
struct future_t : public future_impl_t<T> | |||||
template<class _Ty> | |||||
struct future_t : public future_impl_t<_Ty> | |||||
{ | { | ||||
using state_type = typename future_impl_t<T>::state_type; | |||||
using future_impl_t<T>::_state; | |||||
using future_impl_t::future_impl_t; | |||||
using future_impl_t::_state; | |||||
future_t(const counted_ptr<state_type>& state) | |||||
: future_impl_t<T>(state) | |||||
value_type await_resume() | |||||
{ | { | ||||
if (_state->_exception) | |||||
std::rethrow_exception(std::move(_state->_exception)); | |||||
return std::move(_state->_value.value()); | |||||
} | } | ||||
// movable, but not copyable | |||||
future_t(const future_t&) = default; | |||||
future_t(future_t&& f) = default; | |||||
future_t() = default; | |||||
future_t & operator = (const future_t&) = default; | |||||
future_t & operator = (future_t&& f) = default; | |||||
//------------------------------------------------------------------------------------------ | |||||
//以下是与编译器生成的resumable function交互的接口 | |||||
T await_resume() | |||||
{ | |||||
_state->rethrow_if_exception(); | |||||
return std::move(_state->get_value()); | |||||
} | |||||
void return_value(const T& val) | |||||
{ | |||||
_state->set_value(val); | |||||
} | |||||
void return_value(T&& val) | |||||
{ | |||||
_state->set_value(std::forward<T>(val)); | |||||
} | |||||
//以上是与编译器生成的resumable function交互的接口 | |||||
//------------------------------------------------------------------------------------------ | |||||
}; | }; | ||||
template <> | |||||
template<> | |||||
struct future_t<void> : public future_impl_t<void> | struct future_t<void> : public future_impl_t<void> | ||||
{ | { | ||||
using future_impl_t<void>::_state; | |||||
future_t(const counted_ptr<state_type>& state) | |||||
: future_impl_t<void>(state) | |||||
{ | |||||
} | |||||
// movable, but not copyable | |||||
future_t(const future_t&) = default; | |||||
future_t(future_t&& f) = default; | |||||
future_t() = default; | |||||
future_t & operator = (const future_t&) = default; | |||||
future_t & operator = (future_t&& f) = default; | |||||
//------------------------------------------------------------------------------------------ | |||||
//以下是与编译器生成的resumable function交互的接口 | |||||
using future_impl_t::future_impl_t; | |||||
using future_impl_t::_state; | |||||
void await_resume() | void await_resume() | ||||
{ | { | ||||
_state->rethrow_if_exception(); | |||||
return _state->get_value(); | |||||
if (_state->_exception) | |||||
std::rethrow_exception(std::move(_state->_exception)); | |||||
} | } | ||||
void return_void() | |||||
{ | |||||
_state->set_value(); | |||||
} | |||||
//以上是与编译器生成的resumable function交互的接口 | |||||
//------------------------------------------------------------------------------------------ | |||||
}; | }; | ||||
using future_vt = future_t<void>; | |||||
template <typename T> | |||||
struct promise_impl_t | |||||
{ | |||||
typedef future_t<T> future_type; | |||||
typedef state_t<T> state_type; | |||||
counted_ptr<state_type> _state; | |||||
// movable not copyable | |||||
promise_impl_t() | |||||
: _state(make_counted<state_type>()) | |||||
{ | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
_state->this_promise(this); | |||||
#endif | |||||
} | |||||
promise_impl_t(promise_impl_t&& _Right) noexcept | |||||
: _state(std::move(_Right._state)) | |||||
{ | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
_state->this_promise(this); | |||||
#endif | |||||
} | |||||
promise_impl_t & operator = (promise_impl_t&& _Right) noexcept | |||||
{ | |||||
if (this != _Right) | |||||
{ | |||||
_state = std::move(_Right._state); | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
_state->this_promise(this); | |||||
#endif | |||||
} | |||||
return *this; | |||||
} | |||||
promise_impl_t(const promise_impl_t&) = delete; | |||||
promise_impl_t & operator = (const promise_impl_t&) = delete; | |||||
//这个函数,用于callback里,返回关联的future对象 | |||||
//callback里,不应该调用 get_return_object() | |||||
future_type get_future() | |||||
{ | |||||
return future_type(_state); | |||||
} | |||||
// Most functions don't need this but timers and reads from streams | |||||
// cause multiple callbacks. | |||||
future_type next_future() | |||||
{ | |||||
return future_type(_state); | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
//以下是与编译器生成的resumable function交互的接口 | |||||
//如果在协程外启动一个resumable function,则: | |||||
// 1、即将交给调度器调度 | |||||
// 2、手工获取结果(将来支持) | |||||
// 无论哪种情况,都返回未准备好。则编译器调用await_suspend()获得继续运行的resume_cb | |||||
//如果在协程内启动一个resumable function,则: | |||||
// 1、即将交给调度器调度 | |||||
// 2、通过await启动另外一个子函数 | |||||
// (1)情况下,无法区分是否已经拥有的resume_cb,可以特殊处理 | |||||
// (2)情况下,返回准备好了,让编译器继续运行 | |||||
auto initial_suspend() noexcept | |||||
{ | |||||
return std::experimental::suspend_never{}; | |||||
} | |||||
//这在一个协程被销毁之时调用。 | |||||
//我们选择不挂起协程,只是通知state的对象,本协程已经准备好了删除了 | |||||
auto final_suspend() noexcept | |||||
{ | |||||
_state->final_suspend(); | |||||
return std::experimental::suspend_never{}; | |||||
} | |||||
//返回与之关联的future对象 | |||||
future_type get_return_object() | |||||
{ | |||||
return future_type(_state); | |||||
} | |||||
void set_exception(std::exception_ptr e_) | |||||
{ | |||||
_state->set_exception(std::move(e_)); | |||||
} | |||||
bool cancellation_requested() | |||||
{ | |||||
return _state->cancellation_requested(); | |||||
} | |||||
/* | |||||
void unhandled_exception() | |||||
{ | |||||
std::terminate(); | |||||
} | |||||
*/ | |||||
//return_value/return_void 只能由派生类去实现 | |||||
//以上是与编译器生成的resumable function交互的接口 | |||||
//------------------------------------------------------------------------------------------ | |||||
}; | |||||
template <typename T> | |||||
struct promise_t : public promise_impl_t<T> | |||||
{ | |||||
typedef promise_t<T> promise_type; | |||||
using promise_impl_t<T>::_state; | |||||
//------------------------------------------------------------------------------------------ | |||||
//以下是与编译器生成的resumable function交互的接口 | |||||
void return_value(const T& val) | |||||
{ | |||||
_state->set_value(val); | |||||
} | |||||
void return_value(T&& val) | |||||
{ | |||||
_state->set_value(std::forward<T>(val)); | |||||
} | |||||
void yield_value(const T& val) | |||||
{ | |||||
_state->set_value(val); | |||||
} | |||||
void yield_value(T&& val) | |||||
{ | |||||
_state->set_value(std::forward<T>(val)); | |||||
} | |||||
//以上是与编译器生成的resumable function交互的接口 | |||||
//------------------------------------------------------------------------------------------ | |||||
//兼容std::promise<>用法 | |||||
void set_value(const T& val) | |||||
{ | |||||
_state->set_value(val); | |||||
} | |||||
void set_value(T&& val) | |||||
{ | |||||
_state->set_value(std::forward<T>(val)); | |||||
} | |||||
}; | |||||
template <> | |||||
struct promise_t<void> : public promise_impl_t<void> | |||||
{ | |||||
typedef promise_t<void> promise_type; | |||||
using promise_impl_t<void>::_state; | |||||
//------------------------------------------------------------------------------------------ | |||||
//以下是与编译器生成的resumable function交互的接口 | |||||
void return_void() | |||||
{ | |||||
_state->set_value(); | |||||
} | |||||
//以上是与编译器生成的resumable function交互的接口 | |||||
//------------------------------------------------------------------------------------------ | |||||
//兼容std::promise<>用法 | |||||
void set_value() | |||||
{ | |||||
_state->set_value(); | |||||
} | |||||
}; | |||||
using promise_vt = promise_t<void>; | |||||
/* | |||||
template <typename T = void> | |||||
struct awaitable_t | |||||
{ | |||||
typedef state_t<T> state_type; | |||||
counted_ptr<state_type> _state; | |||||
// movable not copyable | |||||
awaitable_t() | |||||
: _state(make_counted<state_type>()) | |||||
{ | |||||
} | |||||
// movable, but not copyable | |||||
awaitable_t(const awaitable_t&) = delete; | |||||
awaitable_t(awaitable_t&& f) = default; | |||||
awaitable_t & operator = (const awaitable_t&) = delete; | |||||
awaitable_t & operator = (awaitable_t&& f) = default; | |||||
//------------------------------------------------------------------------------------------ | |||||
//以下是与编译器生成的resumable function交互的接口 | |||||
bool await_ready() | |||||
{ | |||||
return _state->ready(); | |||||
} | |||||
void await_suspend(coroutine_handle<> resume_cb) | |||||
{ | |||||
_state->await_suspend(resume_cb); | |||||
} | |||||
T await_resume() | |||||
{ | |||||
_state->rethrow_if_exception(); | |||||
return _state->get_value(); | |||||
} | |||||
//以上是与编译器生成的resumable function交互的接口 | |||||
//------------------------------------------------------------------------------------------ | |||||
}; | |||||
using awaitable_vt = awaitable_t<void>; | |||||
*/ | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
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; | |||||
} | |||||
#endif | |||||
} | } | ||||
namespace resumef | namespace resumef | ||||
{ | { | ||||
task_base::task_base() | |||||
task_base_t::task_base_t() | |||||
: _next_node(nullptr) | : _next_node(nullptr) | ||||
, _prev_node(nullptr) | , _prev_node(nullptr) | ||||
{ | { | ||||
#if RESUMEF_DEBUG_COUNTER | |||||
++g_resumef_task_count; | |||||
#endif | |||||
} | } | ||||
task_base::~task_base() | |||||
task_base_t::~task_base_t() | |||||
{ | { | ||||
#if RESUMEF_DEBUG_COUNTER | |||||
--g_resumef_task_count; | |||||
#endif | |||||
} | } | ||||
} | } |
#include "def.h" | #include "def.h" | ||||
#include "future.h" | #include "future.h" | ||||
#include "promise.h" | |||||
namespace resumef | namespace resumef | ||||
{ | { | ||||
struct task_base; | |||||
struct task_base_t; | |||||
struct task_base | |||||
struct task_base_t | |||||
{ | { | ||||
RF_API task_base(); | |||||
RF_API virtual ~task_base(); | |||||
//如果返回true,则不会调用go_next() | |||||
virtual bool is_suspend() = 0; | |||||
//返回true,表示任务还未完成,后续还需要继续执行 | |||||
//否则,任务从调度器里删除 | |||||
virtual bool go_next(scheduler *) = 0; | |||||
virtual void cancel() = 0; | |||||
virtual void * get_id() = 0; | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
virtual void bind(scheduler *) = 0; | |||||
#endif | |||||
task_base * _next_node; | |||||
task_base * _prev_node; | |||||
RF_API task_base_t(); | |||||
RF_API virtual ~task_base_t(); | |||||
virtual state_base_t * get_state() const = 0; | |||||
task_base_t* _next_node; | |||||
task_base_t* _prev_node; | |||||
}; | }; | ||||
//---------------------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------------------- | ||||
template<class _Ty> | template<class _Ty> | ||||
struct task_t; | struct task_t; | ||||
//task_t接受的是一个experimental::generator<_Ty>类型,是调用一个支持异步的函数后返回的结果 | |||||
template<class _Ty> | |||||
struct task_t<std::experimental::generator<_Ty> > : public task_base | |||||
{ | |||||
typedef std::experimental::generator<_Ty> future_type; | |||||
typedef typename future_type::iterator iterator_type; | |||||
future_type _future; | |||||
iterator_type _iterator; | |||||
bool _ready; | |||||
task_t() | |||||
: _iterator(nullptr) | |||||
, _ready(false) | |||||
{ | |||||
} | |||||
task_t(future_type && f) | |||||
: _future(std::forward<future_type>(f)) | |||||
, _iterator(nullptr) | |||||
, _ready(false) | |||||
{ | |||||
} | |||||
virtual bool is_suspend() override | |||||
{ | |||||
return false; | |||||
} | |||||
virtual bool go_next(scheduler *) override | |||||
{ | |||||
if (!this->_ready) | |||||
{ | |||||
this->_iterator = this->_future.begin(); | |||||
this->_ready = true; | |||||
} | |||||
if (this->_iterator != this->_future.end()) | |||||
{ | |||||
return (++this->_iterator) != this->_future.end(); | |||||
} | |||||
return false; | |||||
} | |||||
virtual void cancel() override | |||||
{ | |||||
} | |||||
virtual void * get_id() override | |||||
{ | |||||
return nullptr; | |||||
} | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
virtual void bind(scheduler *) override | |||||
{ | |||||
} | |||||
#endif | |||||
}; | |||||
template<class _Ty> | template<class _Ty> | ||||
struct task_t<future_t<_Ty> > : public task_base | |||||
struct task_t<future_t<_Ty>> : public task_base_t | |||||
{ | { | ||||
typedef future_t<_Ty> future_type; | |||||
using value_type = _Ty; | |||||
using future_type = future_t<value_type>; | |||||
using state_type = state_t<value_type>; | |||||
future_type _future; | |||||
counted_ptr<state_type> _state; | |||||
task_t() = default; | task_t() = default; | ||||
task_t(future_type && f) | task_t(future_type && f) | ||||
: _future(std::forward<future_type>(f)) | |||||
{ | |||||
} | |||||
//如果返回true,则不会调用go_next() | |||||
// | |||||
//如果第一次运行,则state应该有: | |||||
// _coro != nullptr | |||||
// _ready == false | |||||
//运行一次后,则state应该是: | |||||
// _coro == nullptr | |||||
// _ready == false | |||||
//最后一次运行,则state应该是: | |||||
// _coro == nullptr | |||||
// _ready == true | |||||
virtual bool is_suspend() override | |||||
: _state(std::move(f._state)) | |||||
{ | { | ||||
auto * _state = _future._state.get(); | |||||
return _state->is_suspend(); | |||||
} | } | ||||
//返回true,表示任务还未完成,后续还需要继续执行 | |||||
//否则,任务从调度器里删除 | |||||
virtual bool go_next(scheduler * ) override | |||||
{ | |||||
auto * _state = _future._state.get(); | |||||
_state->resume(); | |||||
return !_state->ready() && !_state->done(); | |||||
} | |||||
virtual void cancel() override | |||||
{ | |||||
_future.cancel(); | |||||
} | |||||
virtual void * get_id() override | |||||
virtual state_base_t * get_state() const | |||||
{ | { | ||||
return _future._state.get(); | |||||
return _state.get(); | |||||
} | } | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
virtual void bind(scheduler * schdler) override | |||||
{ | |||||
auto * _state = _future._state.get(); | |||||
_state->current_scheduler(schdler); | |||||
} | |||||
#endif | |||||
}; | }; | ||||
//---------------------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------------------- | ||||
//这个'函数对象'被调用后,返回generator<_Ty>/future_t<_Ty>类型 | //这个'函数对象'被调用后,返回generator<_Ty>/future_t<_Ty>类型 | ||||
//然后'函数对象'作为异步执行的上下文状态保存起来 | //然后'函数对象'作为异步执行的上下文状态保存起来 | ||||
template<class _Ctx> | template<class _Ctx> | ||||
struct ctx_task_t : public task_t<typename std::remove_cvref<decltype(std::declval<_Ctx>()())>::type> | |||||
struct ctx_task_t : public task_base_t | |||||
{ | { | ||||
typedef task_t<typename std::remove_cvref<decltype(std::declval<_Ctx>()())>::type> base_type; | |||||
using base_type::_future; | |||||
using context_type = _Ctx; | |||||
using future_type = typename std::remove_cvref<decltype(std::declval<_Ctx>()())>::type; | |||||
using value_type = typename future_type::value_type; | |||||
using state_type = state_t<value_type>; | |||||
typedef _Ctx context_type; | |||||
context_type _context; | context_type _context; | ||||
counted_ptr<state_type> _state; | |||||
ctx_task_t(context_type && ctx) | |||||
: _context(std::forward<context_type>(ctx)) | |||||
ctx_task_t(context_type ctx) | |||||
: _context(std::move(ctx)) | |||||
{ | { | ||||
_future = std::move(_context()); | |||||
_state = _context()._state; | |||||
} | } | ||||
ctx_task_t(const context_type & ctx) | |||||
: _context(ctx) | |||||
virtual state_base_t* get_state() const | |||||
{ | { | ||||
_future = std::move(_context()); | |||||
return _state.get(); | |||||
} | } | ||||
}; | }; | ||||
} | } |
namespace resumef | namespace resumef | ||||
{ | { | ||||
static const char * future_error_string[(size_t)error_code::max__] | static const char * future_error_string[(size_t)error_code::max__] | ||||
{ | { | ||||
"none", | "none", | ||||
} | } | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | #if RESUMEF_ENABLE_MULT_SCHEDULER | ||||
thread_local scheduler * th_scheduler_ptr = nullptr; | |||||
thread_local scheduler_t * th_scheduler_ptr = nullptr; | |||||
//获得当前线程下的调度器 | //获得当前线程下的调度器 | ||||
scheduler * this_scheduler() | |||||
scheduler_t * this_scheduler() | |||||
{ | { | ||||
return th_scheduler_ptr ? th_scheduler_ptr : &scheduler::g_scheduler; | |||||
return th_scheduler_ptr ? th_scheduler_ptr : &scheduler_t::g_scheduler; | |||||
} | } | ||||
#endif | #endif | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | #if RESUMEF_ENABLE_MULT_SCHEDULER | ||||
if (th_scheduler_ptr == nullptr) | if (th_scheduler_ptr == nullptr) | ||||
{ | { | ||||
_scheduler_ptr = new scheduler; | |||||
_scheduler_ptr = new scheduler_t; | |||||
th_scheduler_ptr = _scheduler_ptr; | th_scheduler_ptr = _scheduler_ptr; | ||||
} | } | ||||
#endif | #endif | ||||
#endif | #endif | ||||
} | } | ||||
scheduler::scheduler() | |||||
scheduler_t::scheduler_t() | |||||
: _task() | : _task() | ||||
, _ready_task() | , _ready_task() | ||||
, _timer(std::make_shared<timer_manager>()) | , _timer(std::make_shared<timer_manager>()) | ||||
{ | { | ||||
} | } | ||||
scheduler::~scheduler() | |||||
scheduler_t::~scheduler_t() | |||||
{ | { | ||||
cancel_all_task_(); | cancel_all_task_(); | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | #if RESUMEF_ENABLE_MULT_SCHEDULER | ||||
#endif | #endif | ||||
} | } | ||||
void scheduler::new_task(task_base * task) | |||||
void scheduler_t::new_task(task_base_t * task) | |||||
{ | { | ||||
if (task) | if (task) | ||||
{ | { | ||||
scoped_lock<spinlock> __guard(_mtx_ready); | scoped_lock<spinlock> __guard(_mtx_ready); | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
task->bind(this); | |||||
#endif | |||||
this->_ready_task.push_back(task); | this->_ready_task.push_back(task); | ||||
this->add_initial(task->get_state()); | |||||
} | } | ||||
} | } | ||||
void scheduler::cancel_all_task_() | |||||
void scheduler_t::cancel_all_task_() | |||||
{ | { | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(_mtx_task); | scoped_lock<lock_type> __guard(_mtx_task); | ||||
} | } | ||||
} | } | ||||
void scheduler::break_all() | |||||
void scheduler_t::break_all() | |||||
{ | { | ||||
cancel_all_task_(); | cancel_all_task_(); | ||||
this->_timer->clear(); | this->_timer->clear(); | ||||
} | } | ||||
void scheduler::run_one_batch() | |||||
void scheduler_t::run_one_batch() | |||||
{ | { | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | #if RESUMEF_ENABLE_MULT_SCHEDULER | ||||
if (th_scheduler_ptr == nullptr) | if (th_scheduler_ptr == nullptr) | ||||
this->_timer->update(); | this->_timer->update(); | ||||
using namespace std::chrono; | |||||
for (auto task = this->_task.begin(); task != nullptr; ) | |||||
{ | |||||
#if _DEBUG | |||||
#define MAX_TIME_COST 10000us | |||||
#else | |||||
#define MAX_TIME_COST 1000us | |||||
#endif | |||||
// time_cost_evaluation<microseconds> eva(MAX_TIME_COST); | |||||
if (task->is_suspend() || task->go_next(this)) | |||||
{ | |||||
// eva.add("coscheduler"); | |||||
task = task->_next_node; | |||||
continue; | |||||
} | |||||
task = this->_task.erase(task, false); | |||||
} | |||||
{ | |||||
scoped_lock<spinlock> __guard(_mtx_ready); | |||||
if (!this->_ready_task.empty()) | |||||
{ | |||||
this->_task.merge_back(this->_ready_task); | |||||
} | |||||
} | |||||
state_vector states = std::move(_runing_states); | |||||
for (state_sptr& sptr : states) | |||||
sptr->resume(); | |||||
} | } | ||||
} | } | ||||
void scheduler::run_until_notask() | |||||
void scheduler_t::run_until_notask() | |||||
{ | { | ||||
while (!this->empty()) | while (!this->empty()) | ||||
this->run_one_batch(); | this->run_one_batch(); | ||||
} | } | ||||
scheduler scheduler::g_scheduler; | |||||
void scheduler_t::run() | |||||
{ | |||||
for (;;) | |||||
this->run_one_batch(); | |||||
} | |||||
scheduler_t scheduler_t::g_scheduler; | |||||
} | } |
{ | { | ||||
struct local_scheduler; | struct local_scheduler; | ||||
struct scheduler : public std::enable_shared_from_this<scheduler> | |||||
struct scheduler_t : public std::enable_shared_from_this<scheduler_t> | |||||
{ | { | ||||
using state_sptr = std::shared_ptr<state_base_t>; | |||||
using state_vector = std::vector<state_sptr>; | |||||
private: | |||||
state_vector _runing_states; | |||||
private: | private: | ||||
//typedef spinlock lock_type; | //typedef spinlock lock_type; | ||||
typedef std::recursive_mutex lock_type; | typedef std::recursive_mutex lock_type; | ||||
task_list _task; | task_list _task; | ||||
timer_mgr_ptr _timer; | timer_mgr_ptr _timer; | ||||
RF_API void new_task(task_base * task); | |||||
RF_API void new_task(task_base_t * task); | |||||
void cancel_all_task_(); | void cancel_all_task_(); | ||||
public: | public: | ||||
RF_API void run_one_batch(); | RF_API void run_one_batch(); | ||||
RF_API void run_until_notask(); | RF_API void run_until_notask(); | ||||
RF_API void run(); | |||||
template<class _Ty> | |||||
template<class _Ty, typename = std::enable_if_t<std::is_callable_v<_Ty> || is_future_v<_Ty>>> | |||||
inline void operator + (_Ty && t_) | inline void operator + (_Ty && t_) | ||||
{ | { | ||||
typedef typename std::conditional< | |||||
std::is_callable<_Ty>::value, | |||||
ctx_task_t<_Ty>, | |||||
task_t<_Ty> >::type task_type; | |||||
return new_task(new task_type(std::forward<_Ty>(t_))); | |||||
if constexpr(is_future_v<_Ty>) | |||||
new_task(new task_t<_Ty>(std::forward<_Ty>(t_))); | |||||
else | |||||
new_task(new ctx_task_t<_Ty>(std::forward<_Ty>(t_))); | |||||
} | } | ||||
inline void push_task_internal(task_base * t_) | |||||
inline void push_task_internal(task_base_t * t_) | |||||
{ | { | ||||
return new_task(t_); | |||||
new_task(t_); | |||||
} | } | ||||
inline bool empty() const | inline bool empty() const | ||||
friend struct task_base; | friend struct task_base; | ||||
friend struct local_scheduler; | friend struct local_scheduler; | ||||
void add_initial(state_base_t* sptr) | |||||
{ | |||||
sptr->_scheduler = this; | |||||
assert(sptr->_coro != nullptr); | |||||
_runing_states.emplace_back(sptr); | |||||
} | |||||
void add_await(state_base_t* sptr, coroutine_handle<> handler) | |||||
{ | |||||
sptr->_scheduler = this; | |||||
sptr->_coro = handler; | |||||
if (sptr->has_value() || sptr->_exception != nullptr) | |||||
_runing_states.emplace_back(sptr); | |||||
} | |||||
void add_ready(state_base_t* sptr) | |||||
{ | |||||
assert(sptr->_scheduler == this); | |||||
if (sptr->_coro != nullptr) | |||||
_runing_states.emplace_back(sptr); | |||||
} | |||||
protected: | protected: | ||||
RF_API scheduler(); | |||||
RF_API scheduler_t(); | |||||
public: | public: | ||||
RF_API ~scheduler(); | |||||
RF_API ~scheduler_t(); | |||||
scheduler(scheduler && right_) = delete; | |||||
scheduler & operator = (scheduler && right_) = delete; | |||||
scheduler(const scheduler &) = delete; | |||||
scheduler & operator = (const scheduler &) = delete; | |||||
scheduler_t(scheduler_t&& right_) = delete; | |||||
scheduler_t& operator = (scheduler_t&& right_) = delete; | |||||
scheduler_t(const scheduler_t&) = delete; | |||||
scheduler_t& operator = (const scheduler_t&) = delete; | |||||
static scheduler g_scheduler; | |||||
static scheduler_t g_scheduler; | |||||
}; | }; | ||||
struct local_scheduler | struct local_scheduler | ||||
local_scheduler & operator = (const local_scheduler &) = delete; | local_scheduler & operator = (const local_scheduler &) = delete; | ||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | #if RESUMEF_ENABLE_MULT_SCHEDULER | ||||
private: | private: | ||||
scheduler * _scheduler_ptr; | |||||
scheduler_t* _scheduler_ptr; | |||||
#endif | #endif | ||||
}; | }; | ||||
//-------------------------------------------------------------------------------------------------- | //-------------------------------------------------------------------------------------------------- | ||||
#if !RESUMEF_ENABLE_MULT_SCHEDULER | #if !RESUMEF_ENABLE_MULT_SCHEDULER | ||||
//获得当前线程下的调度器 | //获得当前线程下的调度器 | ||||
inline scheduler * this_scheduler() | |||||
inline scheduler_t* this_scheduler() | |||||
{ | { | ||||
return &scheduler::g_scheduler; | |||||
return &scheduler_t::g_scheduler; | |||||
} | } | ||||
#endif | #endif | ||||
#if !defined(_DISABLE_RESUMEF_GO_MACRO) | #if !defined(_DISABLE_RESUMEF_GO_MACRO) | ||||
#define go (*::resumef::this_scheduler()) + | #define go (*::resumef::this_scheduler()) + | ||||
#define GO (*::resumef::this_scheduler()) + [=]()mutable->resumef::future_vt | |||||
#define GO (*::resumef::this_scheduler()) + [=]()mutable->resumef::future_t<> | |||||
#endif | #endif | ||||
//-------------------------------------------------------------------------------------------------- | //-------------------------------------------------------------------------------------------------- |
namespace resumef | namespace resumef | ||||
{ | { | ||||
future_vt sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler & scheduler_) | |||||
future_t<> sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler_t& scheduler_) | |||||
{ | { | ||||
promise_vt awaitable; | promise_vt awaitable; | ||||
namespace resumef | namespace resumef | ||||
{ | { | ||||
struct scheduler; | |||||
struct scheduler_t; | |||||
RF_API future_vt sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler & scheduler_); | |||||
RF_API future_t<> sleep_until_(const std::chrono::system_clock::time_point& tp_, scheduler_t& scheduler_); | |||||
inline future_vt sleep_for_(const std::chrono::system_clock::duration& dt_, scheduler & scheduler_) | |||||
inline future_t<> sleep_for_(const std::chrono::system_clock::duration& dt_, scheduler_t& scheduler_) | |||||
{ | { | ||||
return std::move(sleep_until_(std::chrono::system_clock::now() + dt_, scheduler_)); | return std::move(sleep_until_(std::chrono::system_clock::now() + dt_, scheduler_)); | ||||
} | } | ||||
template<class _Rep, class _Period> | template<class _Rep, class _Period> | ||||
inline future_vt sleep_for(const std::chrono::duration<_Rep, _Period>& dt_, scheduler & scheduler_) | |||||
inline future_t<> sleep_for(const std::chrono::duration<_Rep, _Period>& dt_, scheduler_t& scheduler_) | |||||
{ | { | ||||
return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), scheduler_); | return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), scheduler_); | ||||
} | } | ||||
template<class _Rep, class _Period> | template<class _Rep, class _Period> | ||||
inline future_vt sleep_for(const std::chrono::duration<_Rep, _Period>& dt_) | |||||
inline future_t<> sleep_for(const std::chrono::duration<_Rep, _Period>& dt_) | |||||
{ | { | ||||
return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), *this_scheduler()); | return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), *this_scheduler()); | ||||
} | } | ||||
template<class _Clock, class _Duration = typename _Clock::duration> | template<class _Clock, class _Duration = typename _Clock::duration> | ||||
inline future_vt sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_, scheduler & scheduler_) | |||||
inline future_t<> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_, scheduler_t& scheduler_) | |||||
{ | { | ||||
return sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), scheduler_); | return sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), scheduler_); | ||||
} | } | ||||
template<class _Clock, class _Duration> | template<class _Clock, class _Duration> | ||||
inline future_vt sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_) | |||||
inline future_t<> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_) | |||||
{ | { | ||||
return sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), *this_scheduler()); | return sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), *this_scheduler()); | ||||
} | } | ||||
template <class Rep, class Period> | template <class Rep, class Period> | ||||
inline future_vt operator co_await(std::chrono::duration<Rep, Period> dt_) | |||||
inline future_t<> operator co_await(std::chrono::duration<Rep, Period> dt_) | |||||
{ | { | ||||
return sleep_for(dt_); | return sleep_for(dt_); | ||||
} | } |
namespace resumef | namespace resumef | ||||
{ | { | ||||
template<class state_tt> | |||||
struct awaitable_task_t : public task_base | |||||
state_base_t::~state_base_t() | |||||
{ | { | ||||
counted_ptr<state_tt> _state; | |||||
awaitable_task_t() {} | |||||
awaitable_task_t(state_tt * state) | |||||
: _state(state) | |||||
{ | |||||
} | |||||
virtual bool is_suspend() override | |||||
{ | |||||
return !_state->ready(); | |||||
} | |||||
virtual bool go_next(scheduler * ) override | |||||
{ | |||||
_state->resume(); | |||||
return false; | |||||
} | |||||
virtual void cancel() override | |||||
{ | |||||
_state->cancel(); | |||||
} | |||||
virtual void * get_id() override | |||||
{ | |||||
return _state.get(); | |||||
} | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
virtual void bind(scheduler * ) override | |||||
{ | |||||
} | |||||
#endif | |||||
}; | |||||
state_base::~state_base() | |||||
{ | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
--g_resumef_state_count; | |||||
#endif | |||||
} | |||||
void state_base::set_value_none_lock() | |||||
{ | |||||
// Set all members first as calling coroutine may reset stuff here. | |||||
_ready = true; | |||||
if (_coro) | |||||
{ | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
auto sch_ = this->current_scheduler(); | |||||
#else | |||||
auto sch_ = this_scheduler(); | |||||
#endif | |||||
if(sch_) sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||||
} | |||||
} | |||||
void state_base::set_exception(std::exception_ptr && e_) | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
_exception = std::move(e_); | |||||
// Set all members first as calling coroutine may reset stuff here. | |||||
_ready = true; | |||||
if (_coro) | |||||
{ | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
auto sch_ = this->current_scheduler(); | |||||
#else | |||||
auto sch_ = this_scheduler(); | |||||
#endif | |||||
if (sch_) sch_->push_task_internal(new awaitable_task_t<state_base>(this)); | |||||
} | |||||
} | |||||
void state_base::await_suspend(coroutine_handle<> resume_cb) | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
_coro = resume_cb; | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
if (_current_scheduler == nullptr) | |||||
{ | |||||
auto * promise_ = this->parent_promise(); | |||||
if (promise_) | |||||
{ | |||||
scheduler * sch_ = promise_->_state->current_scheduler(); | |||||
if (sch_) | |||||
this->current_scheduler(sch_); | |||||
else | |||||
promise_->_state->_depend_states.push_back(counted_ptr<state_base>(this)); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
for (auto & stptr : _depend_states) | |||||
stptr->current_scheduler(_current_scheduler); | |||||
_depend_states.clear(); | |||||
} | |||||
#endif | |||||
} | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
void state_base::current_scheduler(scheduler * sch_) | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
_current_scheduler = sch_; | |||||
for (auto & stptr : _depend_states) | |||||
stptr->current_scheduler(sch_); | |||||
_depend_states.clear(); | |||||
} | } | ||||
#endif | |||||
} | } |
namespace resumef | namespace resumef | ||||
{ | { | ||||
template <typename T = void> | |||||
struct promise_t; | |||||
struct state_base | |||||
struct state_base_t : public counted_t<state_base_t> | |||||
{ | { | ||||
protected: | |||||
//typedef spinlock lock_type; | |||||
typedef std::recursive_mutex lock_type; | typedef std::recursive_mutex lock_type; | ||||
lock_type _mtx; //for value, _exception | |||||
RF_API void set_value_none_lock(); | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
private: | |||||
std::atomic<void *> _this_promise = nullptr; | |||||
scheduler * _current_scheduler = nullptr; | |||||
std::vector<counted_ptr<state_base>> _depend_states; | |||||
#endif | |||||
protected: | |||||
lock_type _mtx; | |||||
scheduler_t * _scheduler = nullptr; | |||||
coroutine_handle<> _coro; | coroutine_handle<> _coro; | ||||
std::atomic<intptr_t> _count{0}; // tracks reference count of state object | |||||
std::exception_ptr _exception; | std::exception_ptr _exception; | ||||
std::atomic<bool> _ready = false; | |||||
std::atomic<bool> _cancellation = false; | |||||
std::atomic<bool> _done = false; | |||||
public: | |||||
state_base() noexcept | |||||
{ | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
++g_resumef_state_count; | |||||
#endif | |||||
} | |||||
//某个地方的代码,发生过截断,导致了内存泄漏。还是加上虚析构函数吧。 | |||||
virtual ~state_base(); | |||||
state_base(state_base&&) = delete; | |||||
state_base(const state_base&) = delete; | |||||
state_base & operator = (state_base&&) = delete; | |||||
state_base & operator = (const state_base&) = delete; | |||||
RF_API void set_exception(std::exception_ptr && e_); | |||||
template<class _Exp> | |||||
void throw_exception(const _Exp & e_) | |||||
{ | |||||
set_exception(std::make_exception_ptr(e_)); | |||||
} | |||||
void rethrow_if_exception() | |||||
{ | |||||
if (_exception) | |||||
std::rethrow_exception(_exception); | |||||
} | |||||
bool ready() const | |||||
{ | |||||
return _ready; | |||||
} | |||||
bool done() const | |||||
{ | |||||
return _done; | |||||
} | |||||
void reset_none_lock() | |||||
{ | |||||
_coro = nullptr; | |||||
_ready = false; | |||||
} | |||||
void cancel() | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
_cancellation = true; | |||||
_coro = nullptr; | |||||
} | |||||
RF_API virtual ~state_base_t(); | |||||
virtual bool has_value() const = 0; | |||||
bool is_suspend() const | |||||
{ | |||||
return !_coro && !(_done || _ready || _cancellation); | |||||
} | |||||
void resume() | void resume() | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(_mtx); | scoped_lock<lock_type> __guard(_mtx); | ||||
if (_coro) | |||||
{ | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
{ | |||||
scoped_lock<std::mutex> __lock(g_resumef_cout_mutex); | |||||
std::cout | |||||
<< "coro=" << _coro.address() | |||||
<< ",thread=" << std::this_thread::get_id() | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
<< ",scheduler=" << current_scheduler() | |||||
<< ",this_promise=" << this_promise() | |||||
<< ",parent_promise=" << parent_promise() | |||||
#endif | |||||
<< std::endl; | |||||
} | |||||
#endif | |||||
auto coro = _coro; | |||||
_coro = nullptr; | |||||
coro(); | |||||
} | |||||
} | |||||
state_base* lock() | |||||
{ | |||||
++_count; | |||||
return this; | |||||
} | |||||
void unlock() | |||||
{ | |||||
if (--_count == 0) | |||||
delete this; | |||||
} | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
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_); | |||||
#endif | |||||
//------------------------------------------------------------------------------------------ | |||||
//以下是通过future_t/promise_t, 与编译器生成的resumable function交互的接口 | |||||
void await_suspend(coroutine_handle<> resume_cb); | |||||
void final_suspend() | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
_done = true; | |||||
auto handler = _coro; | |||||
_coro = nullptr; | |||||
handler(); | |||||
} | } | ||||
//以上是通过future_t/promise_t, 与编译器生成的resumable function交互的接口 | |||||
//------------------------------------------------------------------------------------------ | |||||
}; | }; | ||||
template <typename _Ty> | template <typename _Ty> | ||||
struct state_t : public state_base | |||||
struct state_t : public state_base_t | |||||
{ | { | ||||
public: | |||||
typedef _Ty value_type; | |||||
value_type _value; | |||||
state_t<_Ty>* lock() | |||||
{ | |||||
++_count; | |||||
return this; | |||||
} | |||||
void set_value(const value_type& t) | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
_value = t; | |||||
state_base::set_value_none_lock(); | |||||
} | |||||
void set_value(value_type&& t) | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
_value = std::forward<value_type>(t); | |||||
state_base::set_value_none_lock(); | |||||
} | |||||
value_type & set_value__() | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
state_base::set_value_none_lock(); | |||||
return _value; | |||||
} | |||||
value_type & get_value() | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
using value_type = _Ty; | |||||
if (!_ready) | |||||
throw future_exception{ error_code::not_ready }; | |||||
return _value; | |||||
} | |||||
void reset() | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
state_base::reset_none_lock(); | |||||
_value = value_type{}; | |||||
} | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
promise_t<_Ty> * parent_promise() const | |||||
std::optional<value_type> _value; | |||||
virtual bool has_value() const override | |||||
{ | { | ||||
return reinterpret_cast<promise_t<_Ty> *>(state_base::parent_promise()); | |||||
return _value.has_value(); | |||||
} | } | ||||
#endif | |||||
}; | }; | ||||
template<> | template<> | ||||
struct state_t<void> : public state_base | |||||
struct state_t<void> : public state_base_t | |||||
{ | { | ||||
state_t<void>* lock() | |||||
bool _has_value = false; | |||||
virtual bool has_value() const override | |||||
{ | { | ||||
++_count; | |||||
return this; | |||||
return _has_value; | |||||
} | } | ||||
void set_value() | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
set_value_none_lock(); | |||||
} | |||||
void get_value() | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
if (!_ready) | |||||
throw future_exception{ error_code::not_ready }; | |||||
} | |||||
void reset() | |||||
{ | |||||
scoped_lock<lock_type> __guard(_mtx); | |||||
reset_none_lock(); | |||||
} | |||||
#if RESUMEF_ENABLE_MULT_SCHEDULER | |||||
promise_t<void> * parent_promise() const | |||||
{ | |||||
return reinterpret_cast<promise_t<void> *>(state_base::parent_promise()); | |||||
} | |||||
#endif | |||||
}; | }; | ||||
} | } | ||||
{ | { | ||||
struct task_list | struct task_list | ||||
{ | { | ||||
using value_type = task_base; | |||||
using value_type = task_base_t; | |||||
using size_type = std::size_t; | using size_type = std::size_t; | ||||
using difference_type = std::ptrdiff_t; | using difference_type = std::ptrdiff_t; | ||||
using pointer = value_type *; | using pointer = value_type *; | ||||
pointer temp = header; | pointer temp = header; | ||||
header = header->_next_node; | header = header->_next_node; | ||||
if (cancel_) | |||||
temp->cancel(); | |||||
//if (cancel_) | |||||
// temp->cancel(); | |||||
delete temp; | delete temp; | ||||
} | } | ||||
} | } | ||||
if (_M_last == node) | if (_M_last == node) | ||||
_M_last = prev; | _M_last = prev; | ||||
if (cancel_) | |||||
node->cancel(); | |||||
//if (cancel_) | |||||
// node->cancel(); | |||||
delete node; | delete node; | ||||
return next; | return next; |
when_all_functor & operator = (const when_all_functor &) = default; | when_all_functor & operator = (const when_all_functor &) = default; | ||||
when_all_functor & operator = (when_all_functor &&) = default; | when_all_functor & operator = (when_all_functor &&) = default; | ||||
inline future_vt operator ()() const | |||||
inline future_t<> operator ()() const | |||||
{ | { | ||||
_val.get() = co_await _f; | _val.get() = co_await _f; | ||||
_e->signal(); | _e->signal(); | ||||
}; | }; | ||||
template<class _Ty> | template<class _Ty> | ||||
struct when_all_functor<future_vt, _Ty> | |||||
struct when_all_functor<future_t<>, _Ty> | |||||
{ | { | ||||
using value_type = _Ty; | using value_type = _Ty; | ||||
using future_type = future_vt; | |||||
using future_type = future_t<>; | |||||
when_impl_ptr _e; | when_impl_ptr _e; | ||||
mutable future_type _f; | mutable future_type _f; | ||||
when_all_functor & operator = (const when_all_functor &) = default; | when_all_functor & operator = (const when_all_functor &) = default; | ||||
when_all_functor & operator = (when_all_functor &&) = default; | when_all_functor & operator = (when_all_functor &&) = default; | ||||
inline future_vt operator ()() const | |||||
inline future_t<> operator ()() const | |||||
{ | { | ||||
co_await _f; | co_await _f; | ||||
_val.get() = std::ignore; | _val.get() = std::ignore; | ||||
}; | }; | ||||
template<class _Tup, size_t _Idx> | template<class _Tup, size_t _Idx> | ||||
inline void when_all_one__(scheduler & , const when_impl_ptr & , _Tup & ) | |||||
inline void when_all_one__(scheduler_t & , const when_impl_ptr & , _Tup & ) | |||||
{ | { | ||||
} | } | ||||
template<class _Tup, size_t _Idx, class _Fty, class... _Rest> | template<class _Tup, size_t _Idx, class _Fty, class... _Rest> | ||||
inline void when_all_one__(scheduler & s, const when_impl_ptr & e, _Tup & t, _Fty f, _Rest&&... rest) | |||||
inline void when_all_one__(scheduler_t& s, const when_impl_ptr & e, _Tup & t, _Fty f, _Rest&&... rest) | |||||
{ | { | ||||
s + when_all_functor<_Fty, std::tuple_element_t<_Idx, _Tup> >{e, std::move(f), std::get<_Idx>(t)}; | s + when_all_functor<_Fty, std::tuple_element_t<_Idx, _Tup> >{e, std::move(f), std::get<_Idx>(t)}; | ||||
} | } | ||||
template<class _Val, class _Iter, typename _Fty = decltype(*std::declval<_Iter>())> | template<class _Val, class _Iter, typename _Fty = decltype(*std::declval<_Iter>())> | ||||
inline void when_all_range__(scheduler & s, const when_impl_ptr & e, std::vector<_Val> & t, _Iter begin, _Iter end) | |||||
inline void when_all_range__(scheduler_t& s, const when_impl_ptr & e, std::vector<_Val> & t, _Iter begin, _Iter end) | |||||
{ | { | ||||
using future_type = std::remove_reference_t<_Fty>; | using future_type = std::remove_reference_t<_Fty>; | ||||
template<class _Tup, class... _Fty> | template<class _Tup, class... _Fty> | ||||
future_t<_Tup> when_all_count(size_t count, const std::shared_ptr<_Tup> & vals, scheduler & s, _Fty&&... f) | |||||
future_t<_Tup> when_all_count(size_t count, const std::shared_ptr<_Tup> & vals, scheduler_t & s, _Fty&&... f) | |||||
{ | { | ||||
promise_t<_Tup> awaitable; | promise_t<_Tup> awaitable; | ||||
} | } | ||||
template<class _Tup, class _Iter> | template<class _Tup, class _Iter> | ||||
future_t<_Tup> when_all_range(size_t count, const std::shared_ptr<_Tup> & vals, scheduler & s, _Iter begin, _Iter end) | |||||
future_t<_Tup> when_all_range(size_t count, const std::shared_ptr<_Tup> & vals, scheduler_t& s, _Iter begin, _Iter end) | |||||
{ | { | ||||
promise_t<_Tup> awaitable; | promise_t<_Tup> awaitable; | ||||
when_any_functor & operator = (const when_any_functor &) = default; | when_any_functor & operator = (const when_any_functor &) = default; | ||||
when_any_functor & operator = (when_any_functor &&) = default; | when_any_functor & operator = (when_any_functor &&) = default; | ||||
inline future_vt operator ()() const | |||||
inline future_t<> operator ()() const | |||||
{ | { | ||||
if (_val->first < 0) | if (_val->first < 0) | ||||
{ | { | ||||
}; | }; | ||||
template<> | template<> | ||||
struct when_any_functor<future_vt> | |||||
struct when_any_functor<future_t<>> | |||||
{ | { | ||||
using value_type = when_any_pair; | using value_type = when_any_pair; | ||||
using future_type = future_vt; | |||||
using future_type = future_t<>; | |||||
when_impl_ptr _e; | when_impl_ptr _e; | ||||
mutable future_type _f; | mutable future_type _f; | ||||
when_any_functor & operator = (const when_any_functor &) = default; | when_any_functor & operator = (const when_any_functor &) = default; | ||||
when_any_functor & operator = (when_any_functor &&) = default; | when_any_functor & operator = (when_any_functor &&) = default; | ||||
inline future_vt operator ()() const | |||||
inline future_t<> operator ()() const | |||||
{ | { | ||||
if (_val->first < 0) | if (_val->first < 0) | ||||
{ | { | ||||
}; | }; | ||||
template<intptr_t _Idx> | template<intptr_t _Idx> | ||||
inline void when_any_one__(scheduler & , const when_impl_ptr & , const when_any_result_ptr & ) | |||||
inline void when_any_one__(scheduler_t & , const when_impl_ptr & , const when_any_result_ptr & ) | |||||
{ | { | ||||
} | } | ||||
template<intptr_t _Idx, class _Fty, class... _Rest> | template<intptr_t _Idx, class _Fty, class... _Rest> | ||||
inline void when_any_one__(scheduler & s, const when_impl_ptr & e, const when_any_result_ptr & t, _Fty f, _Rest&&... rest) | |||||
inline void when_any_one__(scheduler_t & s, const when_impl_ptr & e, const when_any_result_ptr & t, _Fty f, _Rest&&... rest) | |||||
{ | { | ||||
s + when_any_functor<_Fty>{e, std::move(f), t, _Idx}; | s + when_any_functor<_Fty>{e, std::move(f), t, _Idx}; | ||||
} | } | ||||
template<class... _Fty> | template<class... _Fty> | ||||
future_t<when_any_pair> when_any_count(size_t count, const when_any_result_ptr & val_ptr, scheduler & s, _Fty&&... f) | |||||
future_t<when_any_pair> when_any_count(size_t count, const when_any_result_ptr & val_ptr, scheduler_t & s, _Fty&&... f) | |||||
{ | { | ||||
promise_t<when_any_pair> awaitable; | promise_t<when_any_pair> awaitable; | ||||
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())> | template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())> | ||||
inline void when_any_range__(scheduler & s, const when_impl_ptr & e, const when_any_result_ptr & t, _Iter begin, _Iter end) | |||||
inline void when_any_range__(scheduler_t & s, const when_impl_ptr & e, const when_any_result_ptr & t, _Iter begin, _Iter end) | |||||
{ | { | ||||
using future_type = std::remove_reference_t<_Fty>; | using future_type = std::remove_reference_t<_Fty>; | ||||
} | } | ||||
template<class _Iter> | template<class _Iter> | ||||
future_t<when_any_pair> when_any_range(size_t count, const when_any_result_ptr & val_ptr, scheduler & s, _Iter begin, _Iter end) | |||||
future_t<when_any_pair> when_any_range(size_t count, const when_any_result_ptr & val_ptr, scheduler_t & s, _Iter begin, _Iter end) | |||||
{ | { | ||||
promise_t<when_any_pair> awaitable; | promise_t<when_any_pair> awaitable; | ||||
} | } | ||||
template<class... _Fty> | template<class... _Fty> | ||||
auto when_all(scheduler & s, _Fty&&... f) -> future_t<std::tuple<detail::remove_future_vt<_Fty>...> > | |||||
auto when_all(scheduler_t & s, _Fty&&... f) -> future_t<std::tuple<detail::remove_future_vt<_Fty>...> > | |||||
{ | { | ||||
using tuple_type = std::tuple<detail::remove_future_vt<_Fty>...>; | using tuple_type = std::tuple<detail::remove_future_vt<_Fty>...>; | ||||
auto vals = std::make_shared<tuple_type>(); | auto vals = std::make_shared<tuple_type>(); | ||||
return when_all(*this_scheduler(), std::forward<_Fty>(f)...); | return when_all(*this_scheduler(), std::forward<_Fty>(f)...); | ||||
} | } | ||||
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())> | template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())> | ||||
auto when_all(scheduler & s, _Iter begin, _Iter end) -> future_t<std::vector<detail::remove_future_vt<_Fty> > > | |||||
auto when_all(scheduler_t & s, _Iter begin, _Iter end) -> future_t<std::vector<detail::remove_future_vt<_Fty> > > | |||||
{ | { | ||||
using value_type = detail::remove_future_vt<_Fty>; | using value_type = detail::remove_future_vt<_Fty>; | ||||
using vector_type = std::vector<value_type>; | using vector_type = std::vector<value_type>; | ||||
template<class... _Fty> | template<class... _Fty> | ||||
auto when_any(scheduler & s, _Fty&&... f) -> future_t<detail::when_any_pair> | |||||
auto when_any(scheduler_t & s, _Fty&&... f) -> future_t<detail::when_any_pair> | |||||
{ | { | ||||
auto vals = std::make_shared<detail::when_any_pair>(-1, any_t{}); | auto vals = std::make_shared<detail::when_any_pair>(-1, any_t{}); | ||||
return when_any(*this_scheduler(), std::forward<_Fty>(f)...); | return when_any(*this_scheduler(), std::forward<_Fty>(f)...); | ||||
} | } | ||||
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())> | template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())> | ||||
auto when_any(scheduler & s, _Iter begin, _Iter end) -> future_t<detail::when_any_pair> | |||||
auto when_any(scheduler_t & s, _Iter begin, _Iter end) -> future_t<detail::when_any_pair> | |||||
{ | { | ||||
auto vals = std::make_shared<detail::when_any_pair>(-1, any_t{}); | auto vals = std::make_shared<detail::when_any_pair>(-1, any_t{}); | ||||
//这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | //这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | ||||
auto async_get_long(int64_t val) | auto async_get_long(int64_t val) | ||||
{ | { | ||||
resumef::promise_t<int64_t> awaitable; | |||||
callback_get_long(val, [st = awaitable._state](int64_t val) | |||||
resumef::awaitable_t<int64_t> st; | |||||
callback_get_long(val, [st](int64_t val) | |||||
{ | { | ||||
st->set_value(val); | |||||
st.set_value(val); | |||||
}); | }); | ||||
return awaitable.get_future(); | |||||
return st.get_future(); | |||||
} | } | ||||
//这种情况下,会生成对应的 frame-context,一个promise_type被内嵌在frame-context里 | //这种情况下,会生成对应的 frame-context,一个promise_type被内嵌在frame-context里 | ||||
resumef::future_vt resumable_get_long(int64_t val) | |||||
resumef::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 << std::this_thread::get_id() << std::endl; | std::cout << std::this_thread::get_id() << std::endl; | ||||
go []()->resumef::future_vt | |||||
go []()->resumef::future_t<> | |||||
{ | { | ||||
auto val = co_await loop_get_long(2); | auto val = co_await loop_get_long(2); | ||||
std::cout << val << std::endl; | std::cout << val << std::endl; |
const size_t MAX_CHANNEL_QUEUE = 5; //0, 1, 5, 10, -1 | const size_t MAX_CHANNEL_QUEUE = 5; //0, 1, 5, 10, -1 | ||||
future_vt test_channel_read(const channel_t<std::string> & c) | |||||
future_t<> test_channel_read(const channel_t<std::string> & c) | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
} | } | ||||
} | } | ||||
future_vt test_channel_write(const channel_t<std::string> & c) | |||||
future_t<> test_channel_write(const channel_t<std::string> & c) | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
#define OUTPUT_DEBUG 0 | #define OUTPUT_DEBUG 0 | ||||
future_vt test_channel_consumer(const channel_t<std::string> & c, size_t cnt) | |||||
future_t<> test_channel_consumer(const channel_t<std::string> & c, size_t cnt) | |||||
{ | { | ||||
for (size_t i = 0; i < cnt; ++i) | for (size_t i = 0; i < cnt; ++i) | ||||
{ | { | ||||
} | } | ||||
} | } | ||||
future_vt test_channel_producer(const channel_t<std::string> & c, size_t cnt) | |||||
future_t<> test_channel_producer(const channel_t<std::string> & c, size_t cnt) | |||||
{ | { | ||||
for (size_t i = 0; i < cnt; ++i) | for (size_t i = 0; i < cnt; ++i) | ||||
{ | { | ||||
#if !RESUMEF_ENABLE_MULT_SCHEDULER | #if !RESUMEF_ENABLE_MULT_SCHEDULER | ||||
std::this_thread::sleep_for(100ms); | std::this_thread::sleep_for(100ms); | ||||
scheduler::g_scheduler.run_until_notask(); | |||||
scheduler_t::g_scheduler.run_until_notask(); | |||||
#endif | #endif | ||||
for(auto & th : read_th) | for(auto & th : read_th) | ||||
th.join(); | th.join(); |
} | } | ||||
future_vt resumable_wait_event(const event_t & e) | |||||
future_t<> resumable_wait_event(const event_t & e) | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
} | } | ||||
{ | { | ||||
event_t evt2(1); | event_t evt2(1); | ||||
go[&]() -> future_vt | |||||
go[&]() -> future_t<> | |||||
{ | { | ||||
(void)co_await evt2.wait(); | (void)co_await evt2.wait(); | ||||
std::cout << "event signal on 1!" << std::endl; | std::cout << "event signal on 1!" << std::endl; | ||||
}; | }; | ||||
go[&]() -> future_vt | |||||
go[&]() -> future_t<> | |||||
{ | { | ||||
(void)co_await evt2.wait(); | (void)co_await evt2.wait(); | ||||
std::cout << "event signal on 2!" << std::endl; | std::cout << "event signal on 2!" << std::endl; | ||||
event_t evts[8]; | event_t evts[8]; | ||||
go[&]() -> future_vt | |||||
go[&]() -> future_t<> | |||||
{ | { | ||||
for (int i = 0; i < _countof(evts); ++i) | for (int i = 0; i < _countof(evts); ++i) | ||||
{ | { | ||||
event_t evts[8]; | event_t evts[8]; | ||||
go[&]() -> future_vt | |||||
go[&]() -> future_t<> | |||||
{ | { | ||||
if (co_await event_t::wait_all(evts)) | if (co_await event_t::wait_all(evts)) | ||||
std::cout << "all event signal!" << std::endl; | std::cout << "all event signal!" << std::endl; | ||||
event_t evts[8]; | event_t evts[8]; | ||||
go[&]() -> future_vt | |||||
go[&]() -> future_t<> | |||||
{ | { | ||||
if (co_await event_t::wait_all_for(1000ms, evts)) | if (co_await event_t::wait_all_for(1000ms, evts)) | ||||
std::cout << "all event signal!" << std::endl; | std::cout << "all event signal!" << std::endl; |
using namespace resumef; | using namespace resumef; | ||||
future_vt resumalbe_set_event(const event_t & e, std::chrono::milliseconds dt) | |||||
future_t<> resumalbe_set_event(const event_t & e, std::chrono::milliseconds dt) | |||||
{ | { | ||||
co_await resumef::sleep_for(dt); | co_await resumef::sleep_for(dt); | ||||
e.signal(); | e.signal(); | ||||
event_t evt; | event_t evt; | ||||
go [&evt]() -> future_vt | |||||
go [&evt]() -> future_t<> | |||||
{ | { | ||||
intptr_t counter = 0; | intptr_t counter = 0; | ||||
for (;;) | for (;;) | ||||
event_t evts[8]; | event_t evts[8]; | ||||
//无效的等待 | //无效的等待 | ||||
go[&]()-> future_vt | |||||
go[&]()-> future_t<> | |||||
{ | { | ||||
intptr_t idx = co_await event_t::wait_any_for(500ms, std::begin(evts), std::end(evts)); | intptr_t idx = co_await event_t::wait_any_for(500ms, std::begin(evts), std::end(evts)); | ||||
assert(idx < 0); | assert(idx < 0); | ||||
event_t evts[8]; | event_t evts[8]; | ||||
go[&]() -> future_vt | |||||
go[&]() -> future_t<> | |||||
{ | { | ||||
intptr_t counter = 0; | intptr_t counter = 0; | ||||
for (;;) | for (;;) | ||||
event_t evts[8]; | event_t evts[8]; | ||||
//无效的等待 | //无效的等待 | ||||
go[&]()-> future_vt | |||||
go[&]()-> future_t<> | |||||
{ | { | ||||
bool result = co_await event_t::wait_all_for(500ms, std::begin(evts), std::end(evts)); | bool result = co_await event_t::wait_all_for(500ms, std::begin(evts), std::end(evts)); | ||||
assert(!result); | assert(!result); | ||||
event_t evts[8]; | event_t evts[8]; | ||||
go[&]() -> future_vt | |||||
go[&]() -> future_t<> | |||||
{ | { | ||||
intptr_t counter = 0; | intptr_t counter = 0; | ||||
for (;;) | for (;;) |
return awaitable.get_future(); | return awaitable.get_future(); | ||||
} | } | ||||
future_vt test_signal_exception() | |||||
future_t<> test_signal_exception() | |||||
{ | { | ||||
for (intptr_t i = 10; i >= 0; --i) | for (intptr_t i = 10; i >= 0; --i) | ||||
{ | { | ||||
} | } | ||||
} | } | ||||
future_vt test_bomb_exception() | |||||
future_t<> test_bomb_exception() | |||||
{ | { | ||||
for (intptr_t i = 10; i >= 0; --i) | for (intptr_t i = 10; i >= 0; --i) | ||||
{ | { |
//运行主调度器里面的协程 | //运行主调度器里面的协程 | ||||
//但本范例不应该有协程存在,仅演示不要忽略了主调度器 | //但本范例不应该有协程存在,仅演示不要忽略了主调度器 | ||||
scheduler::g_scheduler.run_until_notask(); | |||||
scheduler_t::g_scheduler.run_until_notask(); | |||||
} | } |
extern void resumable_main_benchmark_asio_server(); | extern void resumable_main_benchmark_asio_server(); | ||||
extern void resumable_main_benchmark_asio_client(intptr_t nNum); | extern void resumable_main_benchmark_asio_client(intptr_t nNum); | ||||
namespace coro = std::experimental; | |||||
namespace librf2 | |||||
{ | |||||
struct scheduler_t; | |||||
template<class _Ty = void> | |||||
struct future_t; | |||||
template<class _Ty = void> | |||||
struct promise_t; | |||||
template<class _PromiseT> | |||||
struct is_promise : std::false_type {}; | |||||
template<class _Ty> | |||||
struct is_promise<promise_t<_Ty>> : std::true_type {}; | |||||
template<class _Ty> | |||||
_INLINE_VAR constexpr bool is_promise_v = is_promise<_Ty>::value; | |||||
struct state_base_t | |||||
{ | |||||
scheduler_t* _scheduler = nullptr; | |||||
coro::coroutine_handle<> _coro; | |||||
std::exception_ptr _exception; | |||||
virtual ~state_base_t() {} | |||||
virtual bool has_value() const = 0; | |||||
void resume() | |||||
{ | |||||
auto handler = _coro; | |||||
_coro = nullptr; | |||||
handler(); | |||||
} | |||||
}; | |||||
template<class _Ty = void> | |||||
struct state_t : public state_base_t | |||||
{ | |||||
using value_type = _Ty; | |||||
std::optional<value_type> _value; | |||||
virtual bool has_value() const override | |||||
{ | |||||
return _value.has_value(); | |||||
} | |||||
}; | |||||
template<> | |||||
struct state_t<void> : public state_base_t | |||||
{ | |||||
bool _has_value = false; | |||||
virtual bool has_value() const override | |||||
{ | |||||
return _has_value; | |||||
} | |||||
}; | |||||
struct scheduler_t | |||||
{ | |||||
using state_sptr = std::shared_ptr<state_base_t>; | |||||
using state_vector = std::vector<state_sptr>; | |||||
private: | |||||
state_vector _runing_states; | |||||
public: | |||||
void add_initial(state_sptr sptr) | |||||
{ | |||||
sptr->_scheduler = this; | |||||
assert(sptr->_coro != nullptr); | |||||
_runing_states.emplace_back(std::move(sptr)); | |||||
} | |||||
void add_await(state_sptr sptr, coro::coroutine_handle<> handler) | |||||
{ | |||||
sptr->_scheduler = this; | |||||
sptr->_coro = handler; | |||||
if (sptr->has_value() || sptr->_exception != nullptr) | |||||
_runing_states.emplace_back(std::move(sptr)); | |||||
} | |||||
void add_ready(state_sptr sptr) | |||||
{ | |||||
assert(sptr->_scheduler == this); | |||||
if (sptr->_coro != nullptr) | |||||
_runing_states.emplace_back(std::move(sptr)); | |||||
} | |||||
void run() | |||||
{ | |||||
for (;;) | |||||
{ | |||||
state_vector states = std::move(_runing_states); | |||||
for (state_sptr& sptr : states) | |||||
sptr->resume(); | |||||
} | |||||
} | |||||
}; | |||||
template<class _Ty> | |||||
struct future_t | |||||
{ | |||||
using value_type = _Ty; | |||||
using state_type = state_t<value_type>; | |||||
using promise_type = promise_t<value_type>; | |||||
using future_type = future_t<value_type>; | |||||
std::shared_ptr<state_type> _state; | |||||
future_t(std::shared_ptr<state_type> _st) | |||||
:_state(std::move(_st)) {} | |||||
future_t(const future_t&) = default; | |||||
future_t(future_t&&) = default; | |||||
future_t& operator = (const future_t&) = default; | |||||
future_t& operator = (future_t&&) = default; | |||||
bool await_ready() | |||||
{ | |||||
return _state->has_value(); | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | |||||
void await_suspend(coro::coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
_PromiseT& promise = handler.promise(); | |||||
scheduler_t * sch = promise._state->_scheduler; | |||||
sch->add_await(_state, handler); | |||||
} | |||||
value_type await_resume() | |||||
{ | |||||
if (_state->_exception) | |||||
std::rethrow_exception(std::move(_state->_exception)); | |||||
return std::move(_state->_value.value()); | |||||
} | |||||
void resume() const | |||||
{ | |||||
auto coro_handle = _state->_coro; | |||||
_state->_coro = nullptr; | |||||
coro_handle(); | |||||
} | |||||
}; | |||||
struct suspend_on_initial | |||||
{ | |||||
std::shared_ptr<state_base_t> _state; | |||||
bool await_ready() noexcept | |||||
{ | |||||
return false; | |||||
} | |||||
void await_suspend(coro::coroutine_handle<> handler) noexcept | |||||
{ | |||||
_state->_coro = handler; | |||||
} | |||||
void await_resume() noexcept | |||||
{ | |||||
} | |||||
}; | |||||
template<class _Ty> | |||||
struct promise_impl_t | |||||
{ | |||||
using value_type = _Ty; | |||||
using state_type = state_t<value_type>; | |||||
using promise_type = promise_t<value_type>; | |||||
using future_type = future_t<value_type>; | |||||
std::shared_ptr<state_type> _state = std::make_shared<state_type>(); | |||||
promise_impl_t() {} | |||||
promise_impl_t(const promise_impl_t&) = delete; | |||||
promise_impl_t(promise_impl_t&&) = delete; | |||||
promise_impl_t& operator = (const promise_impl_t&) = delete; | |||||
promise_impl_t& operator = (promise_impl_t&&) = delete; | |||||
auto initial_suspend() noexcept | |||||
{ | |||||
return suspend_on_initial{ _state }; | |||||
} | |||||
auto final_suspend() noexcept | |||||
{ | |||||
return coro::suspend_never{}; | |||||
} | |||||
void set_exception(std::exception_ptr e) | |||||
{ | |||||
_state->_exception = std::move(e); | |||||
if (_state->_scheduler != nullptr) | |||||
_state->_scheduler->add_ready(_state); | |||||
} | |||||
future_t<value_type> get_return_object() | |||||
{ | |||||
return { _state }; | |||||
} | |||||
void cancellation_requested() | |||||
{ | |||||
} | |||||
}; | |||||
template<class _Ty> | |||||
struct promise_t : public promise_impl_t<_Ty> | |||||
{ | |||||
void return_value(value_type val) | |||||
{ | |||||
_state->_value = std::move(val); | |||||
if (_state->_scheduler != nullptr) | |||||
_state->_scheduler->add_ready(_state); | |||||
} | |||||
void yield_value(value_type val) | |||||
{ | |||||
_state->_value = std::move(val); | |||||
if (_state->_scheduler != nullptr) | |||||
_state->_scheduler->add_ready(_state); | |||||
} | |||||
}; | |||||
template<> | |||||
struct promise_t<void> : public promise_impl_t<void> | |||||
{ | |||||
void return_void() | |||||
{ | |||||
_state->_has_value = true; | |||||
if (_state->_scheduler != nullptr) | |||||
_state->_scheduler->add_ready(_state); | |||||
} | |||||
void yield_value() | |||||
{ | |||||
_state->_has_value = true; | |||||
if (_state->_scheduler != nullptr) | |||||
_state->_scheduler->add_ready(_state); | |||||
} | |||||
}; | |||||
template<class _Ty> | |||||
struct awaitable_t | |||||
{ | |||||
using value_type = _Ty; | |||||
using state_type = state_t<value_type>; | |||||
using future_type = future_t<value_type>; | |||||
private: | |||||
mutable std::shared_ptr<state_type> _state = std::make_shared<state_type>(); | |||||
public: | |||||
awaitable_t() {} | |||||
awaitable_t(const awaitable_t&) = default; | |||||
awaitable_t(awaitable_t&&) = default; | |||||
awaitable_t& operator = (const awaitable_t&) = default; | |||||
awaitable_t& operator = (awaitable_t&&) = default; | |||||
void set_value(value_type value) const | |||||
{ | |||||
_state->_value = std::move(value); | |||||
if (_state->_scheduler != nullptr) | |||||
_state->_scheduler->add_ready(_state); | |||||
_state = nullptr; | |||||
} | |||||
void set_exception(std::exception_ptr e) | |||||
{ | |||||
_state->_exception = std::move(e); | |||||
if (_state->_scheduler != nullptr) | |||||
_state->_scheduler->add_ready(_state); | |||||
_state = nullptr; | |||||
} | |||||
future_type get_future() | |||||
{ | |||||
return future_type{ _state }; | |||||
} | |||||
}; | |||||
template<> | |||||
struct awaitable_t<void> | |||||
{ | |||||
using value_type = void; | |||||
using state_type = state_t<>; | |||||
using future_type = future_t<>; | |||||
mutable std::shared_ptr<state_type> _state = std::make_shared<state_type>(); | |||||
awaitable_t() {} | |||||
awaitable_t(const awaitable_t&) = default; | |||||
awaitable_t(awaitable_t&&) = default; | |||||
awaitable_t& operator = (const awaitable_t&) = default; | |||||
awaitable_t& operator = (awaitable_t&&) = default; | |||||
void set_value() const | |||||
{ | |||||
_state->_has_value = true; | |||||
if (_state->_scheduler != nullptr) | |||||
_state->_scheduler->add_ready(_state); | |||||
_state = nullptr; | |||||
} | |||||
void set_exception(std::exception_ptr e) | |||||
{ | |||||
_state->_exception = std::move(e); | |||||
if (_state->_scheduler != nullptr) | |||||
_state->_scheduler->add_ready(_state); | |||||
_state = nullptr; | |||||
} | |||||
future_type get_future() | |||||
{ | |||||
return future_type{ _state }; | |||||
} | |||||
}; | |||||
} | |||||
void async_get_long(int64_t val, std::function<void(int64_t)> cb) | void async_get_long(int64_t val, std::function<void(int64_t)> cb) | ||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
} | } | ||||
//这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | //这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | ||||
librf2::future_t<int64_t> co_get_long(int64_t val) | |||||
resumef::future_t<int64_t> co_get_long(int64_t val) | |||||
{ | { | ||||
librf2::awaitable_t<int64_t > st; | |||||
resumef::awaitable_t<int64_t > st; | |||||
std::cout << "co_get_long@1" << std::endl; | std::cout << "co_get_long@1" << std::endl; | ||||
async_get_long(val, [st](int64_t value) | async_get_long(val, [st](int64_t value) | ||||
} | } | ||||
//这种情况下,会生成对应的 frame-context,一个promise_type被内嵌在frame-context里 | //这种情况下,会生成对应的 frame-context,一个promise_type被内嵌在frame-context里 | ||||
librf2::future_t<> test_librf2() | |||||
resumef::future_t<> test_librf2() | |||||
{ | { | ||||
auto f = co_await co_get_long(2); | auto f = co_await co_get_long(2); | ||||
std::cout << f << std::endl; | std::cout << f << std::endl; | ||||
int main(int argc, const char* argv[]) | int main(int argc, const char* argv[]) | ||||
{ | { | ||||
librf2::scheduler_t sch; | |||||
librf2::future_t<> ft = test_librf2(); | |||||
sch.add_initial(ft._state); | |||||
sch.run(); | |||||
resumable_main_cb(); | |||||
resumable_main_resumable(); | |||||
//resumable_main_benchmark_mem(); | |||||
/* | /* | ||||
resumable_main_resumable(); | |||||
resumable_main_benchmark_mem(); | |||||
if (argc > 1) | if (argc > 1) | ||||
resumable_main_benchmark_asio_client(atoi(argv[1])); | resumable_main_benchmark_asio_client(atoi(argv[1])); | ||||
else | else | ||||
resumable_main_benchmark_asio_server(); | resumable_main_benchmark_asio_server(); | ||||
*/ | |||||
//return 0; | |||||
resumable_main_when_all(); | resumable_main_when_all(); | ||||
resumable_main_multi_thread(); | resumable_main_multi_thread(); | ||||
resumable_main_channel(); | resumable_main_channel(); | ||||
resumable_main_cb(); | resumable_main_cb(); | ||||
resumable_main_exception(); | resumable_main_exception(); | ||||
*/ | |||||
return 0; | return 0; | ||||
} | } |
</Link> | </Link> | ||||
</ItemDefinitionGroup> | </ItemDefinitionGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp" /> | |||||
<ClCompile Include="..\benchmark\benchmark_async_mem.cpp" /> | |||||
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" /> | |||||
<ClCompile Include="..\librf\src\event.cpp" /> | |||||
<ClCompile Include="..\librf\src\mutex.cpp" /> | |||||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\benchmark\benchmark_async_mem.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\event.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\mutex.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\rf_task.cpp" /> | <ClCompile Include="..\librf\src\rf_task.cpp" /> | ||||
<ClCompile Include="..\librf\src\scheduler.cpp" /> | <ClCompile Include="..\librf\src\scheduler.cpp" /> | ||||
<ClCompile Include="..\librf\src\sleep.cpp" /> | |||||
<ClCompile Include="..\librf\src\sleep.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\state.cpp" /> | <ClCompile Include="..\librf\src\state.cpp" /> | ||||
<ClCompile Include="..\librf\src\timer.cpp" /> | <ClCompile Include="..\librf\src\timer.cpp" /> | ||||
<ClCompile Include="..\librf\src\when.cpp" /> | |||||
<ClCompile Include="..\librf\src\when.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_cb.cpp" /> | <ClCompile Include="..\tutorial\test_async_cb.cpp" /> | ||||
<ClCompile Include="..\tutorial\test_async_channel.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_dynamic_go.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_event.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_event_timeout.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_exception.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_modern_cb.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_multi_thread.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_mutex.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_resumable.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_routine.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_sleep.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_suspend_always.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_timer.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_when_all.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_yield_return.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_channel.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_dynamic_go.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_event.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_event_timeout.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_exception.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_modern_cb.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_multi_thread.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_mutex.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_resumable.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_routine.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_sleep.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_suspend_always.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_timer.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_when_all.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_yield_return.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="librf.cpp"> | <ClCompile Include="librf.cpp"> | ||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks> | <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks> | ||||
<BufferSecurityCheck Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</BufferSecurityCheck> | <BufferSecurityCheck Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</BufferSecurityCheck> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ClInclude Include="..\librf\librf.h" /> | <ClInclude Include="..\librf\librf.h" /> | ||||
<ClInclude Include="..\librf\src\asio_task.h" /> | <ClInclude Include="..\librf\src\asio_task.h" /> | ||||
<ClInclude Include="..\librf\src\awaitable.h" /> | |||||
<ClInclude Include="..\librf\src\channel.h" /> | <ClInclude Include="..\librf\src\channel.h" /> | ||||
<ClInclude Include="..\librf\src\counted_ptr.h" /> | <ClInclude Include="..\librf\src\counted_ptr.h" /> | ||||
<ClInclude Include="..\librf\src\def.h" /> | <ClInclude Include="..\librf\src\def.h" /> | ||||
<ClInclude Include="..\librf\src\event.h" /> | <ClInclude Include="..\librf\src\event.h" /> | ||||
<ClInclude Include="..\librf\src\future.h" /> | <ClInclude Include="..\librf\src\future.h" /> | ||||
<ClInclude Include="..\librf\src\generator.h" /> | |||||
<ClInclude Include="..\librf\src\promise.h" /> | |||||
<ClInclude Include="..\librf\src\task_list.h" /> | <ClInclude Include="..\librf\src\task_list.h" /> | ||||
<ClInclude Include="..\librf\src\mutex.h" /> | <ClInclude Include="..\librf\src\mutex.h" /> | ||||
<ClInclude Include="..\librf\src\rf_task.h" /> | <ClInclude Include="..\librf\src\rf_task.h" /> | ||||
<ItemGroup> | <ItemGroup> | ||||
<None Include="..\librf\src\asio_task_1.10.0.inl" /> | <None Include="..\librf\src\asio_task_1.10.0.inl" /> | ||||
<None Include="..\librf\src\asio_task_1.12.0.inl" /> | <None Include="..\librf\src\asio_task_1.12.0.inl" /> | ||||
<None Include="..\librf\src\promise.inl" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | ||||
<ImportGroup Label="ExtensionTargets"> | <ImportGroup Label="ExtensionTargets"> |
<ClInclude Include="..\librf\src\future.h"> | <ClInclude Include="..\librf\src\future.h"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
<ClInclude Include="..\librf\src\generator.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\mutex.h"> | <ClInclude Include="..\librf\src\mutex.h"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
<ClInclude Include="..\librf\src\task_list.h"> | <ClInclude Include="..\librf\src\task_list.h"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
<ClInclude Include="..\librf\src\promise.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\awaitable.h"> | |||||
<Filter>librf</Filter> | |||||
</ClInclude> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<None Include="..\librf\src\asio_task_1.12.0.inl"> | <None Include="..\librf\src\asio_task_1.12.0.inl"> | ||||
<None Include="..\librf\src\asio_task_1.10.0.inl"> | <None Include="..\librf\src\asio_task_1.10.0.inl"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</None> | </None> | ||||
<None Include="..\librf\src\promise.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |