@@ -9,6 +9,7 @@ namespace resumef | |||
using state_type = state_t<value_type>; | |||
using future_type = future_t<value_type>; | |||
using lock_type = typename state_type::lock_type; | |||
using _Alloc_char = typename state_type::_Alloc_char; | |||
awaitable_impl_t() {} | |||
awaitable_impl_t(const awaitable_impl_t&) = default; | |||
@@ -34,7 +35,18 @@ namespace resumef | |||
return future_type{ this->_state }; | |||
} | |||
mutable counted_ptr<state_type> _state = make_counted<state_type>(true); | |||
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); | |||
} | |||
}; | |||
template<class _Ty> |
@@ -14,15 +14,25 @@ namespace resumef | |||
using promise_type = promise_t<value_type>; | |||
using future_type = future_t<value_type>; | |||
counted_ptr<state_type> _state = make_counted<state_type>(false); | |||
char __xxx[16]; | |||
promise_impl_t() | |||
{ | |||
state_type* st = get_state(); | |||
new(st) state_type(); | |||
st->lock(); | |||
} | |||
promise_impl_t() {} | |||
promise_impl_t(promise_impl_t&& _Right) noexcept = default; | |||
promise_impl_t& operator = (promise_impl_t&& _Right) noexcept = default; | |||
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<state_type>(); | |||
char* ptr = reinterpret_cast<char*>(this) - _State_size; | |||
return reinterpret_cast<state_type*>(ptr); | |||
} | |||
suspend_on_initial initial_suspend() noexcept; | |||
suspend_on_final final_suspend() noexcept; | |||
void set_exception(std::exception_ptr e); | |||
@@ -35,36 +45,41 @@ namespace resumef | |||
using _Alloc_char = std::allocator<char>; | |||
void* operator new(size_t _Size) | |||
{ | |||
std::cout << "promise::new, size=" << _Size << std::endl; | |||
size_t _State_size = _Align_size<state_type>(); | |||
assert(_Size >= sizeof(uint32_t) && _Size < std::numeric_limits<uint32_t>::max() - sizeof(_State_size)); | |||
#if RESUMEF_DEBUG_COUNTER | |||
std::cout << "promise::new, size=" << (_Size + _State_size) << std::endl; | |||
#endif | |||
_Alloc_char _Al; | |||
size_t _State_size = _Align_size<state_type>(); | |||
char* ptr = _Al.allocate(_Size + _State_size); | |||
return ptr; | |||
return ptr + _State_size; | |||
} | |||
void operator delete(void* _Ptr, 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; | |||
return _Al.deallocate(static_cast<char*>(_Ptr), _Size); | |||
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | |||
st->set_alloc_size(static_cast<uint32_t>(_Size + _State_size)); | |||
st->unlock(); | |||
} | |||
}; | |||
template<class _Ty> | |||
struct promise_t : public promise_impl_t<_Ty> | |||
struct promise_t sealed : public promise_impl_t<_Ty> | |||
{ | |||
using typename promise_impl_t<_Ty>::value_type; | |||
using promise_impl_t<_Ty>::_state; | |||
void return_value(value_type val); | |||
void yield_value(value_type val); | |||
}; | |||
template<> | |||
struct promise_t<void> : public promise_impl_t<void> | |||
struct promise_t<void> sealed : public promise_impl_t<void> | |||
{ | |||
using promise_impl_t<void>::_state; | |||
void return_void(); | |||
void yield_value(); | |||
}; |
@@ -45,19 +45,19 @@ namespace resumef | |||
template <typename _Ty> | |||
inline suspend_on_initial promise_impl_t<_Ty>::initial_suspend() noexcept | |||
{ | |||
return { _state.get() }; | |||
return { get_state() }; | |||
} | |||
template <typename _Ty> | |||
inline suspend_on_final promise_impl_t<_Ty>::final_suspend() noexcept | |||
{ | |||
return { _state.get() }; | |||
return { get_state() }; | |||
} | |||
template <typename _Ty> | |||
inline void promise_impl_t<_Ty>::set_exception(std::exception_ptr e) | |||
{ | |||
_state->set_exception(std::move(e)); | |||
get_state()->set_exception(std::move(e)); | |||
} | |||
#ifdef __clang__ | |||
@@ -71,7 +71,7 @@ namespace resumef | |||
template <typename _Ty> | |||
inline future_t<_Ty> promise_impl_t<_Ty>::get_return_object() | |||
{ | |||
return { _state }; | |||
return { get_state() }; | |||
} | |||
template <typename _Ty> | |||
@@ -84,23 +84,23 @@ namespace resumef | |||
template<class _Ty> | |||
inline void promise_t<_Ty>::return_value(value_type val) | |||
{ | |||
_state->set_value(std::move(val)); | |||
get_state()->set_value(std::move(val)); | |||
} | |||
template<class _Ty> | |||
inline void promise_t<_Ty>::yield_value(value_type val) | |||
{ | |||
_state->promise_yield_value(this, std::move(val)); | |||
get_state()->promise_yield_value(this, std::move(val)); | |||
} | |||
inline void promise_t<void>::return_void() | |||
{ | |||
_state->set_value(); | |||
get_state()->set_value(); | |||
} | |||
inline void promise_t<void>::yield_value() | |||
{ | |||
_state->promise_yield_value(this); | |||
get_state()->promise_yield_value(this); | |||
} | |||
} |
@@ -19,7 +19,7 @@ namespace resumef | |||
using state_vector = std::vector<state_sptr>; | |||
private: | |||
using lock_type = std::recursive_mutex; | |||
using task_dictionary_type = std::unordered_map<state_base_t*, task_base_t*>; | |||
using task_dictionary_type = std::unordered_map<state_base_t*, std::unique_ptr<task_base_t>>; | |||
mutable lock_type _lock_running; | |||
state_vector _runing_states; |
@@ -9,6 +9,23 @@ namespace resumef | |||
{ | |||
} | |||
void state_future_t::destroy_deallocate() | |||
{ | |||
size_t _Size = this->_Alloc_size; | |||
#if RESUMEF_DEBUG_COUNTER | |||
std::cout << "destroy_deallocate, size=" << _Size << std::endl; | |||
#endif | |||
this->~state_future_t(); | |||
_Alloc_char _Al; | |||
return _Al.deallocate(reinterpret_cast<char*>(this), _Size); | |||
} | |||
void state_generator_t::destroy_deallocate() | |||
{ | |||
delete this; | |||
} | |||
void state_generator_t::resume() | |||
{ | |||
if (_coro != nullptr) | |||
@@ -38,19 +55,36 @@ namespace resumef | |||
void state_future_t::resume() | |||
{ | |||
scoped_lock<lock_type> __guard(_mtx); | |||
std::unique_lock<lock_type> __guard(_mtx); | |||
if (_initor != nullptr) | |||
if (_initor != nullptr && _is_initor) | |||
{ | |||
coroutine_handle<> handler = _initor; | |||
_initor = nullptr; | |||
__guard.unlock(); | |||
handler.resume(); | |||
return; | |||
} | |||
else if (_coro != nullptr) | |||
if (_coro != nullptr) | |||
{ | |||
coroutine_handle<> handler = _coro; | |||
_coro = nullptr; | |||
__guard.unlock(); | |||
handler.resume(); | |||
return; | |||
} | |||
if (_initor != nullptr && !_is_initor) | |||
{ | |||
coroutine_handle<> handler = _initor; | |||
_initor = nullptr; | |||
__guard.unlock(); | |||
handler.destroy(); | |||
return; | |||
} | |||
} | |||
@@ -10,9 +10,11 @@ namespace resumef | |||
{ | |||
struct state_base_t | |||
{ | |||
using _Alloc_char = std::allocator<char>; | |||
RF_API virtual ~state_base_t(); | |||
private: | |||
std::atomic<intptr_t> _count{ 0 }; | |||
std::atomic<intptr_t> _count{0}; | |||
public: | |||
void lock() | |||
{ | |||
@@ -21,7 +23,9 @@ namespace resumef | |||
void unlock() | |||
{ | |||
if (--_count == 0) | |||
delete this; | |||
{ | |||
destroy_deallocate(); | |||
} | |||
} | |||
protected: | |||
scheduler_t* _scheduler = nullptr; | |||
@@ -30,6 +34,8 @@ namespace resumef | |||
// 一、经过co_await操作后,_coro在初始时不会为nullptr。 | |||
// 二、没有co_await操作,直接加入到了调度器里,则_coro在初始时为nullptr。调度器需要特殊处理此种情况。 | |||
coroutine_handle<> _coro; | |||
private: | |||
virtual void destroy_deallocate() = 0; | |||
public: | |||
virtual void resume() = 0; | |||
virtual bool has_handler() const = 0; | |||
@@ -53,6 +59,7 @@ namespace resumef | |||
_coro = handler; | |||
} | |||
virtual void destroy_deallocate() override; | |||
virtual void resume() override; | |||
virtual bool has_handler() const override; | |||
virtual bool is_ready() const override; | |||
@@ -69,8 +76,10 @@ namespace resumef | |||
intptr_t _id; | |||
#endif | |||
std::exception_ptr _exception; | |||
uint32_t _Alloc_size; | |||
bool _has_value = false; | |||
bool _is_awaitor; | |||
bool _is_initor = false; | |||
public: | |||
state_future_t() | |||
{ | |||
@@ -79,7 +88,7 @@ namespace resumef | |||
#endif | |||
_is_awaitor = false; | |||
} | |||
state_future_t(bool awaitor) | |||
explicit state_future_t(bool awaitor) | |||
{ | |||
#if RESUMEF_DEBUG_COUNTER | |||
_id = ++g_resumef_state_id; | |||
@@ -87,6 +96,7 @@ namespace resumef | |||
_is_awaitor = awaitor; | |||
} | |||
virtual void destroy_deallocate() override; | |||
virtual void resume() override; | |||
virtual bool has_handler() const override; | |||
virtual bool is_ready() const override; | |||
@@ -100,6 +110,10 @@ namespace resumef | |||
{ | |||
return _parent; | |||
} | |||
void set_alloc_size(uint32_t val) | |||
{ | |||
_Alloc_size = val; | |||
} | |||
void set_exception(std::exception_ptr e); | |||
@@ -125,11 +139,19 @@ namespace resumef | |||
}; | |||
template <typename _Ty> | |||
struct state_t : public state_future_t | |||
struct state_t sealed : public state_future_t | |||
{ | |||
using state_future_t::state_future_t; | |||
using state_future_t::lock_type; | |||
using value_type = _Ty; | |||
state_t() :state_future_t() | |||
{ | |||
_Alloc_size = sizeof(*this); | |||
} | |||
explicit state_t(bool awaitor) :state_future_t(awaitor) | |||
{ | |||
_Alloc_size = sizeof(*this); | |||
} | |||
private: | |||
union union_value_type | |||
{ | |||
@@ -154,10 +176,18 @@ namespace resumef | |||
}; | |||
template<> | |||
struct state_t<void> : public state_future_t | |||
struct state_t<void> sealed : public state_future_t | |||
{ | |||
using state_future_t::state_future_t; | |||
using state_future_t::lock_type; | |||
state_t() :state_future_t() | |||
{ | |||
_Alloc_size = sizeof(*this); | |||
} | |||
explicit state_t(bool awaitor) :state_future_t(awaitor) | |||
{ | |||
_Alloc_size = sizeof(*this); | |||
} | |||
public: | |||
void future_await_resume(); | |||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> |
@@ -7,12 +7,13 @@ namespace resumef | |||
{ | |||
_PromiseT& promise = handler.promise(); | |||
state_base_t* parent_state = promise._state.get(); | |||
state_base_t* parent_state = promise.get_state(); | |||
(void)parent_state; | |||
assert(this == parent_state); | |||
assert(this->_scheduler == nullptr); | |||
assert(this->_coro == nullptr); | |||
this->_initor = handler; | |||
this->_is_initor = true; | |||
} | |||
inline void state_future_t::promise_await_resume() | |||
@@ -26,9 +27,11 @@ namespace resumef | |||
_PromiseT& promise = handler.promise(); | |||
state_base_t* parent_state = promise._state.get(); | |||
state_base_t* parent_state = promise.get_state(); | |||
(void)parent_state; | |||
assert(this == parent_state); | |||
this->_initor = handler; | |||
this->_is_initor = false; | |||
scheduler_t* sch = this->get_scheduler(); | |||
assert(sch != nullptr); | |||
@@ -42,7 +45,7 @@ namespace resumef | |||
_PromiseT& promise = handler.promise(); | |||
auto* parent_state = promise._state.get(); | |||
auto* parent_state = promise.get_state(); | |||
scheduler_t* sch = parent_state->get_scheduler(); | |||
if (this != parent_state) | |||
{ |
@@ -23,18 +23,6 @@ void callback_get_long(int64_t val, _Ctype&& cb) | |||
//这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里 | |||
future_t<int64_t> async_get_long(int64_t val) | |||
{ | |||
/* | |||
void* frame_ptr = _coro_frame_ptr(); | |||
size_t frame_size = _coro_frame_size(); | |||
std::cout << "test_routine_use_timer" << std::endl; | |||
std::cout << "frame point=" << frame_ptr << ", size=" << frame_size << ", promise_size=" << _Align_size<promise_t<>>() << std::endl; | |||
auto handler = coroutine_handle<promise_t<>>::from_address(frame_ptr); | |||
auto st = handler.promise()._state; | |||
scheduler_t* sch = st->get_scheduler(); | |||
auto parent = st->get_parent(); | |||
std::cout << "st=" << st.get() << ", scheduler=" << sch << ", parent=" << parent << std::endl; | |||
*/ | |||
resumef::awaitable_t<int64_t> awaitable; | |||
callback_get_long(val, [awaitable](int64_t val) | |||
{ | |||
@@ -81,6 +69,6 @@ void resumable_main_cb() | |||
std::cout << "GO:" << val << std::endl; | |||
}; | |||
go resumable_get_long(3); | |||
go loop_get_long(3); | |||
resumef::this_scheduler()->run_until_notask(); | |||
} |
@@ -19,10 +19,10 @@ future_t<> test_routine_use_timer() | |||
std::cout << "frame point=" << frame_ptr << ", size=" << frame_size << ", promise_size=" << _Align_size<promise_t<>>() << std::endl; | |||
auto handler = coroutine_handle<promise_t<>>::from_address(frame_ptr); | |||
auto st = handler.promise()._state; | |||
auto st = handler.promise().get_state(); | |||
scheduler_t* sch = st->get_scheduler(); | |||
auto parent = st->get_parent(); | |||
std::cout << "st=" << st.get() << ", scheduler=" << sch << ", parent=" << parent << std::endl; | |||
std::cout << "st=" << st << ", scheduler=" << sch << ", parent=" << parent << std::endl; | |||
for (size_t i = 0; i < 3; ++i) | |||
{ |
@@ -31,14 +31,14 @@ int main(int argc, const char* argv[]) | |||
{ | |||
(void)argc; | |||
(void)argv; | |||
//resumable_main_routine(); | |||
resumable_main_routine(); | |||
//if (argc > 1) | |||
// resumable_main_benchmark_asio_client(atoi(argv[1])); | |||
//else | |||
// resumable_main_benchmark_asio_server(); | |||
resumable_main_cb(); | |||
//resumable_main_cb(); | |||
//resumable_main_modern_cb(); | |||
//resumable_main_suspend_always(); | |||
//resumable_main_yield_return(); |
@@ -104,7 +104,7 @@ | |||
<ClCompile> | |||
<WarningLevel>Level3</WarningLevel> | |||
<Optimization>Disabled</Optimization> | |||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;ASIO_STANDALONE;RESUMEF_DEBUG_COUNTER=0;RESUMEF_ENABLE_MULT_SCHEDULER=1;RESUMEF_USE_BOOST_ANY=0;_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING=1;ASIO_DISABLE_CONCEPTS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;ASIO_STANDALONE;RESUMEF_DEBUG_COUNTER=1;RESUMEF_ENABLE_MULT_SCHEDULER=1;RESUMEF_USE_BOOST_ANY=0;_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING=1;ASIO_DISABLE_CONCEPTS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||
<SDLCheck>true</SDLCheck> | |||
<AdditionalIncludeDirectories>..\librf;..\..\asio\asio\include;..\..\asio-1.10.6\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | |||
<AdditionalOptions>/await</AdditionalOptions> |