Browse Source

使用新的state/promise/future和调度器,以便于完成调度链传递

tags/v2.9.7
tearshark 4 years ago
parent
commit
1508d08027

+ 4
- 4
benchmark/benchmark_asio_echo.cpp View File

@@ -41,7 +41,7 @@ union uarray
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::array<char, BUF_SIZE> buffer;
@@ -73,7 +73,7 @@ void AcceptConnections(tcp::acceptor & acceptor, uarray<tcp::socket, _N> & socke
{
for (size_t idx = 0; idx < socketes.c.size(); ++idx)
{
go[&, idx]() -> future_vt
go[&, idx]() -> future_t<>
{
for (;;)
{
@@ -147,7 +147,7 @@ void resumable_main_benchmark_asio_server()
//----------------------------------------------------------------------------------------------------------------------
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);
@@ -198,7 +198,7 @@ future_vt RunPipelineEchoClient(asio::io_service & ios, tcp::resolver::iterator
#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 };

+ 1
- 1
benchmark/benchmark_channel_passing_next.cpp View File

@@ -15,7 +15,7 @@ using namespace std::literals;
const static auto MaxNum = 20000;
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 (;;)
{

+ 4
- 1
librf/librf.h View File

@@ -20,7 +20,10 @@
#include "src/mutex.h"
#include "src/channel.h"
#include "src/scheduler.h"
#include "src/promise.inl"
#include "src/sleep.h"
#include "src/awaitable.h"
#if _HAS_CXX17 || RESUMEF_USE_BOOST_ANY
#include "src/when.h"
#endif
#endif

+ 19
- 2
librf/src/counted_ptr.h View File

@@ -3,6 +3,23 @@
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>
struct counted_ptr
{
@@ -26,8 +43,8 @@ namespace resumef
{
if (&cp != this)
{
_unlock();
_lock(cp._p);
counted_ptr t = cp;
std::swap(_p, t._p);
}
return *this;
}

+ 29
- 20
librf/src/def.h View File

@@ -15,6 +15,7 @@
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <optional>
#include <assert.h>
@@ -66,22 +67,6 @@ namespace resumef
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 error_code
{
none,
@@ -95,7 +80,6 @@ namespace resumef
};
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
{
@@ -137,11 +121,36 @@ namespace resumef
}
};
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

+ 30
- 347
librf/src/future.h View File

@@ -5,380 +5,63 @@
namespace resumef
{
template <typename T>
template<class _Ty>
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 & 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()
{
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>
{
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()
{
_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
}

+ 2
- 9
librf/src/rf_task.cpp View File

@@ -5,20 +5,13 @@
namespace resumef
{
task_base::task_base()
task_base_t::task_base_t()
: _next_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
}
}

+ 30
- 127
librf/src/rf_task.h View File

@@ -2,28 +2,21 @@
#include "def.h"
#include "future.h"
#include "promise.h"
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;
};
//----------------------------------------------------------------------------------------------
@@ -31,116 +24,25 @@ namespace resumef
template<class _Ty>
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>
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(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
};
//----------------------------------------------------------------------------------------------
@@ -149,24 +51,25 @@ namespace resumef
//这个'函数对象'被调用后,返回generator<_Ty>/future_t<_Ty>类型
//然后'函数对象'作为异步执行的上下文状态保存起来
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;
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();
}
};
}

+ 23
- 44
librf/src/scheduler.cpp View File

@@ -10,7 +10,6 @@ std::atomic<intptr_t> g_resumef_evtctx_count = 0;
namespace resumef
{
static const char * future_error_string[(size_t)error_code::max__]
{
"none",
@@ -34,12 +33,12 @@ namespace resumef
}
#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
@@ -48,7 +47,7 @@ namespace resumef
#if RESUMEF_ENABLE_MULT_SCHEDULER
if (th_scheduler_ptr == nullptr)
{
_scheduler_ptr = new scheduler;
_scheduler_ptr = new scheduler_t;
th_scheduler_ptr = _scheduler_ptr;
}
#endif
@@ -63,14 +62,14 @@ namespace resumef
#endif
}
scheduler::scheduler()
scheduler_t::scheduler_t()
: _task()
, _ready_task()
, _timer(std::make_shared<timer_manager>())
{
}
scheduler::~scheduler()
scheduler_t::~scheduler_t()
{
cancel_all_task_();
#if RESUMEF_ENABLE_MULT_SCHEDULER
@@ -79,19 +78,18 @@ namespace resumef
#endif
}
void scheduler::new_task(task_base * task)
void scheduler_t::new_task(task_base_t * task)
{
if (task)
{
scoped_lock<spinlock> __guard(_mtx_ready);
#if RESUMEF_ENABLE_MULT_SCHEDULER
task->bind(this);
#endif
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);
@@ -103,7 +101,7 @@ namespace resumef
}
}
void scheduler::break_all()
void scheduler_t::break_all()
{
cancel_all_task_();
@@ -111,7 +109,7 @@ namespace resumef
this->_timer->clear();
}
void scheduler::run_one_batch()
void scheduler_t::run_one_batch()
{
#if RESUMEF_ENABLE_MULT_SCHEDULER
if (th_scheduler_ptr == nullptr)
@@ -122,42 +120,23 @@ namespace resumef
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())
this->run_one_batch();
}
scheduler scheduler::g_scheduler;
void scheduler_t::run()
{
for (;;)
this->run_one_batch();
}
scheduler_t scheduler_t::g_scheduler;
}

+ 46
- 21
librf/src/scheduler.h View File

@@ -14,8 +14,12 @@ namespace resumef
{
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:
//typedef spinlock lock_type;
typedef std::recursive_mutex lock_type;
@@ -27,26 +31,26 @@ namespace resumef
task_list _task;
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_();
public:
RF_API void run_one_batch();
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_)
{
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
@@ -66,17 +70,38 @@ namespace resumef
friend struct task_base;
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:
RF_API scheduler();
RF_API scheduler_t();
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
@@ -90,21 +115,21 @@ namespace resumef
local_scheduler & operator = (const local_scheduler &) = delete;
#if RESUMEF_ENABLE_MULT_SCHEDULER
private:
scheduler * _scheduler_ptr;
scheduler_t* _scheduler_ptr;
#endif
};
//--------------------------------------------------------------------------------------------------
#if !RESUMEF_ENABLE_MULT_SCHEDULER
//获得当前线程下的调度器
inline scheduler * this_scheduler()
inline scheduler_t* this_scheduler()
{
return &scheduler::g_scheduler;
return &scheduler_t::g_scheduler;
}
#endif
#if !defined(_DISABLE_RESUMEF_GO_MACRO)
#define go (*::resumef::this_scheduler()) +
#define GO (*::resumef::this_scheduler()) + [=]()mutable->resumef::future_vt
#define GO (*::resumef::this_scheduler()) + [=]()mutable->resumef::future_t<>
#endif
//--------------------------------------------------------------------------------------------------

+ 1
- 1
librf/src/sleep.cpp View File

@@ -4,7 +4,7 @@
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;

+ 8
- 8
librf/src/sleep.h View File

@@ -6,39 +6,39 @@
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_));
}
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_);
}
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());
}
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_);
}
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());
}
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_);
}

+ 1
- 115
librf/src/state.cpp View File

@@ -5,121 +5,7 @@
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
}

+ 17
- 224
librf/src/state.h View File

@@ -8,255 +8,48 @@
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;
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;
std::atomic<intptr_t> _count{0}; // tracks reference count of state object
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()
{
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>
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<>
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
};
}

+ 5
- 5
librf/src/task_list.h View File

@@ -4,7 +4,7 @@ namespace resumef
{
struct task_list
{
using value_type = task_base;
using value_type = task_base_t;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
@@ -63,8 +63,8 @@ namespace resumef
pointer temp = header;
header = header->_next_node;
if (cancel_)
temp->cancel();
//if (cancel_)
// temp->cancel();
delete temp;
}
}
@@ -93,8 +93,8 @@ namespace resumef
if (_M_last == node)
_M_last = prev;
if (cancel_)
node->cancel();
//if (cancel_)
// node->cancel();
delete node;
return next;

+ 22
- 22
librf/src/when.h View File

@@ -109,7 +109,7 @@ namespace resumef
when_all_functor & operator = (const 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;
_e->signal();
@@ -117,10 +117,10 @@ namespace resumef
};
template<class _Ty>
struct when_all_functor<future_vt, _Ty>
struct when_all_functor<future_t<>, _Ty>
{
using value_type = _Ty;
using future_type = future_vt;
using future_type = future_t<>;
when_impl_ptr _e;
mutable future_type _f;
@@ -135,7 +135,7 @@ namespace resumef
when_all_functor & operator = (const 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;
_val.get() = std::ignore;
@@ -144,12 +144,12 @@ namespace resumef
};
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>
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)};
@@ -157,7 +157,7 @@ namespace resumef
}
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>;
@@ -169,7 +169,7 @@ namespace resumef
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;
@@ -191,7 +191,7 @@ namespace resumef
}
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;
@@ -238,7 +238,7 @@ namespace resumef
when_any_functor & operator = (const 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)
{
@@ -258,10 +258,10 @@ namespace resumef
};
template<>
struct when_any_functor<future_vt>
struct when_any_functor<future_t<>>
{
using value_type = when_any_pair;
using future_type = future_vt;
using future_type = future_t<>;
when_impl_ptr _e;
mutable future_type _f;
@@ -280,7 +280,7 @@ namespace resumef
when_any_functor & operator = (const 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)
{
@@ -299,12 +299,12 @@ namespace resumef
};
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>
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};
@@ -312,7 +312,7 @@ namespace resumef
}
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;
@@ -335,7 +335,7 @@ namespace resumef
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>;
@@ -345,7 +345,7 @@ namespace resumef
}
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;
@@ -368,7 +368,7 @@ namespace resumef
}
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>...>;
auto vals = std::make_shared<tuple_type>();
@@ -381,7 +381,7 @@ namespace resumef
return when_all(*this_scheduler(), std::forward<_Fty>(f)...);
}
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 vector_type = std::vector<value_type>;
@@ -399,7 +399,7 @@ namespace resumef
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{});
@@ -411,7 +411,7 @@ namespace resumef
return when_any(*this_scheduler(), std::forward<_Fty>(f)...);
}
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{});

+ 6
- 6
tutorial/test_async_cb.cpp View File

@@ -21,16 +21,16 @@ void callback_get_long(int64_t val, _Ctype&& cb)
//这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里
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里
resumef::future_vt resumable_get_long(int64_t val)
resumef::future_t<> resumable_get_long(int64_t val)
{
std::cout << val << std::endl;
val = co_await async_get_long(val);
@@ -56,7 +56,7 @@ void resumable_main_cb()
{
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);
std::cout << val << std::endl;

+ 2
- 2
tutorial/test_async_channel.cpp View File

@@ -13,7 +13,7 @@ using namespace resumef;
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;
@@ -41,7 +41,7 @@ future_vt test_channel_read(const channel_t<std::string> & c)
}
}
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;

+ 3
- 3
tutorial/test_async_channel_mult_thread.cpp View File

@@ -18,7 +18,7 @@ std::atomic<intptr_t> gcounter = 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)
{
@@ -46,7 +46,7 @@ future_vt test_channel_consumer(const channel_t<std::string> & c, size_t cnt)
}
}
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)
{
@@ -96,7 +96,7 @@ void resumable_main_channel_mult_thread()
#if !RESUMEF_ENABLE_MULT_SCHEDULER
std::this_thread::sleep_for(100ms);
scheduler::g_scheduler.run_until_notask();
scheduler_t::g_scheduler.run_until_notask();
#endif
for(auto & th : read_th)
th.join();

+ 6
- 6
tutorial/test_async_event.cpp View File

@@ -20,7 +20,7 @@ std::thread async_set_event(const event_t & e, std::chrono::milliseconds dt)
}
future_vt resumable_wait_event(const event_t & e)
future_t<> resumable_wait_event(const event_t & e)
{
using namespace std::chrono;
@@ -44,12 +44,12 @@ void test_wait_one()
}
{
event_t evt2(1);
go[&]() -> future_vt
go[&]() -> future_t<>
{
(void)co_await evt2.wait();
std::cout << "event signal on 1!" << std::endl;
};
go[&]() -> future_vt
go[&]() -> future_t<>
{
(void)co_await evt2.wait();
std::cout << "event signal on 2!" << std::endl;
@@ -69,7 +69,7 @@ void test_wait_any()
event_t evts[8];
go[&]() -> future_vt
go[&]() -> future_t<>
{
for (int i = 0; i < _countof(evts); ++i)
{
@@ -98,7 +98,7 @@ void test_wait_all()
event_t evts[8];
go[&]() -> future_vt
go[&]() -> future_t<>
{
if (co_await event_t::wait_all(evts))
std::cout << "all event signal!" << std::endl;
@@ -126,7 +126,7 @@ void test_wait_all_timeout()
event_t evts[8];
go[&]() -> future_vt
go[&]() -> future_t<>
{
if (co_await event_t::wait_all_for(1000ms, evts))
std::cout << "all event signal!" << std::endl;

+ 6
- 6
tutorial/test_async_event_timeout.cpp View File

@@ -9,7 +9,7 @@
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);
e.signal();
@@ -32,7 +32,7 @@ void test_wait_timeout_one()
event_t evt;
go [&evt]() -> future_vt
go [&evt]() -> future_t<>
{
intptr_t counter = 0;
for (;;)
@@ -59,7 +59,7 @@ void test_wait_timeout_any_invalid()
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));
assert(idx < 0);
@@ -77,7 +77,7 @@ void test_wait_timeout_any()
event_t evts[8];
go[&]() -> future_vt
go[&]() -> future_t<>
{
intptr_t counter = 0;
for (;;)
@@ -116,7 +116,7 @@ void test_wait_timeout_all_invalid()
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));
assert(!result);
@@ -134,7 +134,7 @@ void test_wait_timeout_all()
event_t evts[8];
go[&]() -> future_vt
go[&]() -> future_t<>
{
intptr_t counter = 0;
for (;;)

+ 2
- 2
tutorial/test_async_exception.cpp View File

@@ -49,7 +49,7 @@ auto async_signal_exception2(const intptr_t dividend)
return awaitable.get_future();
}
future_vt test_signal_exception()
future_t<> test_signal_exception()
{
for (intptr_t i = 10; i >= 0; --i)
{
@@ -69,7 +69,7 @@ future_vt test_signal_exception()
}
}
future_vt test_bomb_exception()
future_t<> test_bomb_exception()
{
for (intptr_t i = 10; i >= 0; --i)
{

+ 1
- 1
tutorial/test_async_multi_thread.cpp View File

@@ -86,5 +86,5 @@ void resumable_main_multi_thread()
//运行主调度器里面的协程
//但本范例不应该有协程存在,仅演示不要忽略了主调度器
scheduler::g_scheduler.run_until_notask();
scheduler_t::g_scheduler.run_until_notask();
}

+ 7
- 333
vs_proj/librf.cpp View File

@@ -26,327 +26,6 @@ extern void resumable_main_benchmark_mem();
extern void resumable_main_benchmark_asio_server();
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)
{
using namespace std::chrono;
@@ -358,9 +37,9 @@ void async_get_long(int64_t val, std::function<void(int64_t)> cb)
}
//这种情况下,没有生成 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;
async_get_long(val, [st](int64_t value)
@@ -374,7 +53,7 @@ librf2::future_t<int64_t> co_get_long(int64_t val)
}
//这种情况下,会生成对应的 frame-context,一个promise_type被内嵌在frame-context里
librf2::future_t<> test_librf2()
resumef::future_t<> test_librf2()
{
auto f = co_await co_get_long(2);
std::cout << f << std::endl;
@@ -382,21 +61,15 @@ librf2::future_t<> test_librf2()
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)
resumable_main_benchmark_asio_client(atoi(argv[1]));
else
resumable_main_benchmark_asio_server();
*/
//return 0;
resumable_main_when_all();
resumable_main_multi_thread();
@@ -413,6 +86,7 @@ int main(int argc, const char* argv[])
resumable_main_channel();
resumable_main_cb();
resumable_main_exception();
*/
return 0;
}

+ 95
- 24
vs_proj/librf.vcxproj View File

@@ -180,34 +180,103 @@
</Link>
</ItemDefinitionGroup>
<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\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\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_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">
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks>
<BufferSecurityCheck Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</BufferSecurityCheck>
@@ -217,12 +286,13 @@
<ItemGroup>
<ClInclude Include="..\librf\librf.h" />
<ClInclude Include="..\librf\src\asio_task.h" />
<ClInclude Include="..\librf\src\awaitable.h" />
<ClInclude Include="..\librf\src\channel.h" />
<ClInclude Include="..\librf\src\counted_ptr.h" />
<ClInclude Include="..\librf\src\def.h" />
<ClInclude Include="..\librf\src\event.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\mutex.h" />
<ClInclude Include="..\librf\src\rf_task.h" />
@@ -239,6 +309,7 @@
<ItemGroup>
<None Include="..\librf\src\asio_task_1.10.0.inl" />
<None Include="..\librf\src\asio_task_1.12.0.inl" />
<None Include="..\librf\src\promise.inl" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

+ 9
- 3
vs_proj/librf.vcxproj.filters View File

@@ -132,9 +132,6 @@
<ClInclude Include="..\librf\src\future.h">
<Filter>librf\src</Filter>
</ClInclude>
<ClInclude Include="..\librf\src\generator.h">
<Filter>librf\src</Filter>
</ClInclude>
<ClInclude Include="..\librf\src\mutex.h">
<Filter>librf\src</Filter>
</ClInclude>
@@ -171,6 +168,12 @@
<ClInclude Include="..\librf\src\task_list.h">
<Filter>librf\src</Filter>
</ClInclude>
<ClInclude Include="..\librf\src\promise.h">
<Filter>librf\src</Filter>
</ClInclude>
<ClInclude Include="..\librf\src\awaitable.h">
<Filter>librf</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\librf\src\asio_task_1.12.0.inl">
@@ -179,5 +182,8 @@
<None Include="..\librf\src\asio_task_1.10.0.inl">
<Filter>librf\src</Filter>
</None>
<None Include="..\librf\src\promise.inl">
<Filter>librf\src</Filter>
</None>
</ItemGroup>
</Project>

Loading…
Cancel
Save