#include <thread> | #include <thread> | ||||
#include <iostream> | #include <iostream> | ||||
#include <assert.h> | #include <assert.h> | ||||
#if defined(__clang__) && _WIN32 | |||||
#include "src/unix/coroutine.h" //编译器内建的协程函数,MSVC和clang不一样 | |||||
#else | |||||
#include <experimental/coroutine> | #include <experimental/coroutine> | ||||
#endif | |||||
#include "src/def.h" | #include "src/def.h" | ||||
#include "src/spinlock.h" | #include "src/spinlock.h" | ||||
#include "src/future.h" | #include "src/future.h" | ||||
#include "src/promise.h" | #include "src/promise.h" | ||||
#include "src/awaitable.h" | #include "src/awaitable.h" | ||||
#include "src/switch_scheduler.h" | |||||
#include "src/rf_task.h" | #include "src/rf_task.h" | ||||
#include "src/utils.h" | #include "src/utils.h" | ||||
#include "src/promise.inl" | #include "src/promise.inl" | ||||
#include "src/state.inl" | #include "src/state.inl" | ||||
#include "src/switch_scheduler.h" | |||||
#include "src/_awaker.h" | #include "src/_awaker.h" | ||||
#include "src/event.h" | #include "src/event.h" | ||||
#include "src/mutex.h" | #include "src/mutex.h" |
return future_type{ this->_state }; | return future_type{ this->_state }; | ||||
} | } | ||||
mutable counted_ptr<state_type> _state = _Alloc_state(); | |||||
private: | |||||
static state_type* _Alloc_state() | |||||
{ | |||||
_Alloc_char _Al; | |||||
size_t _Size = sizeof(state_type); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << "awaitable_t::alloc, size=" << _Size << std::endl; | |||||
#endif | |||||
char * _Ptr = _Al.allocate(_Size); | |||||
return new(_Ptr) state_type(true); | |||||
} | |||||
mutable counted_ptr<state_type> _state = state_future_t::_Alloc_state<state_type>(true); | |||||
}; | }; | ||||
template<class _Ty> | template<class _Ty> |
#pragma once | #pragma once | ||||
#define LIB_RESUMEF_VERSION 20201 // 2.2.1 | |||||
#define LIB_RESUMEF_VERSION 20300 // 2.3.0 | |||||
#if defined(RESUMEF_MODULE_EXPORT) | #if defined(RESUMEF_MODULE_EXPORT) | ||||
#define RESUMEF_NS export namespace resumef | #define RESUMEF_NS export namespace resumef | ||||
#define RESUMEF_NS namespace resumef | #define RESUMEF_NS namespace resumef | ||||
#endif | #endif | ||||
//如果不清楚context frame的内存布局的情况下,该值设置为0 | |||||
#if defined(__clang__) || defined(_MSC_VER) | |||||
#define RESUMEF_INLINE_STATE 1 | |||||
#else | |||||
#define RESUMEF_INLINE_STATE 0 | |||||
#endif | |||||
RESUMEF_NS | RESUMEF_NS | ||||
{ | { | ||||
struct scheduler_t; | struct scheduler_t; | ||||
template<class _Ty = void> | template<class _Ty = void> | ||||
struct future_t; | struct future_t; | ||||
using future_vt [[deprecated]] = future_t<>; | using future_vt [[deprecated]] = future_t<>; | ||||
template <typename _Ty = std::nullptr_t, typename _Alloc = std::allocator<char>> | template <typename _Ty = std::nullptr_t, typename _Alloc = std::allocator<char>> | ||||
struct state_base_t; | struct state_base_t; | ||||
struct switch_scheduler_t; | |||||
template<class... _Mutexes> | template<class... _Mutexes> | ||||
using scoped_lock = std::scoped_lock<_Mutexes...>; | using scoped_lock = std::scoped_lock<_Mutexes...>; | ||||
promise_type() | promise_type() | ||||
{ | { | ||||
state_type* st = get_state(); | |||||
new(st) state_type(coroutine_handle<promise_type>::from_promise(*this)); | |||||
st->lock(); | |||||
get_state()->set_initial_suspend(coroutine_handle<promise_type>::from_promise(*this)); | |||||
} | } | ||||
promise_type(promise_type&& _Right) noexcept = default; | promise_type(promise_type&& _Right) noexcept = default; | ||||
promise_type& operator = (promise_type&& _Right) noexcept = default; | promise_type& operator = (promise_type&& _Right) noexcept = default; | ||||
return generator_t{ *this }; | return generator_t{ *this }; | ||||
} | } | ||||
bool initial_suspend() | |||||
std::experimental::suspend_always initial_suspend() | |||||
{ | { | ||||
return true; | |||||
return {}; | |||||
} | } | ||||
bool final_suspend() | |||||
std::experimental::suspend_always final_suspend() | |||||
{ | { | ||||
return true; | |||||
return {}; | |||||
} | } | ||||
void yield_value(_Ty const& _Value) | |||||
std::experimental::suspend_always yield_value(_Ty const& _Value) | |||||
{ | { | ||||
_CurrentValue = std::addressof(_Value); | _CurrentValue = std::addressof(_Value); | ||||
return {}; | |||||
} | } | ||||
//template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>> | //template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>> | ||||
state_type* get_state() | state_type* get_state() | ||||
{ | { | ||||
#if RESUMEF_INLINE_STATE | |||||
size_t _State_size = _Align_size<state_type>(); | size_t _State_size = _Align_size<state_type>(); | ||||
#if defined(__clang__) | |||||
auto h = coroutine_handle<promise_type>::from_promise(*this); | |||||
char* ptr = reinterpret_cast<char*>(h.address()) - _State_size; | |||||
return reinterpret_cast<state_type*>(ptr); | |||||
#elif defined(_MSC_VER) | |||||
char* ptr = reinterpret_cast<char*>(this) - _State_size; | char* ptr = reinterpret_cast<char*>(this) - _State_size; | ||||
return reinterpret_cast<state_type*>(ptr); | return reinterpret_cast<state_type*>(ptr); | ||||
#else | |||||
#error "Unknown compiler" | |||||
#endif | |||||
#else | |||||
return _state.get(); | |||||
#endif | |||||
} | } | ||||
using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc<char>; | using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc<char>; | ||||
void* operator new(size_t _Size) | void* operator new(size_t _Size) | ||||
{ | { | ||||
_Alloc_char _Al; | |||||
#if RESUMEF_INLINE_STATE | |||||
size_t _State_size = _Align_size<state_type>(); | size_t _State_size = _Align_size<state_type>(); | ||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | ||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << "generator_promise::new, size=" << (_Size + _State_size) << std::endl; | |||||
#endif | |||||
_Alloc_char _Al; | |||||
char* ptr = _Al.allocate(_Size + _State_size); | char* ptr = _Al.allocate(_Size + _State_size); | ||||
char* _Rptr = ptr + _State_size; | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << " generator_promise::new, alloc size=" << (_Size + _State_size) << std::endl; | |||||
std::cout << " generator_promise::new, alloc ptr=" << (void*)ptr << std::endl; | |||||
std::cout << " generator_promise::new, return ptr=" << (void*)_Rptr << std::endl; | |||||
#endif | |||||
//ÔÚ³õʼµØÖ·ÉϹ¹Ôìstate | //ÔÚ³õʼµØÖ·ÉϹ¹Ôìstate | ||||
{ | { | ||||
state_type* st = new(ptr) state_type(coroutine_handle<promise_type>::from_promise(*(promise_type *)ptr)); | |||||
state_type* st = new(ptr) state_type(); | |||||
st->lock(); | st->lock(); | ||||
*reinterpret_cast<uint32_t*>(ptr + _State_size) = static_cast<uint32_t>(_Size + _State_size); | |||||
} | } | ||||
return ptr + _State_size; | |||||
return _Rptr; | |||||
#else | |||||
char* ptr = _Al.allocate(_Size); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << " generator_promise::new, alloc size=" << _Size << std::endl; | |||||
std::cout << " generator_promise::new, alloc ptr=" << (void*)ptr << std::endl; | |||||
std::cout << " generator_promise::new, return ptr=" << (void*)ptr << std::endl; | |||||
#endif | |||||
return ptr; | |||||
#endif | |||||
} | } | ||||
void operator delete(void* _Ptr, size_t _Size) | void operator delete(void* _Ptr, size_t _Size) | ||||
{ | { | ||||
#if RESUMEF_INLINE_STATE | |||||
size_t _State_size = _Align_size<state_type>(); | size_t _State_size = _Align_size<state_type>(); | ||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | ||||
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | ||||
st->unlock(); | st->unlock(); | ||||
#else | |||||
_Alloc_char _Al; | |||||
return _Al.deallocate(reinterpret_cast<char *>(_Ptr), _Size); | |||||
#endif | |||||
} | } | ||||
#if !RESUMEF_INLINE_STATE | |||||
private: | |||||
counted_ptr<state_type> _state = state_generator_t::_Alloc_state(); | |||||
#endif | |||||
}; | }; | ||||
typedef generator_iterator<_Ty, promise_type> iterator; | typedef generator_iterator<_Ty, promise_type> iterator; |
promise_impl_t(const promise_impl_t&) = delete; | promise_impl_t(const promise_impl_t&) = delete; | ||||
promise_impl_t& operator = (const promise_impl_t&) = delete; | promise_impl_t& operator = (const promise_impl_t&) = delete; | ||||
state_type* get_state() | |||||
{ | |||||
size_t _State_size = _Align_size<state_type>(); | |||||
char* ptr = reinterpret_cast<char*>(this) - _State_size; | |||||
return reinterpret_cast<state_type*>(ptr); | |||||
} | |||||
auto get_state()->state_type*; | |||||
suspend_on_initial initial_suspend() noexcept; | suspend_on_initial initial_suspend() noexcept; | ||||
suspend_on_final final_suspend() noexcept; | suspend_on_final final_suspend() noexcept; | ||||
void set_exception(std::exception_ptr e); | void set_exception(std::exception_ptr e); | ||||
void cancellation_requested(); | void cancellation_requested(); | ||||
using _Alloc_char = std::allocator<char>; | using _Alloc_char = std::allocator<char>; | ||||
void* operator new(size_t _Size) | |||||
{ | |||||
size_t _State_size = _Align_size<state_type>(); | |||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | |||||
_Alloc_char _Al; | |||||
/*If allocation fails, the coroutine throws std::bad_alloc, | |||||
unless the Promise type defines the member function Promise::get_return_object_on_allocation_failure(). | |||||
If that member function is defined, allocation uses the nothrow form of operator new and on allocation failure, | |||||
the coroutine immediately returns the object obtained from Promise::get_return_object_on_allocation_failure() to the caller. | |||||
*/ | |||||
char* ptr = _Al.allocate(_Size + _State_size); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << " future_promise::new, alloc size=" << (_Size + _State_size) << std::endl; | |||||
std::cout << " future_promise::new, alloc ptr=" << (void*)ptr << std::endl; | |||||
std::cout << " future_promise::new, return ptr=" << (void*)(ptr + _State_size) << std::endl; | |||||
void* operator new(size_t _Size); | |||||
void operator delete(void* _Ptr, size_t _Size); | |||||
#if !RESUMEF_INLINE_STATE | |||||
private: | |||||
counted_ptr<state_type> _state = state_future_t::_Alloc_state<state_type>(false); | |||||
#endif | #endif | ||||
//在初始地址上构造state | |||||
{ | |||||
state_type* st = new(ptr) state_type(_Size + _State_size); | |||||
st->lock(); | |||||
} | |||||
return ptr + _State_size; | |||||
} | |||||
void operator delete(void* _Ptr, size_t _Size) | |||||
{ | |||||
(void)_Size; | |||||
size_t _State_size = _Align_size<state_type>(); | |||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | |||||
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | |||||
st->unlock(); | |||||
} | |||||
}; | }; | ||||
template<class _Ty> | template<class _Ty> | ||||
template<class U> | template<class U> | ||||
void return_value(U&& val); //co_return val | void return_value(U&& val); //co_return val | ||||
template<class U> | template<class U> | ||||
void yield_value(U&& val); | |||||
std::experimental::suspend_always yield_value(U&& val); | |||||
}; | }; | ||||
template<> | template<> | ||||
using promise_impl_t<void>::get_return_object; | using promise_impl_t<void>::get_return_object; | ||||
void return_void(); //co_return; | void return_void(); //co_return; | ||||
void yield_value(); | |||||
std::experimental::suspend_always yield_value(); | |||||
}; | }; | ||||
} | } |
{ | { | ||||
} | } | ||||
}; | }; | ||||
struct suspend_on_final | struct suspend_on_final | ||||
{ | { | ||||
inline bool await_ready() noexcept | inline bool await_ready() noexcept | ||||
} | } | ||||
template <typename _Ty> | |||||
auto promise_impl_t<_Ty>::get_state() -> state_type* | |||||
{ | |||||
#if RESUMEF_INLINE_STATE | |||||
size_t _State_size = _Align_size<state_type>(); | |||||
#if defined(__clang__) | |||||
auto h = coroutine_handle<promise_type>::from_promise(*reinterpret_cast<promise_type *>(this)); | |||||
char* ptr = reinterpret_cast<char*>(h.address()) - _State_size; | |||||
return reinterpret_cast<state_type*>(ptr); | |||||
#elif defined(_MSC_VER) | |||||
char* ptr = reinterpret_cast<char*>(this) - _State_size; | |||||
return reinterpret_cast<state_type*>(ptr); | |||||
#else | |||||
#error "Unknown compiler" | |||||
#endif | |||||
#else | |||||
return _state.get(); | |||||
#endif | |||||
} | |||||
template <typename _Ty> | |||||
void* promise_impl_t<_Ty>::operator new(size_t _Size) | |||||
{ | |||||
_Alloc_char _Al; | |||||
#if RESUMEF_INLINE_STATE | |||||
size_t _State_size = _Align_size<state_type>(); | |||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | |||||
/*If allocation fails, the coroutine throws std::bad_alloc, | |||||
unless the Promise type defines the member function Promise::get_return_object_on_allocation_failure(). | |||||
If that member function is defined, allocation uses the nothrow form of operator new and on allocation failure, | |||||
the coroutine immediately returns the object obtained from Promise::get_return_object_on_allocation_failure() to the caller. | |||||
*/ | |||||
char* ptr = _Al.allocate(_Size + _State_size); | |||||
char* _Rptr = ptr + _State_size; | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << " future_promise::new, alloc size=" << (_Size + _State_size) << std::endl; | |||||
std::cout << " future_promise::new, alloc ptr=" << (void*)ptr << std::endl; | |||||
std::cout << " future_promise::new, return ptr=" << (void*)_Rptr << std::endl; | |||||
#endif | |||||
//在初始地址上构造state | |||||
{ | |||||
state_type* st = new(ptr) state_type(_Size + _State_size); | |||||
st->lock(); | |||||
} | |||||
return _Rptr; | |||||
#else | |||||
char* ptr = _Al.allocate(_Size); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << " future_promise::new, alloc size=" << (_Size) << std::endl; | |||||
std::cout << " future_promise::new, alloc ptr=" << (void*)ptr << std::endl; | |||||
std::cout << " future_promise::new, return ptr=" << (void*)ptr << std::endl; | |||||
#endif | |||||
return ptr; | |||||
#endif | |||||
} | |||||
template <typename _Ty> | |||||
void promise_impl_t<_Ty>::operator delete(void* _Ptr, size_t _Size) | |||||
{ | |||||
#if RESUMEF_INLINE_STATE | |||||
(void)_Size; | |||||
size_t _State_size = _Align_size<state_type>(); | |||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | |||||
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | |||||
st->unlock(); | |||||
#else | |||||
_Alloc_char _Al; | |||||
return _Al.deallocate(reinterpret_cast<char*>(_Ptr), _Size); | |||||
#endif | |||||
} | |||||
template<class _Ty> | template<class _Ty> | ||||
template<class U> | template<class U> | ||||
template<class _Ty> | template<class _Ty> | ||||
template<class U> | template<class U> | ||||
inline void promise_t<_Ty>::yield_value(U&& val) | |||||
inline std::experimental::suspend_always promise_t<_Ty>::yield_value(U&& val) | |||||
{ | { | ||||
this->get_state()->promise_yield_value(this, std::forward<U>(val)); | this->get_state()->promise_yield_value(this, std::forward<U>(val)); | ||||
return {}; | |||||
} | } | ||||
inline void promise_t<void>::return_void() | inline void promise_t<void>::return_void() | ||||
this->get_state()->set_value(); | this->get_state()->set_value(); | ||||
} | } | ||||
inline void promise_t<void>::yield_value() | |||||
inline std::experimental::suspend_always promise_t<void>::yield_value() | |||||
{ | { | ||||
this->get_state()->promise_yield_value(this); | this->get_state()->promise_yield_value(this); | ||||
return {}; | |||||
} | } | ||||
} | } | ||||
std::unique_ptr<task_base_t> del_switch(state_base_t* sptr); | std::unique_ptr<task_base_t> del_switch(state_base_t* sptr); | ||||
void add_switch(std::unique_ptr<task_base_t> task); | void add_switch(std::unique_ptr<task_base_t> task); | ||||
switch_scheduler_t operator co_await() | |||||
{ | |||||
return { this }; | |||||
} | |||||
friend struct task_base; | |||||
friend struct local_scheduler; | friend struct local_scheduler; | ||||
protected: | protected: | ||||
scheduler_t(); | scheduler_t(); |
void state_generator_t::destroy_deallocate() | void state_generator_t::destroy_deallocate() | ||||
{ | { | ||||
size_t _Size = _Align_size<state_generator_t>(); | size_t _Size = _Align_size<state_generator_t>(); | ||||
#if RESUMEF_INLINE_STATE | |||||
char* _Ptr = reinterpret_cast<char*>(this) + _Size; | char* _Ptr = reinterpret_cast<char*>(this) + _Size; | ||||
_Size = *reinterpret_cast<uint32_t*>(_Ptr); | _Size = *reinterpret_cast<uint32_t*>(_Ptr); | ||||
#endif | |||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
std::cout << "destroy_deallocate, size=" << _Size << std::endl; | std::cout << "destroy_deallocate, size=" << _Size << std::endl; | ||||
#endif | #endif | ||||
void state_generator_t::resume() | void state_generator_t::resume() | ||||
{ | { | ||||
if (_coro != nullptr) | |||||
if (_coro) | |||||
{ | { | ||||
_coro.resume(); | _coro.resume(); | ||||
if (_coro.done()) | if (_coro.done()) | ||||
bool state_generator_t::is_ready() const | bool state_generator_t::is_ready() const | ||||
{ | { | ||||
return _coro != nullptr && !_coro.done(); | |||||
return (bool)_coro && !_coro.done(); | |||||
} | } | ||||
bool state_generator_t::has_handler() const | bool state_generator_t::has_handler() const | ||||
{ | { | ||||
return _coro != nullptr; | |||||
return (bool)_coro; | |||||
} | } | ||||
bool state_generator_t::switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<>) | bool state_generator_t::switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<>) | ||||
if (_is_initor == initor_type::Initial) | if (_is_initor == initor_type::Initial) | ||||
{ | { | ||||
assert(_initor != nullptr); | |||||
assert((bool)_initor); | |||||
_is_initor = initor_type::None; | _is_initor = initor_type::None; | ||||
__guard.unlock(); | __guard.unlock(); | ||||
return; | return; | ||||
} | } | ||||
if (_coro != nullptr) | |||||
if (_coro) | |||||
{ | { | ||||
coroutine_handle<> handler = _coro; | coroutine_handle<> handler = _coro; | ||||
_coro = nullptr; | _coro = nullptr; | ||||
if (_is_initor == initor_type::Final) | if (_is_initor == initor_type::Final) | ||||
{ | { | ||||
assert((bool)_initor); | |||||
_is_initor = initor_type::None; | _is_initor = initor_type::None; | ||||
__guard.unlock(); | __guard.unlock(); | ||||
bool state_future_t::has_handler() const | bool state_future_t::has_handler() const | ||||
{ | { | ||||
scoped_lock<lock_type> __guard(_mtx); | scoped_lock<lock_type> __guard(_mtx); | ||||
return _coro != nullptr || _is_initor != initor_type::None; | |||||
return (bool)_coro || _is_initor != initor_type::None; | |||||
} | } | ||||
bool state_future_t::is_ready() const | bool state_future_t::is_ready() const | ||||
if (_parent != nullptr) | if (_parent != nullptr) | ||||
_parent->switch_scheduler_await_suspend(sch, nullptr); | _parent->switch_scheduler_await_suspend(sch, nullptr); | ||||
if (handler != nullptr) | |||||
if (handler) | |||||
{ | { | ||||
_coro = handler; | _coro = handler; | ||||
sch->add_generator(this); | sch->add_generator(this); |
struct state_generator_t : public state_base_t | struct state_generator_t : public state_base_t | ||||
{ | { | ||||
state_generator_t(coroutine_handle<> handler) | |||||
{ | |||||
_coro = handler; | |||||
} | |||||
private: | private: | ||||
virtual void destroy_deallocate() override; | virtual void destroy_deallocate() override; | ||||
public: | public: | ||||
virtual bool is_ready() const override; | virtual bool is_ready() const override; | ||||
virtual bool switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<> handler) override; | virtual bool switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<> handler) override; | ||||
static state_generator_t * _Alloc_state(coroutine_handle<> handler) | |||||
void set_initial_suspend(coroutine_handle<> handler) | |||||
{ | |||||
_coro = handler; | |||||
} | |||||
static state_generator_t * _Alloc_state() | |||||
{ | { | ||||
_Alloc_char _Al; | |||||
size_t _Size = sizeof(state_generator_t); | |||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
std::cout << "state_generator_t::alloc, size=" << sizeof(state_generator_t) << std::endl; | std::cout << "state_generator_t::alloc, size=" << sizeof(state_generator_t) << std::endl; | ||||
#endif | #endif | ||||
return new state_generator_t(handler); | |||||
char* _Ptr = _Al.allocate(_Size); | |||||
return new(_Ptr) state_generator_t(); | |||||
} | } | ||||
}; | }; | ||||
void promise_initial_suspend(coroutine_handle<_PromiseT> handler); | void promise_initial_suspend(coroutine_handle<_PromiseT> handler); | ||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | ||||
void promise_final_suspend(coroutine_handle<_PromiseT> handler); | void promise_final_suspend(coroutine_handle<_PromiseT> handler); | ||||
template<class _Sty> | |||||
static _Sty* _Alloc_state(bool awaitor) | |||||
{ | |||||
_Alloc_char _Al; | |||||
size_t _Size = sizeof(_Sty); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << "state_future_t::alloc, size=" << _Size << std::endl; | |||||
#endif | |||||
char* _Ptr = _Al.allocate(_Size); | |||||
return new(_Ptr) _Sty(awaitor); | |||||
} | |||||
}; | }; | ||||
template <typename _Ty> | template <typename _Ty> | ||||
struct state_t final : public state_future_t | struct state_t final : public state_future_t | ||||
{ | { | ||||
friend state_future_t; | |||||
using state_future_t::lock_type; | using state_future_t::lock_type; | ||||
using value_type = _Ty; | using value_type = _Ty; | ||||
{ | { | ||||
_alloc_size = sizeof(*this); | _alloc_size = sizeof(*this); | ||||
} | } | ||||
public: | |||||
~state_t() | ~state_t() | ||||
{ | { | ||||
if (_has_value) | if (_has_value) | ||||
template<> | template<> | ||||
struct state_t<void> final : public state_future_t | struct state_t<void> final : public state_future_t | ||||
{ | { | ||||
friend state_future_t; | |||||
using state_future_t::lock_type; | using state_future_t::lock_type; | ||||
explicit state_t(size_t alloc_size) :state_future_t() | explicit state_t(size_t alloc_size) :state_future_t() |
void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler) | void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler) | ||||
{ | { | ||||
assert(this->_scheduler == nullptr); | assert(this->_scheduler == nullptr); | ||||
assert(this->_coro == nullptr); | |||||
assert(!this->_coro); | |||||
this->_initor = handler; | this->_initor = handler; | ||||
this->_is_initor = initor_type::Initial; | this->_is_initor = initor_type::Initial; | ||||
this->_parent = parent_state; | this->_parent = parent_state; | ||||
this->_scheduler = sch; | this->_scheduler = sch; | ||||
} | } | ||||
if (_coro == nullptr) | |||||
if (!_coro) | |||||
this->_coro = handler; | this->_coro = handler; | ||||
if (sch != nullptr) | if (sch != nullptr) | ||||
coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise); | coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise); | ||||
if (!handler.done()) | if (!handler.done()) | ||||
{ | { | ||||
if (this->_coro == nullptr) | |||||
if (!this->_coro) | |||||
this->_coro = handler; | this->_coro = handler; | ||||
scheduler_t* sch = this->get_scheduler(); | scheduler_t* sch = this->get_scheduler(); | ||||
if (sch != nullptr) | if (sch != nullptr) |
scheduler_t* _scheduler; | scheduler_t* _scheduler; | ||||
}; | }; | ||||
inline switch_scheduler_t via(scheduler_t* sch) | |||||
inline switch_scheduler_t operator co_await(scheduler_t& sch) | |||||
{ | { | ||||
return { sch }; | |||||
return { &sch }; | |||||
} | } | ||||
} | } |
struct is_generator<generator_t<_Ty, _Alloc>> : std::true_type {}; | struct is_generator<generator_t<_Ty, _Alloc>> : std::true_type {}; | ||||
template<class _Ty> | template<class _Ty> | ||||
constexpr bool is_generator_v = is_generator<remove_cvref_t<_Ty>>::value; | constexpr bool is_generator_v = is_generator<remove_cvref_t<_Ty>>::value; | ||||
template<class _PromiseT> | |||||
struct is_awaitable : std::false_type {}; | |||||
template<class _Ty> | |||||
struct is_awaitable<awaitable_t<_Ty>> : std::true_type {}; | |||||
template<class _Ty> | |||||
constexpr bool is_awaitable_v = is_awaitable<remove_cvref_t<_Ty>>::value; | |||||
template<class _Ty> | |||||
constexpr bool is_await_suspend_v = is_future_v<_Ty> | |||||
|| is_generator_v<_Ty> | |||||
|| is_awaitable_v<_Ty> | |||||
|| std::is_same_v<remove_cvref_t<_Ty>, switch_scheduler_t> | |||||
; | |||||
} | } |
//#pragma once | |||||
//===----------------------------- coroutine -----------------------------===// | |||||
// | |||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||||
// See https://llvm.org/LICENSE.txt for license information. | |||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||||
// | |||||
//===----------------------------------------------------------------------===// | |||||
#ifndef _LIBCPP_EXPERIMENTAL_COROUTINE | |||||
#define _LIBCPP_EXPERIMENTAL_COROUTINE | |||||
/** | |||||
experimental/coroutine synopsis | |||||
// C++next | |||||
namespace std { | namespace std { | ||||
namespace experimental { | |||||
template <typename R, typename...> struct coroutine_traits { | |||||
using promise_type = typename R::promise_type; | |||||
}; | |||||
template <typename Promise = void> struct coroutine_handle; | |||||
template <> struct coroutine_handle<void> { | |||||
static coroutine_handle from_address(void *addr) noexcept { | |||||
coroutine_handle me; | |||||
me.ptr = addr; | |||||
return me; | |||||
} | |||||
void operator()() { resume(); } | |||||
void *address() const { return ptr; } | |||||
void resume() const { __builtin_coro_resume(ptr); } | |||||
void destroy() const { __builtin_coro_destroy(ptr); } | |||||
bool done() const { return __builtin_coro_done(ptr); } | |||||
coroutine_handle &operator=(decltype(nullptr)) { | |||||
ptr = nullptr; | |||||
return *this; | |||||
} | |||||
coroutine_handle(decltype(nullptr)) : ptr(nullptr) {} | |||||
coroutine_handle() : ptr(nullptr) {} | |||||
// void reset() { ptr = nullptr; } // add to P0057? | |||||
explicit operator bool() const { return ptr; } | |||||
protected: | |||||
void *ptr; | |||||
}; | |||||
template <typename Promise> struct coroutine_handle : coroutine_handle<> { | |||||
static coroutine_handle from_address(void *addr) noexcept { | |||||
coroutine_handle me; | |||||
me.ptr = addr; | |||||
return me; | |||||
} | |||||
coroutine_handle() {} | |||||
coroutine_handle(decltype(nullptr)) {} | |||||
coroutine_handle &operator=(decltype(nullptr)) { | |||||
ptr = nullptr; | |||||
return *this; | |||||
} | |||||
Promise &promise() const { | |||||
return *reinterpret_cast<Promise *>( | |||||
__builtin_coro_promise(ptr, alignof(Promise), false)); | |||||
} | |||||
static coroutine_handle from_promise(Promise &promise) { | |||||
coroutine_handle p; | |||||
p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true); | |||||
return p; | |||||
} | |||||
}; | |||||
template <typename _PromiseT> | |||||
bool operator==(coroutine_handle<_PromiseT> const &_Left, | |||||
coroutine_handle<_PromiseT> const &_Right) noexcept { | |||||
return _Left.address() == _Right.address(); | |||||
} | |||||
namespace experimental { | |||||
inline namespace coroutines_v1 { | |||||
template <typename _PromiseT> | |||||
bool operator!=(coroutine_handle<_PromiseT> const &_Left, | |||||
coroutine_handle<_PromiseT> const &_Right) noexcept { | |||||
return !(_Left == _Right); | |||||
} | |||||
// 18.11.1 coroutine traits | |||||
template <typename R, typename... ArgTypes> | |||||
class coroutine_traits; | |||||
// 18.11.2 coroutine handle | |||||
template <typename Promise = void> | |||||
class coroutine_handle; | |||||
// 18.11.2.7 comparison operators: | |||||
bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept; | |||||
bool operator!=(coroutine_handle<> x, coroutine_handle<> y) noexcept; | |||||
bool operator<(coroutine_handle<> x, coroutine_handle<> y) noexcept; | |||||
bool operator<=(coroutine_handle<> x, coroutine_handle<> y) noexcept; | |||||
bool operator>=(coroutine_handle<> x, coroutine_handle<> y) noexcept; | |||||
bool operator>(coroutine_handle<> x, coroutine_handle<> y) noexcept; | |||||
// 18.11.3 trivial awaitables | |||||
struct suspend_never; | |||||
struct suspend_always; | |||||
// 18.11.2.8 hash support: | |||||
template <class T> struct hash; | |||||
template <class P> struct hash<coroutine_handle<P>>; | |||||
struct suspend_always { | |||||
bool await_ready() { return false; } | |||||
void await_suspend(coroutine_handle<>) {} | |||||
void await_resume() {} | |||||
}; | |||||
struct suspend_never { | |||||
bool await_ready() { return true; } | |||||
void await_suspend(coroutine_handle<>) {} | |||||
void await_resume() {} | |||||
}; | |||||
struct suspend_if { | |||||
bool _Ready; | |||||
explicit suspend_if(bool _Condition) : _Ready(!_Condition) {} | |||||
bool await_ready() { return _Ready; } | |||||
void await_suspend(coroutine_handle<>) {} | |||||
void await_resume() {} | |||||
}; | |||||
} | |||||
} // namespace coroutines_v1 | |||||
} // namespace experimental | |||||
} // namespace std | |||||
*/ | |||||
#include <new> | |||||
#include <type_traits> | |||||
#include <functional> | |||||
#include <memory> // for hash<T*> | |||||
#include <cstddef> | |||||
#include <cassert> | |||||
#include "clang_builtin.h" | |||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | |||||
#pragma GCC system_header | |||||
#endif | |||||
#ifndef _LIBCPP_HAS_NO_COROUTINES | |||||
namespace std { | |||||
namespace experimental { | |||||
template <class _Tp, class = void> | |||||
struct __coroutine_traits_sfinae {}; | |||||
template <class _Tp> | |||||
struct __coroutine_traits_sfinae<_Tp, void_t<typename _Tp::promise_type>> | |||||
{ | |||||
using promise_type = typename _Tp::promise_type; | |||||
}; | |||||
template <typename _Ret, typename... _Args> | |||||
struct coroutine_traits : public __coroutine_traits_sfinae<_Ret> | |||||
{ | |||||
}; | |||||
template <typename _Promise = void> | |||||
class coroutine_handle; | |||||
template <> | |||||
class coroutine_handle<void> { | |||||
public: | |||||
constexpr coroutine_handle() noexcept : __handle_(nullptr) {} | |||||
constexpr coroutine_handle(nullptr_t) noexcept : __handle_(nullptr) {} | |||||
coroutine_handle& operator=(nullptr_t) noexcept { | |||||
__handle_ = nullptr; | |||||
return *this; | |||||
} | |||||
constexpr void* address() const noexcept { return __handle_; } | |||||
constexpr explicit operator bool() const noexcept { return __handle_; } | |||||
void operator()() { resume(); } | |||||
void resume() { | |||||
__builtin_coro_resume(__handle_); | |||||
} | |||||
void destroy() { | |||||
__builtin_coro_destroy(__handle_); | |||||
} | |||||
bool done() const { | |||||
return __builtin_coro_done(__handle_); | |||||
} | |||||
public: | |||||
static coroutine_handle from_address(void* __addr) noexcept { | |||||
coroutine_handle __tmp; | |||||
__tmp.__handle_ = __addr; | |||||
return __tmp; | |||||
} | |||||
// FIXME: Should from_address(nullptr) be allowed? | |||||
static coroutine_handle from_address(nullptr_t) noexcept { | |||||
return coroutine_handle(nullptr); | |||||
} | |||||
template <class _Tp, bool _CallIsValid = false> | |||||
static coroutine_handle from_address(_Tp*) { | |||||
static_assert(_CallIsValid, | |||||
"coroutine_handle<void>::from_address cannot be called with " | |||||
"non-void pointers"); | |||||
} | |||||
private: | |||||
bool __is_suspended() const noexcept { | |||||
// FIXME actually implement a check for if the coro is suspended. | |||||
return __handle_; | |||||
} | |||||
template <class _PromiseT> | |||||
friend class coroutine_handle; | |||||
void* __handle_; | |||||
}; | |||||
// 18.11.2.7 comparison operators: | |||||
inline bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { | |||||
return __x.address() == __y.address(); | |||||
} | |||||
inline bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { | |||||
return !(__x == __y); | |||||
} | |||||
inline bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { | |||||
return less<void*>()(__x.address(), __y.address()); | |||||
} | |||||
inline bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { | |||||
return __y < __x; | |||||
} | |||||
inline bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { | |||||
return !(__x > __y); | |||||
} | |||||
inline bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { | |||||
return !(__x < __y); | |||||
} | |||||
template <typename _Promise> | |||||
class coroutine_handle : public coroutine_handle<> { | |||||
using _Base = coroutine_handle<>; | |||||
public: | |||||
#ifndef _LIBCPP_CXX03_LANG | |||||
// 18.11.2.1 construct/reset | |||||
using coroutine_handle<>::coroutine_handle; | |||||
#else | |||||
coroutine_handle() noexcept : _Base() {} | |||||
coroutine_handle(nullptr_t) noexcept : _Base(nullptr) {} | |||||
#endif | |||||
coroutine_handle& operator=(nullptr_t) noexcept { | |||||
_Base::operator=(nullptr); | |||||
return *this; | |||||
} | |||||
_Promise& promise() const { | |||||
return *static_cast<_Promise*>( | |||||
__builtin_coro_promise(this->__handle_, alignof(_Promise), false)); | |||||
} | |||||
public: | |||||
static coroutine_handle from_address(void* __addr) noexcept { | |||||
coroutine_handle __tmp; | |||||
__tmp.__handle_ = __addr; | |||||
return __tmp; | |||||
} | |||||
// NOTE: this overload isn't required by the standard but is needed so | |||||
// the deleted _Promise* overload doesn't make from_address(nullptr) | |||||
// ambiguous. | |||||
// FIXME: should from_address work with nullptr? | |||||
static coroutine_handle from_address(nullptr_t) noexcept { | |||||
return coroutine_handle(nullptr); | |||||
} | |||||
template <class _Tp, bool _CallIsValid = false> | |||||
static coroutine_handle from_address(_Tp*) { | |||||
static_assert(_CallIsValid, | |||||
"coroutine_handle<promise_type>::from_address cannot be called with " | |||||
"non-void pointers"); | |||||
} | |||||
template <bool _CallIsValid = false> | |||||
static coroutine_handle from_address(_Promise*) { | |||||
static_assert(_CallIsValid, | |||||
"coroutine_handle<promise_type>::from_address cannot be used with " | |||||
"pointers to the coroutine's promise type; use 'from_promise' instead"); | |||||
} | |||||
static coroutine_handle from_promise(_Promise& __promise) noexcept { | |||||
typedef typename remove_cv<_Promise>::type _RawPromise; | |||||
coroutine_handle __tmp; | |||||
__tmp.__handle_ = __builtin_coro_promise( | |||||
std::addressof(const_cast<_RawPromise&>(__promise)), | |||||
alignof(_Promise), true); | |||||
return __tmp; | |||||
} | |||||
}; | |||||
#if __has_builtin(__builtin_coro_noop) | |||||
struct noop_coroutine_promise {}; | |||||
template <> | |||||
class coroutine_handle<noop_coroutine_promise> | |||||
: public coroutine_handle<> { | |||||
using _Base = coroutine_handle<>; | |||||
using _Promise = noop_coroutine_promise; | |||||
public: | |||||
_Promise& promise() const { | |||||
return *static_cast<_Promise*>( | |||||
__builtin_coro_promise(this->__handle_, alignof(_Promise), false)); | |||||
} | |||||
constexpr explicit operator bool() const noexcept { return true; } | |||||
constexpr bool done() const noexcept { return false; } | |||||
constexpr void operator()() const noexcept {} | |||||
constexpr void resume() const noexcept {} | |||||
constexpr void destroy() const noexcept {} | |||||
private: | |||||
friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept; | |||||
coroutine_handle() noexcept { | |||||
this->__handle_ = __builtin_coro_noop(); | |||||
} | |||||
}; | |||||
using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; | |||||
inline noop_coroutine_handle noop_coroutine() noexcept { | |||||
return noop_coroutine_handle(); | |||||
} | |||||
#endif // __has_builtin(__builtin_coro_noop) | |||||
struct suspend_never { | |||||
bool await_ready() const noexcept { return true; } | |||||
void await_suspend(coroutine_handle<>) const noexcept {} | |||||
void await_resume() const noexcept {} | |||||
}; | |||||
struct suspend_always { | |||||
bool await_ready() const noexcept { return false; } | |||||
void await_suspend(coroutine_handle<>) const noexcept {} | |||||
void await_resume() const noexcept {} | |||||
}; | |||||
} | |||||
template <class _Tp> | |||||
struct hash<experimental::coroutine_handle<_Tp> > { | |||||
using __arg_type = experimental::coroutine_handle<_Tp>; | |||||
size_t operator()(__arg_type const& __v) const noexcept | |||||
{ | |||||
return hash<void*>()(__v.address()); | |||||
} | |||||
}; | |||||
} | } | ||||
#endif // !defined(_LIBCPP_HAS_NO_COROUTINES) | |||||
#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ |
for (size_t i = 0; i < 10; ++i) | for (size_t i = 0; i < 10; ++i) | ||||
{ | { | ||||
#ifndef __clang__ | |||||
try | try | ||||
#endif | |||||
{ | { | ||||
auto val = co_await c.read(); | auto val = co_await c.read(); | ||||
//auto val = co_await c; //第二种从channel读出数据的方法。利用重载operator co_await(),而不是c是一个awaitable_t。 | //auto val = co_await c; //第二种从channel读出数据的方法。利用重载operator co_await(),而不是c是一个awaitable_t。 | ||||
#endif | #endif | ||||
std::cout << std::endl; | std::cout << std::endl; | ||||
} | } | ||||
#ifndef __clang__ | |||||
catch (resumef::channel_exception& e) | catch (resumef::channel_exception& e) | ||||
{ | { | ||||
//MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常 | //MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常 | ||||
std::cout << e.what() << std::endl; | std::cout << e.what() << std::endl; | ||||
} | } | ||||
#endif | |||||
co_await sleep_for(50ms); | co_await sleep_for(50ms); | ||||
} | } |
{ | { | ||||
for (size_t i = 0; i < cnt; ++i) | for (size_t i = 0; i < cnt; ++i) | ||||
{ | { | ||||
#ifndef __clang__ | |||||
try | try | ||||
#endif | |||||
{ | { | ||||
auto val = co_await c.read(); | auto val = co_await c.read(); | ||||
++gcounter; | ++gcounter; | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
#ifndef __clang__ | |||||
catch (channel_exception& e) | catch (channel_exception& e) | ||||
{ | { | ||||
//MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常 | //MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常 | ||||
scoped_lock<std::mutex> __lock(cout_mutex); | scoped_lock<std::mutex> __lock(cout_mutex); | ||||
std::cout << e.what() << std::endl; | std::cout << e.what() << std::endl; | ||||
} | } | ||||
#endif | |||||
#if OUTPUT_DEBUG | #if OUTPUT_DEBUG | ||||
co_await sleep_for(50ms); | co_await sleep_for(50ms); | ||||
write_th.join(); | write_th.join(); | ||||
std::cout << "OK: counter = " << gcounter.load() << std::endl; | std::cout << "OK: counter = " << gcounter.load() << std::endl; | ||||
(void)_getch(); | |||||
} | } |
{ | { | ||||
for (intptr_t i = 10; i >= 0; --i) | for (intptr_t i = 10; i >= 0; --i) | ||||
{ | { | ||||
#ifndef __clang__ | |||||
try | try | ||||
#endif | |||||
{ | { | ||||
auto r = co_await async_signal_exception2(i); | auto r = co_await async_signal_exception2(i); | ||||
std::cout << "result is " << r << std::endl; | std::cout << "result is " << r << std::endl; | ||||
} | } | ||||
#ifndef __clang__ | |||||
catch (const std::exception& e) | catch (const std::exception& e) | ||||
{ | { | ||||
std::cout << "exception signal : " << e.what() << std::endl; | std::cout << "exception signal : " << e.what() << std::endl; | ||||
{ | { | ||||
std::cout << "exception signal : who knows?" << std::endl; | std::cout << "exception signal : who knows?" << std::endl; | ||||
} | } | ||||
#endif | |||||
} | } | ||||
} | } | ||||
//支持librf的用法 | //支持librf的用法 | ||||
GO | GO | ||||
{ | { | ||||
#ifndef __clang__ | |||||
try | try | ||||
#endif | |||||
{ | { | ||||
int val = co_await add_async(1, 2, use_librf); | int val = co_await add_async(1, 2, use_librf); | ||||
std::cout << val << std::endl; | std::cout << val << std::endl; | ||||
std::cout << result << std::endl; | std::cout << result << std::endl; | ||||
} | } | ||||
#ifndef __clang__ | |||||
catch (const std::exception& e) | catch (const std::exception& e) | ||||
{ | { | ||||
std::cout << "exception signal : " << e.what() << std::endl; | std::cout << "exception signal : " << e.what() << std::endl; | ||||
{ | { | ||||
std::cout << "exception signal : who knows?" << std::endl; | std::cout << "exception signal : who knows?" << std::endl; | ||||
} | } | ||||
#endif | |||||
}; | }; | ||||
resumef::this_scheduler()->run_until_notask(); | resumef::this_scheduler()->run_until_notask(); |
{ | { | ||||
for (intptr_t i = 0; i < N / coro; ++i) | for (intptr_t i = 0; i < N / coro; ++i) | ||||
co_yield i; | co_yield i; | ||||
return N / coro; | |||||
co_return N / coro; | |||||
} | } | ||||
void resumable_switch(intptr_t coro, size_t idx) | void resumable_switch(intptr_t coro, size_t idx) |
{ | { | ||||
std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl; | std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl; | ||||
co_await via(sch_in_thread); | |||||
co_await *sch_in_thread; | |||||
val = co_await async_get_long(val); | val = co_await async_get_long(val); | ||||
std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl; | std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl; | ||||
using namespace resumef; | using namespace resumef; | ||||
auto test_yield_int() -> generator_t<int> | |||||
generator_t<int> test_yield_int() | |||||
{ | { | ||||
std::cout << "1 will yield return" << std::endl; | std::cout << "1 will yield return" << std::endl; | ||||
co_yield 1; | co_yield 1; |
| | ||||
#include "librf.h" | #include "librf.h" | ||||
#include <experimental/resumable> | |||||
#include <experimental/generator> | |||||
#include <optional> | #include <optional> | ||||
extern void resumable_main_yield_return(); | extern void resumable_main_yield_return(); | ||||
(void)argc; | (void)argc; | ||||
(void)argv; | (void)argv; | ||||
resumable_main_layout(); | resumable_main_layout(); | ||||
return 0; | |||||
//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(); | ||||
//resumable_main_cb(); | |||||
//resumable_main_layout(); | |||||
//resumable_main_modern_cb(); | |||||
//resumable_main_suspend_always(); | |||||
//resumable_main_yield_return(); | |||||
resumable_main_cb(); | |||||
resumable_main_layout(); | |||||
resumable_main_modern_cb(); | |||||
resumable_main_suspend_always(); | |||||
resumable_main_yield_return(); | |||||
//resumable_main_resumable(); | //resumable_main_resumable(); | ||||
//resumable_main_routine(); | |||||
//resumable_main_exception(); | |||||
//resumable_main_dynamic_go(); | |||||
resumable_main_routine(); | |||||
resumable_main_exception(); | |||||
resumable_main_dynamic_go(); | |||||
//resumable_main_multi_thread(); | //resumable_main_multi_thread(); | ||||
//resumable_main_timer(); | |||||
resumable_main_timer(); | |||||
//resumable_main_benchmark_mem(); | //resumable_main_benchmark_mem(); | ||||
//resumable_main_mutex(); | |||||
//resumable_main_event(); | |||||
//resumable_main_event_timeout(); | |||||
//resumable_main_channel(); | |||||
//resumable_main_channel_mult_thread(); | |||||
//resumable_main_sleep(); | |||||
//resumable_main_when_all(); | |||||
//resumable_main_switch_scheduler(); | |||||
resumable_main_mutex(); | |||||
resumable_main_event(); | |||||
resumable_main_event_timeout(); | |||||
resumable_main_channel(); | |||||
resumable_main_channel_mult_thread(); | |||||
resumable_main_sleep(); | |||||
resumable_main_when_all(); | |||||
resumable_main_switch_scheduler(); | |||||
//benchmark_main_channel_passing_next(); | //benchmark_main_channel_passing_next(); | ||||
std::cout << "ALL OK!" << std::endl; | |||||
return 0; | return 0; | ||||
} | } |
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | ||||
<ConfigurationType>Application</ConfigurationType> | <ConfigurationType>Application</ConfigurationType> | ||||
<UseDebugLibraries>false</UseDebugLibraries> | <UseDebugLibraries>false</UseDebugLibraries> | ||||
<PlatformToolset>v142</PlatformToolset> | |||||
<PlatformToolset>ClangCL</PlatformToolset> | |||||
<WholeProgramOptimization>true</WholeProgramOptimization> | <WholeProgramOptimization>true</WholeProgramOptimization> | ||||
<CharacterSet>NotSet</CharacterSet> | <CharacterSet>NotSet</CharacterSet> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
</Link> | </Link> | ||||
</ItemDefinitionGroup> | </ItemDefinitionGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp" /> | |||||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\benchmark\benchmark_async_mem.cpp" /> | <ClCompile Include="..\benchmark\benchmark_async_mem.cpp" /> | ||||
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" /> | <ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" /> | ||||
<ClCompile Include="..\librf\src\event.cpp" /> | <ClCompile Include="..\librf\src\event.cpp" /> | ||||
<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" /> | ||||
<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_cb.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_channel.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_dynamic_go.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_event.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_event_timeout.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_exception.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_memory_layout.cpp" /> | <ClCompile Include="..\tutorial\test_async_memory_layout.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_switch_scheduler.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_timer.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_when_all.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_modern_cb.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_multi_thread.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_mutex.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_resumable.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_routine.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_sleep.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_suspend_always.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_switch_scheduler.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_timer.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_when_all.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_yield_return.cpp" /> | <ClCompile Include="..\tutorial\test_async_yield_return.cpp" /> | ||||
<ClCompile Include="librf.cpp"> | <ClCompile Include="librf.cpp"> | ||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks> | <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks> | ||||
<ClInclude Include="..\librf\src\state.h" /> | <ClInclude Include="..\librf\src\state.h" /> | ||||
<ClInclude Include="..\librf\src\switch_scheduler.h" /> | <ClInclude Include="..\librf\src\switch_scheduler.h" /> | ||||
<ClInclude Include="..\librf\src\timer.h" /> | <ClInclude Include="..\librf\src\timer.h" /> | ||||
<ClInclude Include="..\librf\src\unix\clang_builtin.h" /> | |||||
<ClInclude Include="..\librf\src\unix\coroutine.h" /> | <ClInclude Include="..\librf\src\unix\coroutine.h" /> | ||||
<ClInclude Include="..\librf\src\utils.h" /> | <ClInclude Include="..\librf\src\utils.h" /> | ||||
<ClInclude Include="..\librf\src\when.h" /> | <ClInclude Include="..\librf\src\when.h" /> |
<ClInclude Include="..\librf\src\switch_scheduler.h"> | <ClInclude Include="..\librf\src\switch_scheduler.h"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
<ClInclude Include="..\librf\src\unix\clang_builtin.h"> | |||||
<Filter>librf\src\unix</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"> |