endif() | endif() | ||||
if(${LIBRF_COMPILER_SETTING} STREQUAL "msvc") | |||||
option(LIBRF_INLINE_STATE "Enable Inline state" ON) | |||||
elseif ("${LIBRF_COMPILER_SETTING}" STREQUAL "clang_on_msvc") | |||||
option(LIBRF_INLINE_STATE "Enable Inline state" ON) | |||||
elseif(${LIBRF_COMPILER_SETTING} STREQUAL "clang") | |||||
option(LIBRF_INLINE_STATE "Enable Inline state" ON) | |||||
elseif(${LIBRF_COMPILER_SETTING} STREQUAL "gcc") | |||||
option(LIBRF_INLINE_STATE "Enable Inline state" OFF) | |||||
else() | |||||
option(LIBRF_INLINE_STATE "Enable Inline state" OFF) | |||||
endif() | |||||
option(LIBRF_DEBUG_COUNTER "Debug objects count" OFF) | option(LIBRF_DEBUG_COUNTER "Debug objects count" OFF) | ||||
option(LIBRF_KEEP_REAL_SIZE "Keep real size in queue" OFF) | option(LIBRF_KEEP_REAL_SIZE "Keep real size in queue" OFF) | ||||
option(LIBRF_DISABLE_MULT_THREAD "Disable multi-threaded scheduler" OFF) | option(LIBRF_DISABLE_MULT_THREAD "Disable multi-threaded scheduler" OFF) | ||||
#set(RESUMEF_USE_CUSTOM_SPINLOCK "std::mutex") | #set(RESUMEF_USE_CUSTOM_SPINLOCK "std::mutex") | ||||
if(LIBRF_INLINE_STATE) | |||||
set(RESUMEF_INLINE_STATE 1) | |||||
endif() | |||||
if(LIBRF_DEBUG_COUNTER) | if(LIBRF_DEBUG_COUNTER) | ||||
set(RESUMEF_DEBUG_COUNTER 1) | set(RESUMEF_DEBUG_COUNTER 1) | ||||
endif() | endif() |
#include "librf/librf.h" | #include "librf/librf.h" | ||||
const size_t N = 5000000; | |||||
const size_t N = 10'000'000; | |||||
const size_t LOOP_COUNT = 50; | const size_t LOOP_COUNT = 50; | ||||
std::atomic<size_t> globalValue{0}; | std::atomic<size_t> globalValue{0}; |
#pragma once | #pragma once | ||||
#ifndef RESUMEF_INLINE_STATE | |||||
#if defined(__clang__) || defined(_MSC_VER) | |||||
#cmakedefine RESUMEF_INLINE_STATE @RESUMEF_INLINE_STATE@ | |||||
#else | |||||
#cmakedefine RESUMEF_INLINE_STATE 0 | |||||
#endif //defined(__clang__) || defined(_MSC_VER) | |||||
#endif //RESUMEF_INLINE_STATE | |||||
#ifndef RESUMEF_DEBUG_COUNTER | #ifndef RESUMEF_DEBUG_COUNTER | ||||
#cmakedefine RESUMEF_DEBUG_COUNTER @RESUMEF_DEBUG_COUNTER@ | #cmakedefine RESUMEF_DEBUG_COUNTER @RESUMEF_DEBUG_COUNTER@ | ||||
#endif //RESUMEF_DEBUG_COUNTER | #endif //RESUMEF_DEBUG_COUNTER |
#pragma once | #pragma once | ||||
#ifndef RESUMEF_INLINE_STATE | |||||
#if defined(__clang__) || defined(_MSC_VER) | |||||
#define RESUMEF_INLINE_STATE 1 | |||||
#else | |||||
#define RESUMEF_INLINE_STATE 0 | |||||
#endif //defined(__clang__) || defined(_MSC_VER) | |||||
#endif //RESUMEF_INLINE_STATE | |||||
#ifndef RESUMEF_DEBUG_COUNTER | #ifndef RESUMEF_DEBUG_COUNTER | ||||
/* #undef RESUMEF_DEBUG_COUNTER */ | /* #undef RESUMEF_DEBUG_COUNTER */ | ||||
#endif //RESUMEF_DEBUG_COUNTER | #endif //RESUMEF_DEBUG_COUNTER |
namespace librf | namespace librf | ||||
{ | { | ||||
/** | /** | ||||
* @brief 专用与state的智能计数指针,通过管理state内嵌的引用计数来管理state的生存期。 | |||||
* @brief 专用于state的智能计数指针,通过管理state内嵌的引用计数来管理state的生存期。 | |||||
*/ | */ | ||||
template <typename T> | template <typename T> | ||||
struct counted_ptr | struct counted_ptr |
template<class _Ty> | template<class _Ty> | ||||
constexpr size_t _Align_size() | constexpr size_t _Align_size() | ||||
{ | { | ||||
const size_t _ALIGN_REQ = sizeof(void*) * 2; | |||||
constexpr size_t _ALIGN_REQ = sizeof(void*) * 2; | |||||
return std::is_empty_v<_Ty> ? 0 : | return std::is_empty_v<_Ty> ? 0 : | ||||
(sizeof(_Ty) + _ALIGN_REQ - 1) & ~(_ALIGN_REQ - 1); | (sizeof(_Ty) + _ALIGN_REQ - 1) & ~(_ALIGN_REQ - 1); | ||||
} | } | ||||
template<class _Callable> | template<class _Callable> | ||||
auto make_stop_callback(const stop_token& token, _Callable&& cb) ->std::unique_ptr<stop_callback<_Callable>> | auto make_stop_callback(const stop_token& token, _Callable&& cb) ->std::unique_ptr<stop_callback<_Callable>> | ||||
{ | { | ||||
return std::make_unique<stop_callback<_Callable>>(token, cb); | |||||
return std::make_unique<stop_callback<_Callable>>(token, std::forward<_Callable>(cb)); | |||||
} | } | ||||
template<class _Callable> | template<class _Callable> | ||||
auto make_stop_callback(stop_token&& token, _Callable&& cb) ->std::unique_ptr<stop_callback<_Callable>> | auto make_stop_callback(stop_token&& token, _Callable&& cb) ->std::unique_ptr<stop_callback<_Callable>> | ||||
{ | { | ||||
return std::make_unique<stop_callback<_Callable>>(std::move(token), cb); | |||||
return std::make_unique<stop_callback<_Callable>>(std::move(token), std::forward<_Callable>(cb)); | |||||
} | } | ||||
} | } | ||||
none, | none, | ||||
not_ready, ///< get_value called when value not available | not_ready, ///< get_value called when value not available | ||||
already_acquired, ///< attempt to get another future | already_acquired, ///< attempt to get another future | ||||
unlock_more, ///< unlock 次数多余lock次数 | |||||
read_before_write, ///< 0容量的channel,先读后写 | |||||
unlock_more, ///< unlock 次数多于 lock 次数 | |||||
read_before_write, ///< 0容量的 channel,先读后写 | |||||
timer_canceled, ///< 定时器被意外取消 | timer_canceled, ///< 定时器被意外取消 | ||||
not_await_lock, ///< 没有在协程中使用co_await等待lock结果 | |||||
stop_requested, ///< stop_source触发了 | |||||
not_await_lock, ///< 没有在协程中使用 co_await 等待 lock 结果 | |||||
stop_requested, ///< stop_source 触发了 | |||||
max__ | max__ | ||||
}; | }; | ||||
}; | }; | ||||
/** | /** | ||||
* @brief 错误使用channel_t时产生的异常(v2版本已经不再抛此异常了)。 | |||||
* @brief 错误使用channel_t时产生的异常(v2.0版本以后已经不再抛此异常了)。 | |||||
*/ | */ | ||||
struct channel_exception : std::logic_error | struct channel_exception : std::logic_error | ||||
{ | { |
state_type* get_state() noexcept | state_type* get_state() noexcept | ||||
{ | { | ||||
#if RESUMEF_INLINE_STATE | |||||
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) | |||||
auto h = coroutine_handle<promise_type>::from_promise(*this); | |||||
char* ptr = reinterpret_cast<char*>(h.address()) - _State_size; | |||||
return reinterpret_cast<state_type*>(ptr); | |||||
#else | |||||
#error "Unknown compiler" | |||||
#endif | |||||
#else | |||||
return _state.get(); | return _state.get(); | ||||
#endif | |||||
} | } | ||||
//counted_ptr<state_type> ref_state() noexcept | //counted_ptr<state_type> ref_state() noexcept | ||||
//{ | //{ | ||||
void* operator new(size_t _Size) | void* operator new(size_t _Size) | ||||
{ | { | ||||
_Alloc_char _Al; | _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)); | |||||
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) << ", state 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 = state_type::_Construct(ptr); | |||||
st->lock(); | |||||
} | |||||
return _Rptr; | |||||
#else | |||||
char* ptr = _Al.allocate(_Size); | char* ptr = _Al.allocate(_Size); | ||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
std::cout << " generator_promise::new, alloc size=" << _Size << std::endl; | std::cout << " generator_promise::new, alloc size=" << _Size << std::endl; | ||||
#endif | #endif | ||||
return ptr; | 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>(); | |||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size)); | |||||
*reinterpret_cast<uint32_t*>(_Ptr) = static_cast<uint32_t>(_Size + _State_size); | |||||
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | |||||
st->unlock(); | |||||
#else | |||||
_Alloc_char _Al; | _Alloc_char _Al; | ||||
return _Al.deallocate(reinterpret_cast<char *>(_Ptr), _Size); | return _Al.deallocate(reinterpret_cast<char *>(_Ptr), _Size); | ||||
#endif | |||||
} | } | ||||
#if !RESUMEF_INLINE_STATE | |||||
private: | private: | ||||
counted_ptr<state_type> _state = state_generator_t::_Alloc_state(); | counted_ptr<state_type> _state = state_generator_t::_Alloc_state(); | ||||
#endif | |||||
}; | }; | ||||
#endif //DOXYGEN_SKIP_PROPERTY | #endif //DOXYGEN_SKIP_PROPERTY | ||||
using _Alloc_char = std::allocator<char>; | using _Alloc_char = std::allocator<char>; | ||||
void* operator new(size_t _Size); | void* operator new(size_t _Size); | ||||
void operator delete(void* _Ptr, size_t _Size); | void operator delete(void* _Ptr, size_t _Size); | ||||
#if !RESUMEF_INLINE_STATE | |||||
private: | private: | ||||
counted_ptr<state_type> _state = state_future_t::_Alloc_state<state_type>(false); | counted_ptr<state_type> _state = state_future_t::_Alloc_state<state_type>(false); | ||||
#endif | |||||
}; | }; | ||||
template<class _Ty> | template<class _Ty> |
template <typename _Ty> | template <typename _Ty> | ||||
auto promise_impl_t<_Ty>::get_state() noexcept -> state_type* | auto promise_impl_t<_Ty>::get_state() noexcept -> 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) | |||||
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); | |||||
//char* ptr = reinterpret_cast<char*>(this) - _State_size; | |||||
//return reinterpret_cast<state_type*>(ptr); | |||||
#else | |||||
#error "Unknown compiler" | |||||
#endif | |||||
#else | |||||
return _state.get(); | return _state.get(); | ||||
#endif | |||||
} | } | ||||
// 如果去掉了调度器,则ref_state()实现为返回counted_ptr<>,以便于处理一些意外情况 | // 如果去掉了调度器,则ref_state()实现为返回counted_ptr<>,以便于处理一些意外情况 | ||||
void* promise_impl_t<_Ty>::operator new(size_t _Size) | void* promise_impl_t<_Ty>::operator new(size_t _Size) | ||||
{ | { | ||||
_Alloc_char _Al; | _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 = state_future_t::_Construct<state_type>(ptr, _Size + _State_size); | |||||
st->lock(); | |||||
} | |||||
return _Rptr; | |||||
#else | |||||
char* ptr = _Al.allocate(_Size); | char* ptr = _Al.allocate(_Size); | ||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
std::cout << " future_promise::new, alloc size=" << (_Size) << std::endl; | std::cout << " future_promise::new, alloc size=" << (_Size) << std::endl; | ||||
std::cout << " future_promise::new, return ptr=" << (void*)ptr << std::endl; | std::cout << " future_promise::new, return ptr=" << (void*)ptr << std::endl; | ||||
#endif | #endif | ||||
return ptr; | return ptr; | ||||
#endif | |||||
} | } | ||||
template <typename _Ty> | template <typename _Ty> | ||||
void promise_impl_t<_Ty>::operator delete(void* _Ptr, size_t _Size) | 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; | _Alloc_char _Al; | ||||
return _Al.deallocate(reinterpret_cast<char*>(_Ptr), _Size); | return _Al.deallocate(reinterpret_cast<char*>(_Ptr), _Size); | ||||
#endif | |||||
} | } | ||||
} | } | ||||
_coro = handler; | _coro = handler; | ||||
} | } | ||||
#if RESUMEF_INLINE_STATE | |||||
static state_generator_t* _Construct(void* _Ptr) | |||||
{ | |||||
return new(_Ptr) state_generator_t(); | |||||
} | |||||
#endif | |||||
LIBRF_API static state_generator_t* _Alloc_state(); | LIBRF_API static state_generator_t* _Alloc_state(); | ||||
}; | }; | ||||
template<class _PromiseT> requires(traits::is_promise_v<_PromiseT>) | template<class _PromiseT> requires(traits::is_promise_v<_PromiseT>) | ||||
void promise_final_suspend(coroutine_handle<_PromiseT> handler); | void promise_final_suspend(coroutine_handle<_PromiseT> handler); | ||||
#if RESUMEF_INLINE_STATE | |||||
template<class _Sty> | |||||
static _Sty* _Construct(void* _Ptr, size_t _Size) | |||||
{ | |||||
_Sty* st = new(_Ptr) _Sty(false); | |||||
st->_alloc_size = static_cast<uint32_t>(_Size); | |||||
return st; | |||||
} | |||||
#endif | |||||
template<class _Sty> | template<class _Sty> | ||||
static inline _Sty* _Alloc_state(bool awaitor) | static inline _Sty* _Alloc_state(bool awaitor) | ||||
{ | { |
namespace librf | namespace librf | ||||
{ | { | ||||
template<typename T> | |||||
concept _ValidAwaitSuspendReturnT = std::same_as<T, void> || std::same_as<T, bool> || traits::is_coroutine_handle_v<T>; | |||||
template<typename T> | template<typename T> | ||||
concept _AwaitorT = requires(T&& v) | concept _AwaitorT = requires(T&& v) | ||||
{ | { | ||||
{ v.await_ready() } ->std::same_as<bool>; | |||||
{ v.await_suspend(std::declval<std::coroutine_handle<promise_t<>>>()) }; | |||||
{ v.await_ready() } -> std::same_as<bool>; | |||||
{ v.await_suspend(std::declval<std::coroutine_handle<promise_t<>>>()) } -> _ValidAwaitSuspendReturnT; | |||||
{ v.await_resume() }; | { v.await_resume() }; | ||||
requires traits::is_valid_await_suspend_return_v< | |||||
decltype(v.await_suspend(std::declval<std::coroutine_handle<promise_t<>>>())) | |||||
>; | |||||
}; | }; | ||||
template<typename T> | template<typename T> |
"stop_requested", | "stop_requested", | ||||
}; | }; | ||||
char sz_future_error_buffer[256]; | |||||
thread_local char sz_future_error_buffer[256]; | |||||
LIBRF_API const char * get_error_string(error_code fe, const char * classname) | LIBRF_API const char * get_error_string(error_code fe, const char * classname) | ||||
{ | { |
LIBRF_API void state_generator_t::destroy_deallocate() | LIBRF_API 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; | |||||
_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 |