diff --git a/librf/librf.h b/librf/librf.h index 787e914..fb21232 100644 --- a/librf/librf.h +++ b/librf/librf.h @@ -31,7 +31,11 @@ #include #include #include +#if defined(__clang__) && _WIN32 +#include "src/unix/coroutine.h" //编译器内建的协程函数,MSVC和clang不一样 +#else #include +#endif #include "src/def.h" #include "src/spinlock.h" @@ -40,7 +44,6 @@ #include "src/future.h" #include "src/promise.h" #include "src/awaitable.h" -#include "src/switch_scheduler.h" #include "src/rf_task.h" #include "src/utils.h" @@ -50,6 +53,7 @@ #include "src/promise.inl" #include "src/state.inl" +#include "src/switch_scheduler.h" #include "src/_awaker.h" #include "src/event.h" #include "src/mutex.h" diff --git a/librf/src/awaitable.h b/librf/src/awaitable.h index 158e162..7fab776 100644 --- a/librf/src/awaitable.h +++ b/librf/src/awaitable.h @@ -35,18 +35,7 @@ RESUMEF_NS return future_type{ this->_state }; } - mutable counted_ptr _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 = state_future_t::_Alloc_state(true); }; template diff --git a/librf/src/def.h b/librf/src/def.h index aeb34f8..93effcc 100644 --- a/librf/src/def.h +++ b/librf/src/def.h @@ -1,6 +1,6 @@ #pragma once -#define LIB_RESUMEF_VERSION 20201 // 2.2.1 +#define LIB_RESUMEF_VERSION 20300 // 2.3.0 #if defined(RESUMEF_MODULE_EXPORT) #define RESUMEF_NS export namespace resumef @@ -8,12 +8,20 @@ #define RESUMEF_NS namespace resumef #endif +//如果不清楚context frame的内存布局的情况下,该值设置为0 +#if defined(__clang__) || defined(_MSC_VER) +#define RESUMEF_INLINE_STATE 1 +#else +#define RESUMEF_INLINE_STATE 0 +#endif + RESUMEF_NS { struct scheduler_t; template struct future_t; + using future_vt [[deprecated]] = future_t<>; template > @@ -33,6 +41,8 @@ RESUMEF_NS struct state_base_t; + struct switch_scheduler_t; + template using scoped_lock = std::scoped_lock<_Mutexes...>; diff --git a/librf/src/generator.h b/librf/src/generator.h index ff22953..687d8da 100644 --- a/librf/src/generator.h +++ b/librf/src/generator.h @@ -109,9 +109,7 @@ RESUMEF_NS promise_type() { - state_type* st = get_state(); - new(st) state_type(coroutine_handle::from_promise(*this)); - st->lock(); + get_state()->set_initial_suspend(coroutine_handle::from_promise(*this)); } promise_type(promise_type&& _Right) noexcept = default; promise_type& operator = (promise_type&& _Right) noexcept = default; @@ -123,19 +121,20 @@ RESUMEF_NS 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); + return {}; } //template, _Ty>> @@ -170,9 +169,21 @@ RESUMEF_NS state_type* get_state() { +#if RESUMEF_INLINE_STATE size_t _State_size = _Align_size(); +#if defined(__clang__) + auto h = coroutine_handle::from_promise(*this); + char* ptr = reinterpret_cast(h.address()) - _State_size; + return reinterpret_cast(ptr); +#elif defined(_MSC_VER) char* ptr = reinterpret_cast(this) - _State_size; return reinterpret_cast(ptr); +#else +#error "Unknown compiler" +#endif +#else + return _state.get(); +#endif } using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc; @@ -183,27 +194,41 @@ RESUMEF_NS void* operator new(size_t _Size) { + _Alloc_char _Al; +#if RESUMEF_INLINE_STATE size_t _State_size = _Align_size(); assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits::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* _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_type* st = new(ptr) state_type(coroutine_handle::from_promise(*(promise_type *)ptr)); + state_type* st = new(ptr) state_type(); st->lock(); - *reinterpret_cast(ptr + _State_size) = static_cast(_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) { +#if RESUMEF_INLINE_STATE size_t _State_size = _Align_size(); assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits::max)() - sizeof(_State_size)); @@ -211,7 +236,15 @@ RESUMEF_NS state_type* st = reinterpret_cast(static_cast(_Ptr) - _State_size); st->unlock(); +#else + _Alloc_char _Al; + return _Al.deallocate(reinterpret_cast(_Ptr), _Size); +#endif } +#if !RESUMEF_INLINE_STATE + private: + counted_ptr _state = state_generator_t::_Alloc_state(); +#endif }; typedef generator_iterator<_Ty, promise_type> iterator; diff --git a/librf/src/promise.h b/librf/src/promise.h index 29737b1..1a796eb 100644 --- a/librf/src/promise.h +++ b/librf/src/promise.h @@ -22,13 +22,7 @@ RESUMEF_NS promise_impl_t(const promise_impl_t&) = delete; promise_impl_t& operator = (const promise_impl_t&) = delete; - state_type* get_state() - { - size_t _State_size = _Align_size(); - char* ptr = reinterpret_cast(this) - _State_size; - return reinterpret_cast(ptr); - } - + auto get_state()->state_type*; suspend_on_initial initial_suspend() noexcept; suspend_on_final final_suspend() noexcept; void set_exception(std::exception_ptr e); @@ -39,42 +33,12 @@ RESUMEF_NS void cancellation_requested(); using _Alloc_char = std::allocator; - void* operator new(size_t _Size) - { - size_t _State_size = _Align_size(); - assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits::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 = state_future_t::_Alloc_state(false); #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(); - assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits::max)() - sizeof(_State_size)); - - state_type* st = reinterpret_cast(static_cast(_Ptr) - _State_size); - st->unlock(); - } }; template @@ -86,7 +50,7 @@ RESUMEF_NS template void return_value(U&& val); //co_return val template - void yield_value(U&& val); + std::experimental::suspend_always yield_value(U&& val); }; template<> @@ -95,7 +59,7 @@ RESUMEF_NS using promise_impl_t::get_return_object; void return_void(); //co_return; - void yield_value(); + std::experimental::suspend_always yield_value(); }; } diff --git a/librf/src/promise.inl b/librf/src/promise.inl index bf3545c..08b07d0 100644 --- a/librf/src/promise.inl +++ b/librf/src/promise.inl @@ -24,6 +24,7 @@ RESUMEF_NS { } }; + struct suspend_on_final { inline bool await_ready() noexcept @@ -80,6 +81,80 @@ RESUMEF_NS } + template + auto promise_impl_t<_Ty>::get_state() -> state_type* + { +#if RESUMEF_INLINE_STATE + size_t _State_size = _Align_size(); +#if defined(__clang__) + auto h = coroutine_handle::from_promise(*reinterpret_cast(this)); + char* ptr = reinterpret_cast(h.address()) - _State_size; + return reinterpret_cast(ptr); +#elif defined(_MSC_VER) + char* ptr = reinterpret_cast(this) - _State_size; + return reinterpret_cast(ptr); +#else +#error "Unknown compiler" +#endif +#else + return _state.get(); +#endif + } + + template + void* promise_impl_t<_Ty>::operator new(size_t _Size) + { + _Alloc_char _Al; +#if RESUMEF_INLINE_STATE + size_t _State_size = _Align_size(); + assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits::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 + void promise_impl_t<_Ty>::operator delete(void* _Ptr, size_t _Size) + { +#if RESUMEF_INLINE_STATE + (void)_Size; + size_t _State_size = _Align_size(); + assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits::max)() - sizeof(_State_size)); + + state_type* st = reinterpret_cast(static_cast(_Ptr) - _State_size); + st->unlock(); +#else + _Alloc_char _Al; + return _Al.deallocate(reinterpret_cast(_Ptr), _Size); +#endif + } template template @@ -90,9 +165,10 @@ RESUMEF_NS template template - 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(val)); + return {}; } inline void promise_t::return_void() @@ -100,10 +176,10 @@ RESUMEF_NS this->get_state()->set_value(); } - inline void promise_t::yield_value() + inline std::experimental::suspend_always promise_t::yield_value() { this->get_state()->promise_yield_value(this); + return {}; } - } diff --git a/librf/src/scheduler.h b/librf/src/scheduler.h index cf37370..3b8abad 100644 --- a/librf/src/scheduler.h +++ b/librf/src/scheduler.h @@ -58,12 +58,6 @@ RESUMEF_NS std::unique_ptr del_switch(state_base_t* sptr); void add_switch(std::unique_ptr task); - switch_scheduler_t operator co_await() - { - return { this }; - } - - friend struct task_base; friend struct local_scheduler; protected: scheduler_t(); diff --git a/librf/src/state.cpp b/librf/src/state.cpp index 56792cf..656bcb4 100644 --- a/librf/src/state.cpp +++ b/librf/src/state.cpp @@ -21,8 +21,10 @@ RESUMEF_NS void state_generator_t::destroy_deallocate() { size_t _Size = _Align_size(); +#if RESUMEF_INLINE_STATE char* _Ptr = reinterpret_cast(this) + _Size; _Size = *reinterpret_cast(_Ptr); +#endif #if RESUMEF_DEBUG_COUNTER std::cout << "destroy_deallocate, size=" << _Size << std::endl; #endif @@ -34,7 +36,7 @@ RESUMEF_NS void state_generator_t::resume() { - if (_coro != nullptr) + if (_coro) { _coro.resume(); if (_coro.done()) @@ -54,12 +56,12 @@ RESUMEF_NS bool state_generator_t::is_ready() const { - return _coro != nullptr && !_coro.done(); + return (bool)_coro && !_coro.done(); } 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<>) @@ -90,7 +92,7 @@ RESUMEF_NS if (_is_initor == initor_type::Initial) { - assert(_initor != nullptr); + assert((bool)_initor); _is_initor = initor_type::None; __guard.unlock(); @@ -99,7 +101,7 @@ RESUMEF_NS return; } - if (_coro != nullptr) + if (_coro) { coroutine_handle<> handler = _coro; _coro = nullptr; @@ -111,6 +113,8 @@ RESUMEF_NS if (_is_initor == initor_type::Final) { + assert((bool)_initor); + _is_initor = initor_type::None; __guard.unlock(); @@ -122,7 +126,7 @@ RESUMEF_NS bool state_future_t::has_handler() const { scoped_lock __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 @@ -162,7 +166,7 @@ RESUMEF_NS if (_parent != nullptr) _parent->switch_scheduler_await_suspend(sch, nullptr); - if (handler != nullptr) + if (handler) { _coro = handler; sch->add_generator(this); diff --git a/librf/src/state.h b/librf/src/state.h index e38d074..61ec8ac 100644 --- a/librf/src/state.h +++ b/librf/src/state.h @@ -48,10 +48,6 @@ RESUMEF_NS struct state_generator_t : public state_base_t { - state_generator_t(coroutine_handle<> handler) - { - _coro = handler; - } private: virtual void destroy_deallocate() override; public: @@ -60,12 +56,20 @@ RESUMEF_NS virtual bool is_ready() const 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 std::cout << "state_generator_t::alloc, size=" << sizeof(state_generator_t) << std::endl; #endif - return new state_generator_t(handler); + char* _Ptr = _Al.allocate(_Size); + return new(_Ptr) state_generator_t(); } }; @@ -146,11 +150,25 @@ RESUMEF_NS void promise_initial_suspend(coroutine_handle<_PromiseT> handler); template>> void promise_final_suspend(coroutine_handle<_PromiseT> handler); + + template + 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 struct state_t final : public state_future_t { + friend state_future_t; + using state_future_t::lock_type; using value_type = _Ty; @@ -162,7 +180,7 @@ RESUMEF_NS { _alloc_size = sizeof(*this); } - + public: ~state_t() { if (_has_value) @@ -187,6 +205,7 @@ RESUMEF_NS template<> struct state_t final : public state_future_t { + friend state_future_t; using state_future_t::lock_type; explicit state_t(size_t alloc_size) :state_future_t() diff --git a/librf/src/state.inl b/librf/src/state.inl index 8beb14a..7f1e002 100644 --- a/librf/src/state.inl +++ b/librf/src/state.inl @@ -5,7 +5,7 @@ RESUMEF_NS void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler) { assert(this->_scheduler == nullptr); - assert(this->_coro == nullptr); + assert(!this->_coro); this->_initor = handler; this->_is_initor = initor_type::Initial; @@ -38,7 +38,7 @@ RESUMEF_NS this->_parent = parent_state; this->_scheduler = sch; } - if (_coro == nullptr) + if (!_coro) this->_coro = handler; if (sch != nullptr) @@ -55,7 +55,7 @@ RESUMEF_NS coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise); if (!handler.done()) { - if (this->_coro == nullptr) + if (!this->_coro) this->_coro = handler; scheduler_t* sch = this->get_scheduler(); if (sch != nullptr) diff --git a/librf/src/switch_scheduler.h b/librf/src/switch_scheduler.h index 94cf5ea..2ae500a 100644 --- a/librf/src/switch_scheduler.h +++ b/librf/src/switch_scheduler.h @@ -33,8 +33,8 @@ RESUMEF_NS 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 }; } } diff --git a/librf/src/type_traits.inl b/librf/src/type_traits.inl index 915ebb6..a63d3a8 100644 --- a/librf/src/type_traits.inl +++ b/librf/src/type_traits.inl @@ -22,4 +22,18 @@ RESUMEF_NS struct is_generator> : std::true_type {}; template constexpr bool is_generator_v = is_generator>::value; + + template + struct is_awaitable : std::false_type {}; + template + struct is_awaitable> : std::true_type {}; + template + constexpr bool is_awaitable_v = is_awaitable>::value; + + template + constexpr bool is_await_suspend_v = is_future_v<_Ty> + || is_generator_v<_Ty> + || is_awaitable_v<_Ty> + || std::is_same_v, switch_scheduler_t> + ; } diff --git a/librf/src/unix/coroutine.h b/librf/src/unix/coroutine.h index b86735a..e4d4443 100644 --- a/librf/src/unix/coroutine.h +++ b/librf/src/unix/coroutine.h @@ -1,91 +1,276 @@ -//#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 experimental { -template struct coroutine_traits { - using promise_type = typename R::promise_type; -}; +namespace experimental { +inline namespace coroutines_v1 { -template struct coroutine_handle; + // 18.11.1 coroutine traits +template +class coroutine_traits; +// 18.11.2 coroutine handle +template +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 struct hash; +template struct hash>; -template <> struct coroutine_handle { - 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; } +} // namespace coroutines_v1 +} // namespace experimental +} // namespace std -protected: - void *ptr; -}; + */ -template struct coroutine_handle : coroutine_handle<> { +#include +#include +#include +#include // for hash +#include +#include +#include "clang_builtin.h" - 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; - } +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif - Promise &promise() const { - return *reinterpret_cast( - __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; - } -}; +#ifndef _LIBCPP_HAS_NO_COROUTINES -template -bool operator==(coroutine_handle<_PromiseT> const &_Left, - coroutine_handle<_PromiseT> const &_Right) noexcept { - return _Left.address() == _Right.address(); +namespace std { + namespace experimental { + + template + struct __coroutine_traits_sfinae {}; + + template + struct __coroutine_traits_sfinae<_Tp, void_t> + { + using promise_type = typename _Tp::promise_type; + }; + + template + struct coroutine_traits : public __coroutine_traits_sfinae<_Ret> + { + }; + + template + class coroutine_handle; + + template <> + class coroutine_handle { + 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 + static coroutine_handle from_address(_Tp*) { + static_assert(_CallIsValid, + "coroutine_handle::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 + 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()(__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 + 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 + static coroutine_handle from_address(_Tp*) { + static_assert(_CallIsValid, + "coroutine_handle::from_address cannot be called with " + "non-void pointers"); + } + + template + static coroutine_handle from_address(_Promise*) { + static_assert(_CallIsValid, + "coroutine_handle::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 + : 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() noexcept; + coroutine_handle() noexcept { + this->__handle_ = __builtin_coro_noop(); + } + }; + + using noop_coroutine_handle = coroutine_handle; + + 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 + struct hash > { + using __arg_type = experimental::coroutine_handle<_Tp>; + size_t operator()(__arg_type const& __v) const noexcept + { + return hash()(__v.address()); + } + }; } -template -bool operator!=(coroutine_handle<_PromiseT> const &_Left, - coroutine_handle<_PromiseT> const &_Right) noexcept { - return !(_Left == _Right); -} +#endif // !defined(_LIBCPP_HAS_NO_COROUTINES) -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() {} -}; -} -} +#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ \ No newline at end of file diff --git a/tutorial/test_async_channel.cpp b/tutorial/test_async_channel.cpp index d021b3a..10ac8b2 100644 --- a/tutorial/test_async_channel.cpp +++ b/tutorial/test_async_channel.cpp @@ -19,7 +19,9 @@ future_t<> test_channel_read(const channel_t & c) for (size_t i = 0; i < 10; ++i) { +#ifndef __clang__ try +#endif { auto val = co_await c.read(); //auto val = co_await c; //第二种从channel读出数据的方法。利用重载operator co_await(),而不是c是一个awaitable_t。 @@ -31,11 +33,13 @@ future_t<> test_channel_read(const channel_t & c) #endif std::cout << std::endl; } +#ifndef __clang__ catch (resumef::channel_exception& e) { //MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常 std::cout << e.what() << std::endl; } +#endif co_await sleep_for(50ms); } diff --git a/tutorial/test_async_channel_mult_thread.cpp b/tutorial/test_async_channel_mult_thread.cpp index 5a9a7a8..b977adc 100644 --- a/tutorial/test_async_channel_mult_thread.cpp +++ b/tutorial/test_async_channel_mult_thread.cpp @@ -22,7 +22,9 @@ future_t<> test_channel_consumer(const channel_t & c, size_t cnt) { for (size_t i = 0; i < cnt; ++i) { +#ifndef __clang__ try +#endif { auto val = co_await c.read(); ++gcounter; @@ -33,12 +35,14 @@ future_t<> test_channel_consumer(const channel_t & c, size_t cnt) } #endif } +#ifndef __clang__ catch (channel_exception& e) { //MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常 scoped_lock __lock(cout_mutex); std::cout << e.what() << std::endl; } +#endif #if OUTPUT_DEBUG co_await sleep_for(50ms); @@ -109,5 +113,4 @@ void resumable_main_channel_mult_thread() write_th.join(); std::cout << "OK: counter = " << gcounter.load() << std::endl; - (void)_getch(); } diff --git a/tutorial/test_async_exception.cpp b/tutorial/test_async_exception.cpp index 3b0a16c..d762de1 100644 --- a/tutorial/test_async_exception.cpp +++ b/tutorial/test_async_exception.cpp @@ -53,11 +53,14 @@ future_t<> test_signal_exception() { for (intptr_t i = 10; i >= 0; --i) { +#ifndef __clang__ try +#endif { auto r = co_await async_signal_exception2(i); std::cout << "result is " << r << std::endl; } +#ifndef __clang__ catch (const std::exception& e) { std::cout << "exception signal : " << e.what() << std::endl; @@ -66,6 +69,7 @@ future_t<> test_signal_exception() { std::cout << "exception signal : who knows?" << std::endl; } +#endif } } diff --git a/tutorial/test_async_modern_cb.cpp b/tutorial/test_async_modern_cb.cpp index ace85d7..d62ab31 100644 --- a/tutorial/test_async_modern_cb.cpp +++ b/tutorial/test_async_modern_cb.cpp @@ -394,7 +394,9 @@ void resumable_main_modern_cb() //支持librf的用法 GO { +#ifndef __clang__ try +#endif { int val = co_await add_async(1, 2, use_librf); std::cout << val << std::endl; @@ -409,6 +411,7 @@ void resumable_main_modern_cb() std::cout << result << std::endl; } +#ifndef __clang__ catch (const std::exception& e) { std::cout << "exception signal : " << e.what() << std::endl; @@ -417,6 +420,7 @@ void resumable_main_modern_cb() { std::cout << "exception signal : who knows?" << std::endl; } +#endif }; resumef::this_scheduler()->run_until_notask(); diff --git a/tutorial/test_async_resumable.cpp b/tutorial/test_async_resumable.cpp index a1117be..ba8c81e 100644 --- a/tutorial/test_async_resumable.cpp +++ b/tutorial/test_async_resumable.cpp @@ -30,7 +30,7 @@ auto yield_switch(intptr_t coro) -> resumef::generator_t { for (intptr_t i = 0; i < N / coro; ++i) co_yield i; - return N / coro; + co_return N / coro; } void resumable_switch(intptr_t coro, size_t idx) diff --git a/tutorial/test_async_switch_scheduler.cpp b/tutorial/test_async_switch_scheduler.cpp index 941c93d..bc455f2 100644 --- a/tutorial/test_async_switch_scheduler.cpp +++ b/tutorial/test_async_switch_scheduler.cpp @@ -59,7 +59,7 @@ static future_t<> resumable_get_long(int64_t val, channel_t & c_done) { 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); std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl; diff --git a/tutorial/test_async_yield_return.cpp b/tutorial/test_async_yield_return.cpp index d030efd..8fe42bd 100644 --- a/tutorial/test_async_yield_return.cpp +++ b/tutorial/test_async_yield_return.cpp @@ -9,7 +9,7 @@ using namespace resumef; -auto test_yield_int() -> generator_t +generator_t test_yield_int() { std::cout << "1 will yield return" << std::endl; co_yield 1; diff --git a/vs_proj/librf.cpp b/vs_proj/librf.cpp index c7ec3bd..d65686d 100644 --- a/vs_proj/librf.cpp +++ b/vs_proj/librf.cpp @@ -1,7 +1,5 @@  #include "librf.h" -#include -#include #include extern void resumable_main_yield_return(); @@ -34,33 +32,36 @@ int main(int argc, const char* argv[]) (void)argc; (void)argv; resumable_main_layout(); + return 0; //if (argc > 1) // resumable_main_benchmark_asio_client(atoi(argv[1])); //else // 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_routine(); - //resumable_main_exception(); - //resumable_main_dynamic_go(); + resumable_main_routine(); + resumable_main_exception(); + resumable_main_dynamic_go(); //resumable_main_multi_thread(); - //resumable_main_timer(); + resumable_main_timer(); //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(); + std::cout << "ALL OK!" << std::endl; + return 0; } diff --git a/vs_proj/librf.vcxproj b/vs_proj/librf.vcxproj index 38bf785..9d8c7ca 100644 --- a/vs_proj/librf.vcxproj +++ b/vs_proj/librf.vcxproj @@ -46,7 +46,7 @@ Application false - v142 + ClangCL true NotSet @@ -170,7 +170,10 @@ - + + true + true + @@ -181,24 +184,58 @@ - - - - - - - + + true + + + true + + + true + + + true + + + true + + + true + + + true + - - - - - - - - - - + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + Default @@ -226,6 +263,7 @@ + diff --git a/vs_proj/librf.vcxproj.filters b/vs_proj/librf.vcxproj.filters index 007a0f2..999c70c 100644 --- a/vs_proj/librf.vcxproj.filters +++ b/vs_proj/librf.vcxproj.filters @@ -186,6 +186,9 @@ librf\src + + librf\src\unix +