/vs_proj/Release | /vs_proj/Release | ||||
/vs_proj/Debug | /vs_proj/Debug | ||||
private | private | ||||
bin | |||||
out | |||||
/CMakeSettings.json |
cmake_minimum_required(VERSION 3.10) | |||||
cmake_minimum_required(VERSION 3.10) | |||||
project(librf VERSION 3.0) | project(librf VERSION 3.0) | ||||
set(CMAKE_CXX_STANDARD 20) | set(CMAKE_CXX_STANDARD 20) | ||||
set(CMAKE_CXX_STANDARD_REQUIRED True) | |||||
set(CMAKE_CXX_STANDARD_REQUIRED true) | |||||
set(LIBRF_COMPILER_SETTING ) | set(LIBRF_COMPILER_SETTING ) | ||||
if(WIN32) | if(WIN32) | ||||
endif() | endif() | ||||
configure_file( | configure_file( | ||||
${PROJECT_SOURCE_DIR}/config.h.in | |||||
${PROJECT_SOURCE_DIR}/librf/src/config.h | |||||
${CMAKE_SOURCE_DIR}/config.h.in | |||||
${CMAKE_SOURCE_DIR}/include/librf/src/config.h | |||||
) | ) | ||||
include_directories( | |||||
${PROJECT_SOURCE_DIR}/librf | |||||
) | |||||
set(SRC | |||||
${PROJECT_SOURCE_DIR}/librf/src/event_v2.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/mutex_v2.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/rf_task.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/scheduler.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/sleep.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/state.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/timer.cpp | |||||
${PROJECT_SOURCE_DIR}/librf/src/when_v2.cpp | |||||
) | |||||
file(GLOB_RECURSE HEADER_FILES ${CMAKE_SOURCE_DIR}/include/*.*) | |||||
file(GLOB_RECURSE SOURCE_FILES ${CMAKE_SOURCE_DIR}/source/*.*) | |||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib) | |||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) | |||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib) | |||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) | |||||
if(OPT_DYNAMIC_LIBRARY) | if(OPT_DYNAMIC_LIBRARY) | ||||
add_library(librf SHARED ${SRC}) | |||||
add_library(${PROJECT_NAME} SHARED | |||||
${HEADER_FILES} | |||||
${SOURCE_FILES} | |||||
) | |||||
else() | else() | ||||
add_library(librf STATIC ${SRC}) | |||||
add_library(${PROJECT_NAME} STATIC | |||||
${HEADER_FILES} | |||||
${SOURCE_FILES} | |||||
) | |||||
endif() | endif() | ||||
include_directories( | |||||
${PROJECT_SOURCE_DIR}/modern_cb | |||||
target_include_directories(${PROJECT_NAME} | |||||
PUBLIC | |||||
${CMAKE_CURRENT_SOURCE_DIR}/include | |||||
) | ) | ||||
#aux_source_directory(${PROJECT_SOURCE_DIR}/tutorial TSRC) | |||||
#set(TSRC ${TSRC} | |||||
#${PROJECT_SOURCE_DIR}/benchmark/benchmark_async_mem.cpp | |||||
#${PROJECT_SOURCE_DIR}/benchmark/benchmark_channel_passing_next.cpp | |||||
#${PROJECT_SOURCE_DIR}/test_librf.cpp | |||||
#) | |||||
include_directories( | |||||
${CMAKE_SOURCE_DIR}/modern_cb | |||||
) | |||||
if(OPT_USE_MIMALLOC) | if(OPT_USE_MIMALLOC) | ||||
set(LIB_MIMALLOC, "mimalloc") | set(LIB_MIMALLOC, "mimalloc") | ||||
endif() | endif() | ||||
add_subdirectory(tutorial) | add_subdirectory(tutorial) | ||||
#add_subdirectory(benchmark) |
{ | { | ||||
public: | public: | ||||
using result_type_t = T; | using result_type_t = T; | ||||
using state_type = resumef::state_t<result_type_t>; | |||||
using state_type = librf::state_t<result_type_t>; | |||||
template<typename Allocator> | template<typename Allocator> | ||||
promise_handler(const rf_task_t<Allocator> &) | promise_handler(const rf_task_t<Allocator> &) | ||||
} | } | ||||
} | } | ||||
resumef::counted_ptr<state_type> state_; | |||||
librf::counted_ptr<state_type> state_; | |||||
}; | }; | ||||
template<> | template<> | ||||
{ | { | ||||
public: | public: | ||||
using result_type_t = void; | using result_type_t = void; | ||||
using state_type = resumef::state_t<result_type_t>; | |||||
using state_type = librf::state_t<result_type_t>; | |||||
template<typename Allocator> | template<typename Allocator> | ||||
promise_handler(const rf_task_t<Allocator> &) | promise_handler(const rf_task_t<Allocator> &) | ||||
} | } | ||||
} | } | ||||
resumef::counted_ptr<state_type> state_; | |||||
librf::counted_ptr<state_type> state_; | |||||
}; | }; | ||||
} // namespace detail | } // namespace detail | ||||
class async_result<detail::promise_handler<T> > | class async_result<detail::promise_handler<T> > | ||||
{ | { | ||||
public: | public: | ||||
typedef resumef::future_t<T> type; | |||||
typedef librf::future_t<T> type; | |||||
explicit async_result(detail::promise_handler<T> & h) | explicit async_result(detail::promise_handler<T> & h) | ||||
: task_(std::move(h.state_)) | : task_(std::move(h.state_)) | ||||
{ } | { } | ||||
resumef::future_t<T> get() { return std::move(task_); } | |||||
librf::future_t<T> get() { return std::move(task_); } | |||||
private: | private: | ||||
resumef::future_t<T> task_; | |||||
librf::future_t<T> task_; | |||||
}; | }; | ||||
// Handler type specialisation for zero arg. | // Handler type specialisation for zero arg. |
namespace asio { | namespace asio { | ||||
/** | /** | ||||
* @brief 用于指示asio相关异步函数,返回resumef::future_t<>的类型,从而变成支持 librf 的协程函数。 | |||||
* @brief 用于指示asio相关异步函数,返回librf::future_t<>的类型,从而变成支持 librf 的协程函数。 | |||||
*/ | */ | ||||
template <typename Executor = executor> | template <typename Executor = executor> | ||||
struct rf_task_t | struct rf_task_t | ||||
}; | }; | ||||
/** | /** | ||||
* @brief 用于指示asio相关异步函数,返回resumef::future_t<>的常量,从而变成支持 librf 的协程函数。 | |||||
* @brief 用于指示asio相关异步函数,返回librf::future_t<>的常量,从而变成支持 librf 的协程函数。 | |||||
*/ | */ | ||||
constexpr rf_task_t<> rf_task; | constexpr rf_task_t<> rf_task; | ||||
{ | { | ||||
public: | public: | ||||
typedef T result_type; | typedef T result_type; | ||||
typedef resumef::state_t<result_type> state_type; | |||||
typedef librf::state_t<result_type> state_type; | |||||
promise_handler_base() | promise_handler_base() | ||||
: state_(resumef::state_future_t::_Alloc_state<state_type>(true)) | |||||
: state_(librf::state_future_t::_Alloc_state<state_type>(true)) | |||||
{ | { | ||||
} | } | ||||
resumef::counted_ptr<state_type> state_; | |||||
librf::counted_ptr<state_type> state_; | |||||
promise_handler_base(promise_handler_base &&) = default; | promise_handler_base(promise_handler_base &&) = default; | ||||
promise_handler_base(const promise_handler_base &) = default; | promise_handler_base(const promise_handler_base &) = default; | ||||
promise_handler_base & operator = (promise_handler_base &&) = default; | promise_handler_base & operator = (promise_handler_base &&) = default; | ||||
public: | public: | ||||
typedef librf::promise_handler<Executor, Args...> handler_type; | typedef librf::promise_handler<Executor, Args...> handler_type; | ||||
typedef typename handler_type::result_type result_type; | typedef typename handler_type::result_type result_type; | ||||
typedef resumef::future_t<result_type> return_type; | |||||
typedef librf::future_t<result_type> return_type; | |||||
template <typename Initiation, typename... InitArgs> | template <typename Initiation, typename... InitArgs> | ||||
static return_type initiate(ASIO_MOVE_ARG(Initiation) initiation, | static return_type initiate(ASIO_MOVE_ARG(Initiation) initiation, |
namespace asio { | namespace asio { | ||||
/** | /** | ||||
* @brief 用于指示asio相关异步函数,返回resumef::future_t<>的类型,从而变成支持 librf 的协程函数。 | |||||
* @brief 用于指示asio相关异步函数,返回librf::future_t<>的类型,从而变成支持 librf 的协程函数。 | |||||
*/ | */ | ||||
template <typename Executor = executor> | template <typename Executor = executor> | ||||
struct rf_task_t | struct rf_task_t | ||||
}; | }; | ||||
/** | /** | ||||
* @brief 用于指示asio相关异步函数,返回resumef::future_t<>的常量,从而变成支持 librf 的协程函数。 | |||||
* @brief 用于指示asio相关异步函数,返回librf::future_t<>的常量,从而变成支持 librf 的协程函数。 | |||||
*/ | */ | ||||
constexpr rf_task_t<> rf_task; | constexpr rf_task_t<> rf_task; | ||||
{ | { | ||||
public: | public: | ||||
typedef _Result result_type; | typedef _Result result_type; | ||||
typedef ::resumef::state_t<result_type> state_type; | |||||
typedef ::librf::state_t<result_type> state_type; | |||||
promise_handler_base(const rf_task_t<Executor>&) | promise_handler_base(const rf_task_t<Executor>&) | ||||
: state_(::resumef::state_future_t::_Alloc_state<state_type>(true)) | |||||
: state_(::librf::state_future_t::_Alloc_state<state_type>(true)) | |||||
{ | { | ||||
} | } | ||||
::resumef::counted_ptr<state_type> state_; | |||||
::librf::counted_ptr<state_type> state_; | |||||
promise_handler_base(promise_handler_base &&) = default; | promise_handler_base(promise_handler_base &&) = default; | ||||
promise_handler_base(const promise_handler_base &) = default; | promise_handler_base(const promise_handler_base &) = default; | ||||
promise_handler_base & operator = (promise_handler_base &&) = default; | promise_handler_base & operator = (promise_handler_base &&) = default; | ||||
typedef librf::promise_handler<Executor, Args...> completion_handler_type; | typedef librf::promise_handler<Executor, Args...> completion_handler_type; | ||||
typedef typename completion_handler_type::result_type result_type; | typedef typename completion_handler_type::result_type result_type; | ||||
typedef ::resumef::state_t<result_type> state_type; | |||||
typedef ::resumef::future_t<result_type> return_type; | |||||
typedef ::librf::state_t<result_type> state_type; | |||||
typedef ::librf::future_t<result_type> return_type; | |||||
async_result(completion_handler_type& hander) | async_result(completion_handler_type& hander) | ||||
: state_(hander.state_) | : state_(hander.state_) | ||||
return this->state_; | return this->state_; | ||||
} | } | ||||
private: | private: | ||||
::resumef::counted_ptr<state_type> state_; | |||||
::librf::counted_ptr<state_type> state_; | |||||
}; | }; | ||||
} // namespace asio | } // namespace asio |
set(BENCHMARK_FILES "") | |||||
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} BENCHMARK_FILES) | |||||
foreach(BENCHMARK_FILE_PATH ${BENCHMARK_FILES}) | |||||
string(REGEX REPLACE ".+[/\]([^/\.]+)\\.cpp" "\\1" BENCHMARK_FILE_NAME ${BENCHMARK_FILE_PATH}) | |||||
message(STATUS "Generating benchmark target: ${BENCHMARK_FILE_NAME}") | |||||
add_executable(${BENCHMARK_FILE_NAME} ${BENCHMARK_FILE_PATH}) | |||||
target_link_libraries(${BENCHMARK_FILE_NAME} PUBLIC librf) | |||||
endforeach(BENCHMARK_FILE_PATH) |
| |||||
#include <iostream> | #include <iostream> | ||||
#include "librf.h" | #include "librf.h" | ||||
using namespace asio; | using namespace asio; | ||||
using namespace asio::ip; | using namespace asio::ip; | ||||
using namespace resumef; | |||||
using namespace librf; | |||||
template<class _Ty, size_t _Size> | template<class _Ty, size_t _Size> | ||||
union uarray | union uarray | ||||
void RunOneBenchmark(bool bMain) | void RunOneBenchmark(bool bMain) | ||||
{ | { | ||||
resumef::local_scheduler_t ls; | |||||
librf::local_scheduler_t ls; | |||||
asio::io_service io_service; | asio::io_service io_service; | ||||
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 3456)); | tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 3456)); |
| |||||
#include <chrono> | #include <chrono> | ||||
#include <iostream> | #include <iostream> | ||||
#include <string> | #include <string> | ||||
for (size_t i = 0; i < N; ++i) | for (size_t i = 0; i < N; ++i) | ||||
{ | { | ||||
go[=]()->resumef::generator_t<size_t> | |||||
go[=]()->librf::generator_t<size_t> | |||||
{ | { | ||||
for (size_t k = 0; k < LOOP_COUNT; ++k) | for (size_t k = 0; k < LOOP_COUNT; ++k) | ||||
{ | { | ||||
}; | }; | ||||
} | } | ||||
resumef::this_scheduler()->run_until_notask(); | |||||
librf::this_scheduler()->run_until_notask(); | |||||
if (wait_key) | if (wait_key) | ||||
{ | { | ||||
std::cout << "press any key to continue." << std::endl; | std::cout << "press any key to continue." << std::endl; | ||||
//clang : 平均 210字节 | //clang : 平均 210字节 | ||||
//msvc : 平均600字节 | //msvc : 平均600字节 | ||||
int main() | |||||
{ | |||||
resumable_main_benchmark_mem(false); | |||||
return 0; | |||||
} |
#include "librf.h" | #include "librf.h" | ||||
using namespace resumef; | |||||
using namespace librf; | |||||
using namespace std::chrono; | using namespace std::chrono; | ||||
using namespace std::literals; | using namespace std::literals; | ||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); | ||||
} | } | ||||
int main() | |||||
{ | |||||
benchmark_main_channel_passing_next(); | |||||
return 0; | |||||
} |
#include "librf.h" | #include "librf.h" | ||||
#include "use_librf.h" | #include "use_librf.h" | ||||
using namespace resumef; | |||||
using namespace librf; | |||||
using namespace cinatra; | using namespace cinatra; | ||||
void test_async_cinatra_client() | void test_async_cinatra_client() | ||||
}; | }; | ||||
#endif | #endif | ||||
resumef::this_scheduler()->run_until_notask(); | |||||
librf::this_scheduler()->run_until_notask(); | |||||
} | } |
*/ | */ | ||||
#include <iostream> | #include <iostream> | ||||
#include "librf.h" | #include "librf.h" | ||||
using namespace resumef; | |||||
using namespace librf; | |||||
#define GCC_FIX_BUGS 1 | #define GCC_FIX_BUGS 1 | ||||
/* | |||||
*Copyright 2017~2020 lanzhengpeng | |||||
* | |||||
*Licensed under the Apache License, Version 2.0 (the "License"); | |||||
*you may not use this file except in compliance with the License. | |||||
*You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
*Unless required by applicable law or agreed to in writing, software | |||||
*distributed under the License is distributed on an "AS IS" BASIS, | |||||
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
*See the License for the specific language governing permissions and | |||||
*limitations under the License. | |||||
*/ | |||||
#pragma once | |||||
#include <cstdint> | |||||
#include <cstddef> | |||||
#include <type_traits> | |||||
#include <atomic> | |||||
#include <chrono> | |||||
#include <array> | |||||
#include <vector> | |||||
#include <deque> | |||||
#include <mutex> | |||||
#include <map> | |||||
#include <list> | |||||
#include <any> | |||||
#include <unordered_map> | |||||
#include <functional> | |||||
#include <optional> | |||||
#include <thread> | |||||
#include <cassert> | |||||
#ifdef __cpp_impl_coroutine | |||||
#include <coroutine> | |||||
#ifdef _MSC_VER | |||||
extern "C" size_t _coro_frame_size(); | |||||
extern "C" void* _coro_frame_ptr(); | |||||
extern "C" void _coro_init_block(); | |||||
extern "C" void* _coro_resume_addr(); | |||||
extern "C" void _coro_init_frame(void*); | |||||
extern "C" void _coro_save(size_t); | |||||
extern "C" void _coro_suspend(size_t); | |||||
extern "C" void _coro_cancel(); | |||||
extern "C" void _coro_resume_block(); | |||||
#pragma intrinsic(_coro_frame_size) | |||||
#pragma intrinsic(_coro_frame_ptr) | |||||
#pragma intrinsic(_coro_init_block) | |||||
#pragma intrinsic(_coro_resume_addr) | |||||
#pragma intrinsic(_coro_init_frame) | |||||
#pragma intrinsic(_coro_save) | |||||
#pragma intrinsic(_coro_suspend) | |||||
#pragma intrinsic(_coro_cancel) | |||||
#pragma intrinsic(_coro_resume_block) | |||||
#endif | |||||
#else | |||||
#include <experimental/coroutine> | |||||
#endif | |||||
#include "src/stop_token.hpp" | |||||
#include "src/config.h" | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
#include <iostream> | |||||
#endif | |||||
#include "src/def.h" | |||||
#include "src/macro_def.inl" | |||||
#include "src/counted_ptr.h" | |||||
#include "src/type_traits.inl" | |||||
#include "src/type_concept.inl" | |||||
#include "src/spinlock.h" | |||||
#include "src/state.h" | |||||
#include "src/future.h" | |||||
#include "src/promise.h" | |||||
#include "src/awaitable.h" | |||||
#include "src/generator.h" | |||||
#include "src/rf_task.h" | |||||
#include "src/timer.h" | |||||
#include "src/scheduler.h" | |||||
#include "src/promise.inl" | |||||
#include "src/state.inl" | |||||
#include "src/switch_scheduler.h" | |||||
#include "src/current_scheduler.h" | |||||
#include "src/yield.h" | |||||
#include "src/sleep.h" | |||||
#include "src/when.h" | |||||
#include "src/_awaker.h" | |||||
#include "src/ring_queue.h" | |||||
#include "src/intrusive_link_queue.h" | |||||
#include "src/channel.h" | |||||
#include "src/event.h" | |||||
#include "src/mutex.h" | |||||
/* | |||||
*Copyright 2017~2020 lanzhengpeng | |||||
* | |||||
*Licensed under the Apache License, Version 2.0 (the "License"); | |||||
*you may not use this file except in compliance with the License. | |||||
*You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
*Unless required by applicable law or agreed to in writing, software | |||||
*distributed under the License is distributed on an "AS IS" BASIS, | |||||
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
*See the License for the specific language governing permissions and | |||||
*limitations under the License. | |||||
*/ | |||||
#pragma once | |||||
#include <cstdint> | |||||
#include <cstddef> | |||||
#include <type_traits> | |||||
#include <atomic> | |||||
#include <chrono> | |||||
#include <array> | |||||
#include <vector> | |||||
#include <deque> | |||||
#include <mutex> | |||||
#include <map> | |||||
#include <list> | |||||
#include <any> | |||||
#include <unordered_map> | |||||
#include <functional> | |||||
#include <optional> | |||||
#include <thread> | |||||
#include <cassert> | |||||
#ifdef __cpp_impl_coroutine | |||||
#include <coroutine> | |||||
#ifdef _MSC_VER | |||||
extern "C" size_t _coro_frame_size(); | |||||
extern "C" void* _coro_frame_ptr(); | |||||
extern "C" void _coro_init_block(); | |||||
extern "C" void* _coro_resume_addr(); | |||||
extern "C" void _coro_init_frame(void*); | |||||
extern "C" void _coro_save(size_t); | |||||
extern "C" void _coro_suspend(size_t); | |||||
extern "C" void _coro_cancel(); | |||||
extern "C" void _coro_resume_block(); | |||||
#pragma intrinsic(_coro_frame_size) | |||||
#pragma intrinsic(_coro_frame_ptr) | |||||
#pragma intrinsic(_coro_init_block) | |||||
#pragma intrinsic(_coro_resume_addr) | |||||
#pragma intrinsic(_coro_init_frame) | |||||
#pragma intrinsic(_coro_save) | |||||
#pragma intrinsic(_coro_suspend) | |||||
#pragma intrinsic(_coro_cancel) | |||||
#pragma intrinsic(_coro_resume_block) | |||||
#endif | |||||
#else | |||||
#include <experimental/coroutine> | |||||
#endif | |||||
#include "src/stop_token.h" | |||||
#include "src/config.h" | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
#include <iostream> | |||||
#endif | |||||
#include "src/def.h" | |||||
#include "src/macro_def.inl" | |||||
#include "src/counted_ptr.h" | |||||
#include "src/type_traits.inl" | |||||
#include "src/type_concept.inl" | |||||
#include "src/spinlock.h" | |||||
#include "src/state.h" | |||||
#include "src/future.h" | |||||
#include "src/promise.h" | |||||
#include "src/awaitable.h" | |||||
#include "src/generator.h" | |||||
#include "src/rf_task.h" | |||||
#include "src/timer.h" | |||||
#include "src/scheduler.h" | |||||
#include "src/promise.inl" | |||||
#include "src/state.inl" | |||||
#include "src/switch_scheduler.h" | |||||
#include "src/current_scheduler.h" | |||||
#include "src/yield.h" | |||||
#include "src/sleep.h" | |||||
#include "src/when.h" | |||||
#include "src/_awaker.h" | |||||
#include "src/ring_queue.h" | |||||
#include "src/intrusive_link_queue.h" | |||||
#include "src/channel.h" | |||||
#include "src/event.h" | |||||
#include "src/mutex.h" | |||||
namespace resumef = librf; |
#pragma once | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
namespace resumef | |||||
{ | |||||
namespace detail | |||||
{ | |||||
template<class _Ety, class... _Types> | |||||
struct _awaker | |||||
{ | |||||
//如果超时 | |||||
// e 始终为nullptr | |||||
// 不关心返回值 | |||||
//如果不是超时, | |||||
// e 指向当前触发的事件,用于实现wait_any | |||||
// 返回true表示成功触发了事件,event内部减小一次事件计数,并删除此awaker | |||||
// 返回false表示此事件已经无效,event内部只删除此awaker | |||||
typedef std::function<bool(_Ety * e, _Types...)> callee_type; | |||||
private: | |||||
typedef spinlock lock_type; | |||||
//typedef std::recursive_mutex lock_type; | |||||
lock_type _lock; | |||||
callee_type _callee; | |||||
std::atomic<intptr_t> _counter; | |||||
public: | |||||
_awaker(callee_type && callee_, intptr_t init_count_ = 0) | |||||
: _callee(std::forward<callee_type>(callee_)) | |||||
, _counter(init_count_) | |||||
{ | |||||
} | |||||
//调用一次后,_callee就被置nullptr,下次再调用,必然返回false | |||||
//第一次调用,返回调用_callee的返回值 | |||||
//超时通过传入nullptr来调用 | |||||
bool awake(_Ety * e, intptr_t count_, const _Types&... args) | |||||
{ | |||||
assert(count_ > 0); | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
if ((this->_counter.fetch_sub(count_) - count_) <= 0) | |||||
{ | |||||
if (this->_callee) | |||||
{ | |||||
callee_type callee_ = std::move(this->_callee); | |||||
return callee_(e, args...); | |||||
} | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
private: | |||||
_awaker(const _awaker &) = delete; | |||||
_awaker(_awaker &&) = delete; | |||||
_awaker & operator = (const _awaker &) = delete; | |||||
_awaker & operator = (_awaker &&) = delete; | |||||
}; | |||||
} | |||||
} | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
#pragma once | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
namespace librf | |||||
{ | |||||
namespace detail | |||||
{ | |||||
template<class _Ety, class... _Types> | |||||
struct _awaker | |||||
{ | |||||
//如果超时 | |||||
// e 始终为nullptr | |||||
// 不关心返回值 | |||||
//如果不是超时, | |||||
// e 指向当前触发的事件,用于实现wait_any | |||||
// 返回true表示成功触发了事件,event内部减小一次事件计数,并删除此awaker | |||||
// 返回false表示此事件已经无效,event内部只删除此awaker | |||||
typedef std::function<bool(_Ety * e, _Types...)> callee_type; | |||||
private: | |||||
typedef spinlock lock_type; | |||||
//typedef std::recursive_mutex lock_type; | |||||
lock_type _lock; | |||||
callee_type _callee; | |||||
std::atomic<intptr_t> _counter; | |||||
public: | |||||
_awaker(callee_type && callee_, intptr_t init_count_ = 0) | |||||
: _callee(std::forward<callee_type>(callee_)) | |||||
, _counter(init_count_) | |||||
{ | |||||
} | |||||
//调用一次后,_callee就被置nullptr,下次再调用,必然返回false | |||||
//第一次调用,返回调用_callee的返回值 | |||||
//超时通过传入nullptr来调用 | |||||
bool awake(_Ety * e, intptr_t count_, const _Types&... args) | |||||
{ | |||||
assert(count_ > 0); | |||||
scoped_lock<lock_type> lock_(this->_lock); | |||||
if ((this->_counter.fetch_sub(count_) - count_) <= 0) | |||||
{ | |||||
if (this->_callee) | |||||
{ | |||||
callee_type callee_ = std::move(this->_callee); | |||||
return callee_(e, args...); | |||||
} | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
private: | |||||
_awaker(const _awaker &) = delete; | |||||
_awaker(_awaker &&) = delete; | |||||
_awaker & operator = (const _awaker &) = delete; | |||||
_awaker & operator = (_awaker &&) = delete; | |||||
}; | |||||
} | |||||
} | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
/** | /** |
#pragma once | |||||
#include "channel_v2.h" | |||||
#include "channel_v2.inl" | |||||
#pragma once | |||||
#include "channel_v2.h" | |||||
#include "channel_v2.inl" |
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | #ifndef DOXYGEN_SKIP_PROPERTY | ||||
namespace detail | namespace detail | ||||
*/ | */ | ||||
using semaphore_t = channel_t<bool, false, true>; | using semaphore_t = channel_t<bool, false, true>; | ||||
} //namespace resumef | |||||
} //namespace librf |
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
namespace detail | namespace detail | ||||
{ | { | ||||
return write_awaiter{ _chan.get(), std::forward<U>(val) }; | return write_awaiter{ _chan.get(), std::forward<U>(val) }; | ||||
} | } | ||||
} //namespace resumef | |||||
} //namespace librf |
#pragma once | |||||
namespace resumef | |||||
{ | |||||
/** | |||||
* @brief 专用与state的智能计数指针,通过管理state内嵌的引用计数来管理state的生存期。 | |||||
*/ | |||||
template <typename T> | |||||
struct counted_ptr | |||||
{ | |||||
/** | |||||
* @brief 构造一个无内容的计数指针。 | |||||
*/ | |||||
counted_ptr() noexcept = default; | |||||
/** | |||||
* @brief 拷贝构造函数。 | |||||
*/ | |||||
counted_ptr(const counted_ptr& cp) noexcept : _p(cp._p) | |||||
{ | |||||
_lock(); | |||||
} | |||||
/** | |||||
* @brief 通过裸指针构造一个计数指针。 | |||||
*/ | |||||
counted_ptr(T* p) noexcept : _p(p) | |||||
{ | |||||
_lock(); | |||||
} | |||||
/** | |||||
* @brief 移动构造函数。 | |||||
*/ | |||||
counted_ptr(counted_ptr&& cp) noexcept : _p(std::exchange(cp._p, nullptr)) | |||||
{ | |||||
} | |||||
/** | |||||
* @brief 拷贝赋值函数。 | |||||
*/ | |||||
counted_ptr& operator=(const counted_ptr& cp) | |||||
{ | |||||
if (&cp != this) | |||||
{ | |||||
counted_ptr t(cp); | |||||
std::swap(_p, t._p); | |||||
} | |||||
return *this; | |||||
} | |||||
/** | |||||
* @brief 移动赋值函数。 | |||||
*/ | |||||
counted_ptr& operator=(counted_ptr&& cp) | |||||
{ | |||||
if (&cp != this) | |||||
{ | |||||
std::swap(_p, cp._p); | |||||
cp._unlock(); | |||||
} | |||||
return *this; | |||||
} | |||||
void swap(counted_ptr& cp) noexcept | |||||
{ | |||||
std::swap(_p, cp._p); | |||||
} | |||||
/** | |||||
* @brief 析构函数中自动做一个计数减一操作。计数减为0,则删除state对象。 | |||||
*/ | |||||
~counted_ptr() | |||||
{ | |||||
_unlock(); | |||||
} | |||||
/** | |||||
* @brief 重载指针操作符。 | |||||
*/ | |||||
T* operator->() const noexcept | |||||
{ | |||||
return _p; | |||||
} | |||||
/** | |||||
* @brief 获得管理的state指针。 | |||||
*/ | |||||
T* get() const noexcept | |||||
{ | |||||
return _p; | |||||
} | |||||
/** | |||||
* @brief 重置为空指针。 | |||||
*/ | |||||
void reset() | |||||
{ | |||||
_unlock(); | |||||
} | |||||
private: | |||||
void _unlock() | |||||
{ | |||||
if (likely(_p != nullptr)) | |||||
{ | |||||
auto t = _p; | |||||
_p = nullptr; | |||||
t->unlock(); | |||||
} | |||||
} | |||||
void _lock(T* p) noexcept | |||||
{ | |||||
if (p != nullptr) | |||||
p->lock(); | |||||
_p = p; | |||||
} | |||||
void _lock() noexcept | |||||
{ | |||||
if (_p != nullptr) | |||||
_p->lock(); | |||||
} | |||||
T* _p = nullptr; | |||||
}; | |||||
template <typename T, typename U> | |||||
inline bool operator == (const counted_ptr<T>& _Left, const counted_ptr<U>& _Right) | |||||
{ | |||||
return _Left.get() == _Right.get(); | |||||
} | |||||
template <typename T> | |||||
inline bool operator == (const counted_ptr<T>& _Left, std::nullptr_t) | |||||
{ | |||||
return _Left.get() == nullptr; | |||||
} | |||||
template <typename T> | |||||
inline bool operator == (std::nullptr_t, const counted_ptr<T>& _Left) | |||||
{ | |||||
return _Left.get() == nullptr; | |||||
} | |||||
template <typename T> | |||||
inline bool operator != (const counted_ptr<T>& _Left, std::nullptr_t) | |||||
{ | |||||
return _Left.get() != nullptr; | |||||
} | |||||
template <typename T> | |||||
inline bool operator != (std::nullptr_t, const counted_ptr<T>& _Left) | |||||
{ | |||||
return _Left.get() != nullptr; | |||||
} | |||||
} | |||||
namespace std | |||||
{ | |||||
template<typename T> | |||||
inline void swap(resumef::counted_ptr<T>& a, resumef::counted_ptr<T>& b) noexcept | |||||
{ | |||||
a.swap(b); | |||||
} | |||||
} | |||||
#pragma once | |||||
namespace librf | |||||
{ | |||||
/** | |||||
* @brief 专用与state的智能计数指针,通过管理state内嵌的引用计数来管理state的生存期。 | |||||
*/ | |||||
template <typename T> | |||||
struct counted_ptr | |||||
{ | |||||
/** | |||||
* @brief 构造一个无内容的计数指针。 | |||||
*/ | |||||
counted_ptr() noexcept = default; | |||||
/** | |||||
* @brief 拷贝构造函数。 | |||||
*/ | |||||
counted_ptr(const counted_ptr& cp) noexcept : _p(cp._p) | |||||
{ | |||||
_lock(); | |||||
} | |||||
/** | |||||
* @brief 通过裸指针构造一个计数指针。 | |||||
*/ | |||||
counted_ptr(T* p) noexcept : _p(p) | |||||
{ | |||||
_lock(); | |||||
} | |||||
/** | |||||
* @brief 移动构造函数。 | |||||
*/ | |||||
counted_ptr(counted_ptr&& cp) noexcept : _p(std::exchange(cp._p, nullptr)) | |||||
{ | |||||
} | |||||
/** | |||||
* @brief 拷贝赋值函数。 | |||||
*/ | |||||
counted_ptr& operator=(const counted_ptr& cp) | |||||
{ | |||||
if (&cp != this) | |||||
{ | |||||
counted_ptr t(cp); | |||||
std::swap(_p, t._p); | |||||
} | |||||
return *this; | |||||
} | |||||
/** | |||||
* @brief 移动赋值函数。 | |||||
*/ | |||||
counted_ptr& operator=(counted_ptr&& cp) | |||||
{ | |||||
if (&cp != this) | |||||
{ | |||||
std::swap(_p, cp._p); | |||||
cp._unlock(); | |||||
} | |||||
return *this; | |||||
} | |||||
void swap(counted_ptr& cp) noexcept | |||||
{ | |||||
std::swap(_p, cp._p); | |||||
} | |||||
/** | |||||
* @brief 析构函数中自动做一个计数减一操作。计数减为0,则删除state对象。 | |||||
*/ | |||||
~counted_ptr() | |||||
{ | |||||
_unlock(); | |||||
} | |||||
/** | |||||
* @brief 重载指针操作符。 | |||||
*/ | |||||
T* operator->() const noexcept | |||||
{ | |||||
return _p; | |||||
} | |||||
/** | |||||
* @brief 获得管理的state指针。 | |||||
*/ | |||||
T* get() const noexcept | |||||
{ | |||||
return _p; | |||||
} | |||||
/** | |||||
* @brief 重置为空指针。 | |||||
*/ | |||||
void reset() | |||||
{ | |||||
_unlock(); | |||||
} | |||||
private: | |||||
void _unlock() | |||||
{ | |||||
if (likely(_p != nullptr)) | |||||
{ | |||||
auto t = _p; | |||||
_p = nullptr; | |||||
t->unlock(); | |||||
} | |||||
} | |||||
void _lock(T* p) noexcept | |||||
{ | |||||
if (p != nullptr) | |||||
p->lock(); | |||||
_p = p; | |||||
} | |||||
void _lock() noexcept | |||||
{ | |||||
if (_p != nullptr) | |||||
_p->lock(); | |||||
} | |||||
T* _p = nullptr; | |||||
}; | |||||
template <typename T, typename U> | |||||
inline bool operator == (const counted_ptr<T>& _Left, const counted_ptr<U>& _Right) | |||||
{ | |||||
return _Left.get() == _Right.get(); | |||||
} | |||||
template <typename T> | |||||
inline bool operator == (const counted_ptr<T>& _Left, std::nullptr_t) | |||||
{ | |||||
return _Left.get() == nullptr; | |||||
} | |||||
template <typename T> | |||||
inline bool operator == (std::nullptr_t, const counted_ptr<T>& _Left) | |||||
{ | |||||
return _Left.get() == nullptr; | |||||
} | |||||
template <typename T> | |||||
inline bool operator != (const counted_ptr<T>& _Left, std::nullptr_t) | |||||
{ | |||||
return _Left.get() != nullptr; | |||||
} | |||||
template <typename T> | |||||
inline bool operator != (std::nullptr_t, const counted_ptr<T>& _Left) | |||||
{ | |||||
return _Left.get() != nullptr; | |||||
} | |||||
} | |||||
namespace std | |||||
{ | |||||
template<typename T> | |||||
inline void swap(librf::counted_ptr<T>& a, librf::counted_ptr<T>& b) noexcept | |||||
{ | |||||
a.swap(b); | |||||
} | |||||
} |
#pragma once | |||||
namespace resumef | |||||
{ | |||||
/** | |||||
* @brief 获得本协程绑定的调度器的可等待对象。 | |||||
*/ | |||||
struct get_current_scheduler_awaitor | |||||
{ | |||||
bool await_ready() const noexcept | |||||
{ | |||||
return false; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
_PromiseT& promise = handler.promise(); | |||||
auto* state = promise.get_state(); | |||||
this->_scheduler = state->get_scheduler(); | |||||
return false; | |||||
} | |||||
scheduler_t* await_resume() const noexcept | |||||
{ | |||||
return _scheduler; | |||||
} | |||||
private: | |||||
scheduler_t* _scheduler; | |||||
#ifdef DOXYGEN_SKIP_PROPERTY | |||||
public: | |||||
/** | |||||
* @brief 获得当前协程绑定的调度器。 | |||||
* @details 立即返回,没有协程切换和等待。\n | |||||
* 推荐使用 current_scheduler() 宏替代 co_await get_current_scheduler()。 | |||||
* @return [co_await] scheduler_t* | |||||
* @note 本函数是resumef名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 get_current_scheduler_awaitor 类下。 | |||||
*/ | |||||
static get_current_scheduler_awaitor get_current_scheduler() noexcept; | |||||
/** | |||||
* @brief 获得当前协程绑定的调度器。 | |||||
* @details 立即返回,没有协程切换和等待。\n | |||||
* 这是一条宏函数,等同于 co_await get_current_scheduler()。 | |||||
* @return scheduler_t* | |||||
* @note 由于doxygen使用上的问题,将之归纳到 get_current_scheduler_awaitor 类下。 | |||||
*/ | |||||
static scheduler_t* current_scheduler() noexcept; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
}; | |||||
/** | |||||
* @brief 获得当前协程绑定的调度器。 | |||||
* @details 立即返回,没有协程切换和等待。\n | |||||
* 推荐使用 current_scheduler() 宏替代 co_await get_current_scheduler()。 | |||||
* @return [co_await] scheduler_t* | |||||
*/ | |||||
inline get_current_scheduler_awaitor get_current_scheduler() noexcept | |||||
{ | |||||
return {}; | |||||
} | |||||
/** | |||||
* @brief 获得本协程绑定的跟state指针的可等待对象。 | |||||
*/ | |||||
struct get_root_state_awaitor | |||||
{ | |||||
bool await_ready() const noexcept | |||||
{ | |||||
return false; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
_PromiseT& promise = handler.promise(); | |||||
auto* parent = promise.get_state(); | |||||
this->_state = parent->get_root(); | |||||
return false; | |||||
} | |||||
state_base_t* await_resume() const noexcept | |||||
{ | |||||
return _state; | |||||
} | |||||
private: | |||||
state_base_t* _state; | |||||
#ifdef DOXYGEN_SKIP_PROPERTY | |||||
public: | |||||
/** | |||||
* @brief 获得当前协程的跟state指针。 | |||||
* @details 立即返回,没有协程切换和等待。\n | |||||
* 推荐使用 root_state() 宏替代 co_await get_root_state()。 | |||||
* @return [co_await] state_base_t* | |||||
* @note 本函数是resumef名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 get_root_state_awaitor 类下。 | |||||
*/ | |||||
static get_root_state_awaitor get_root_state() noexcept; | |||||
/** | |||||
* @brief 获得当前协程的跟state指针。 | |||||
* @details 立即返回,没有协程切换和等待。 | |||||
* 这是一条宏函数,等同于 co_await get_root_state()。 | |||||
* @return state_base_t* | |||||
* @note 由于doxygen使用上的问题,将之归纳到 get_root_state_awaitor 类下。 | |||||
*/ | |||||
static state_base_t* root_state() noexcept; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
}; | |||||
/** | |||||
* @brief 获得当前协程的跟state指针。 | |||||
* @details 立即返回,没有协程切换和等待。 | |||||
* 推荐使用 root_state() 宏替代 co_await get_root_state()。 | |||||
* @return [co_await] state_base_t* | |||||
*/ | |||||
inline get_root_state_awaitor get_root_state() noexcept | |||||
{ | |||||
return {}; | |||||
} | |||||
/** | |||||
* @brief 获得本协程的task_t对象。 | |||||
*/ | |||||
struct get_current_task_awaitor | |||||
{ | |||||
bool await_ready() const noexcept | |||||
{ | |||||
return false; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
_PromiseT& promise = handler.promise(); | |||||
auto* parent = promise.get_state(); | |||||
state_base_t * state = parent->get_root(); | |||||
scheduler_t* sch = state->get_scheduler(); | |||||
this->_task = sch->find_task(state); | |||||
return false; | |||||
} | |||||
task_t* await_resume() const noexcept | |||||
{ | |||||
return _task; | |||||
} | |||||
private: | |||||
task_t* _task; | |||||
#ifdef DOXYGEN_SKIP_PROPERTY | |||||
public: | |||||
/** | |||||
* @brief 获得当前协程的task_t指针。 | |||||
* @details 立即返回,没有协程切换和等待。 | |||||
* 推荐使用 current_task() 宏替代 co_await get_current_task()。 | |||||
* @return [co_await] task_t* | |||||
* @note 本函数是resumef名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 get_current_task_awaitor 类下。 | |||||
*/ | |||||
static get_root_state_awaitor get_current_task() noexcept; | |||||
/** | |||||
* @brief 获得当前协程的task_t指针。 | |||||
* @details 立即返回,没有协程切换和等待。 | |||||
* 这是一条宏函数,等同于 co_await get_current_task()。 | |||||
* @return task_t* | |||||
* @note 由于doxygen使用上的问题,将之归纳到 get_current_task_awaitor 类下。 | |||||
*/ | |||||
static task_t* current_task() noexcept; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
}; | |||||
/** | |||||
* @brief 获得当前协程的task_t指针。 | |||||
* @details 立即返回,没有协程切换和等待。 | |||||
* 推荐使用 current_task() 宏替代 co_await get_current_task()。 | |||||
* @return [co_await] task_t* | |||||
*/ | |||||
inline get_current_task_awaitor get_current_task() noexcept | |||||
{ | |||||
return {}; | |||||
} | |||||
} | |||||
#pragma once | |||||
namespace librf | |||||
{ | |||||
/** | |||||
* @brief 获得本协程绑定的调度器的可等待对象。 | |||||
*/ | |||||
struct get_current_scheduler_awaitor | |||||
{ | |||||
bool await_ready() const noexcept | |||||
{ | |||||
return false; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
_PromiseT& promise = handler.promise(); | |||||
auto* state = promise.get_state(); | |||||
this->_scheduler = state->get_scheduler(); | |||||
return false; | |||||
} | |||||
scheduler_t* await_resume() const noexcept | |||||
{ | |||||
return _scheduler; | |||||
} | |||||
private: | |||||
scheduler_t* _scheduler; | |||||
#ifdef DOXYGEN_SKIP_PROPERTY | |||||
public: | |||||
/** | |||||
* @brief 获得当前协程绑定的调度器。 | |||||
* @details 立即返回,没有协程切换和等待。\n | |||||
* 推荐使用 current_scheduler() 宏替代 co_await get_current_scheduler()。 | |||||
* @return [co_await] scheduler_t* | |||||
* @note 本函数是librf名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 get_current_scheduler_awaitor 类下。 | |||||
*/ | |||||
static get_current_scheduler_awaitor get_current_scheduler() noexcept; | |||||
/** | |||||
* @brief 获得当前协程绑定的调度器。 | |||||
* @details 立即返回,没有协程切换和等待。\n | |||||
* 这是一条宏函数,等同于 co_await get_current_scheduler()。 | |||||
* @return scheduler_t* | |||||
* @note 由于doxygen使用上的问题,将之归纳到 get_current_scheduler_awaitor 类下。 | |||||
*/ | |||||
static scheduler_t* current_scheduler() noexcept; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
}; | |||||
/** | |||||
* @brief 获得当前协程绑定的调度器。 | |||||
* @details 立即返回,没有协程切换和等待。\n | |||||
* 推荐使用 current_scheduler() 宏替代 co_await get_current_scheduler()。 | |||||
* @return [co_await] scheduler_t* | |||||
*/ | |||||
inline get_current_scheduler_awaitor get_current_scheduler() noexcept | |||||
{ | |||||
return {}; | |||||
} | |||||
/** | |||||
* @brief 获得本协程绑定的跟state指针的可等待对象。 | |||||
*/ | |||||
struct get_root_state_awaitor | |||||
{ | |||||
bool await_ready() const noexcept | |||||
{ | |||||
return false; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
_PromiseT& promise = handler.promise(); | |||||
auto* parent = promise.get_state(); | |||||
this->_state = parent->get_root(); | |||||
return false; | |||||
} | |||||
state_base_t* await_resume() const noexcept | |||||
{ | |||||
return _state; | |||||
} | |||||
private: | |||||
state_base_t* _state; | |||||
#ifdef DOXYGEN_SKIP_PROPERTY | |||||
public: | |||||
/** | |||||
* @brief 获得当前协程的跟state指针。 | |||||
* @details 立即返回,没有协程切换和等待。\n | |||||
* 推荐使用 root_state() 宏替代 co_await get_root_state()。 | |||||
* @return [co_await] state_base_t* | |||||
* @note 本函数是librf名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 get_root_state_awaitor 类下。 | |||||
*/ | |||||
static get_root_state_awaitor get_root_state() noexcept; | |||||
/** | |||||
* @brief 获得当前协程的跟state指针。 | |||||
* @details 立即返回,没有协程切换和等待。 | |||||
* 这是一条宏函数,等同于 co_await get_root_state()。 | |||||
* @return state_base_t* | |||||
* @note 由于doxygen使用上的问题,将之归纳到 get_root_state_awaitor 类下。 | |||||
*/ | |||||
static state_base_t* root_state() noexcept; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
}; | |||||
/** | |||||
* @brief 获得当前协程的跟state指针。 | |||||
* @details 立即返回,没有协程切换和等待。 | |||||
* 推荐使用 root_state() 宏替代 co_await get_root_state()。 | |||||
* @return [co_await] state_base_t* | |||||
*/ | |||||
inline get_root_state_awaitor get_root_state() noexcept | |||||
{ | |||||
return {}; | |||||
} | |||||
/** | |||||
* @brief 获得本协程的task_t对象。 | |||||
*/ | |||||
struct get_current_task_awaitor | |||||
{ | |||||
bool await_ready() const noexcept | |||||
{ | |||||
return false; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
_PromiseT& promise = handler.promise(); | |||||
auto* parent = promise.get_state(); | |||||
state_base_t * state = parent->get_root(); | |||||
scheduler_t* sch = state->get_scheduler(); | |||||
this->_task = sch->find_task(state); | |||||
return false; | |||||
} | |||||
task_t* await_resume() const noexcept | |||||
{ | |||||
return _task; | |||||
} | |||||
private: | |||||
task_t* _task; | |||||
#ifdef DOXYGEN_SKIP_PROPERTY | |||||
public: | |||||
/** | |||||
* @brief 获得当前协程的task_t指针。 | |||||
* @details 立即返回,没有协程切换和等待。 | |||||
* 推荐使用 current_task() 宏替代 co_await get_current_task()。 | |||||
* @return [co_await] task_t* | |||||
* @note 本函数是librf名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 get_current_task_awaitor 类下。 | |||||
*/ | |||||
static get_root_state_awaitor get_current_task() noexcept; | |||||
/** | |||||
* @brief 获得当前协程的task_t指针。 | |||||
* @details 立即返回,没有协程切换和等待。 | |||||
* 这是一条宏函数,等同于 co_await get_current_task()。 | |||||
* @return task_t* | |||||
* @note 由于doxygen使用上的问题,将之归纳到 get_current_task_awaitor 类下。 | |||||
*/ | |||||
static task_t* current_task() noexcept; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
}; | |||||
/** | |||||
* @brief 获得当前协程的task_t指针。 | |||||
* @details 立即返回,没有协程切换和等待。 | |||||
* 推荐使用 current_task() 宏替代 co_await get_current_task()。 | |||||
* @return [co_await] task_t* | |||||
*/ | |||||
inline get_current_task_awaitor get_current_task() noexcept | |||||
{ | |||||
return {}; | |||||
} | |||||
} |
#pragma once | |||||
#define LIB_RESUMEF_VERSION 30000 // 3.0.0 | |||||
#ifndef __cpp_impl_coroutine | |||||
namespace std | |||||
{ | |||||
using experimental::coroutine_traits; | |||||
using experimental::coroutine_handle; | |||||
using experimental::suspend_if; | |||||
using experimental::suspend_always; | |||||
using experimental::suspend_never; | |||||
} | |||||
#endif | |||||
namespace resumef | |||||
{ | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
struct scheduler_t; | |||||
template<class _Ty = void> | |||||
struct future_t; | |||||
template <typename _Ty = std::nullptr_t, typename _Alloc = std::allocator<char>> | |||||
struct generator_t; | |||||
template<class _Ty = void> | |||||
struct promise_t; | |||||
template<class _Ty = void> | |||||
struct awaitable_t; | |||||
struct state_base_t; | |||||
struct switch_scheduler_t; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
template<typename _PromiseT = void> | |||||
using coroutine_handle = std::coroutine_handle<_PromiseT>; | |||||
using suspend_always = std::suspend_always; | |||||
using suspend_never = std::suspend_never; | |||||
template<class... _Mutexes> | |||||
using scoped_lock = std::scoped_lock<_Mutexes...>; | |||||
using stop_source = milk::concurrency::stop_source; | |||||
using stop_token = milk::concurrency::stop_token; | |||||
template<typename Callback> | |||||
using stop_callback = milk::concurrency::stop_callback<Callback>; | |||||
using milk::concurrency::nostopstate; | |||||
/** | |||||
* @brief 版本号。 | |||||
*/ | |||||
constexpr size_t _Version = LIB_RESUMEF_VERSION; | |||||
/** | |||||
* @brief 获得当前线程下的调度器。 | |||||
*/ | |||||
scheduler_t* this_scheduler(); | |||||
} | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
extern std::mutex g_resumef_cout_mutex; | |||||
extern std::atomic<intptr_t> g_resumef_state_count; | |||||
extern std::atomic<intptr_t> g_resumef_task_count; | |||||
extern std::atomic<intptr_t> g_resumef_evtctx_count; | |||||
extern std::atomic<intptr_t> g_resumef_state_id; | |||||
#endif | |||||
namespace resumef | |||||
{ | |||||
template<class T> | |||||
struct remove_cvref | |||||
{ | |||||
typedef std::remove_cv_t<std::remove_reference_t<T>> type; | |||||
}; | |||||
template<class T> | |||||
using remove_cvref_t = typename remove_cvref<T>::type; | |||||
template<class _Ty> | |||||
constexpr size_t _Align_size() | |||||
{ | |||||
const size_t _ALIGN_REQ = sizeof(void*) * 2; | |||||
return std::is_empty_v<_Ty> ? 0 : | |||||
(sizeof(_Ty) + _ALIGN_REQ - 1) & ~(_ALIGN_REQ - 1); | |||||
} | |||||
template<class _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); | |||||
} | |||||
template<class _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); | |||||
} | |||||
} | |||||
#include "exception.inl" | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
#pragma once | |||||
#define LIB_RESUMEF_VERSION 30000 // 3.0.0 | |||||
#ifndef __cpp_impl_coroutine | |||||
namespace std | |||||
{ | |||||
using experimental::coroutine_traits; | |||||
using experimental::coroutine_handle; | |||||
using experimental::suspend_if; | |||||
using experimental::suspend_always; | |||||
using experimental::suspend_never; | |||||
} | |||||
#endif | |||||
namespace librf | |||||
{ | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
struct scheduler_t; | |||||
template<class _Ty = void> | |||||
struct future_t; | |||||
template <typename _Ty = std::nullptr_t, typename _Alloc = std::allocator<char>> | |||||
struct generator_t; | |||||
template<class _Ty = void> | |||||
struct promise_t; | |||||
template<class _Ty = void> | |||||
struct awaitable_t; | |||||
struct state_base_t; | |||||
struct switch_scheduler_t; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
template<typename _PromiseT = void> | |||||
using coroutine_handle = std::coroutine_handle<_PromiseT>; | |||||
using suspend_always = std::suspend_always; | |||||
using suspend_never = std::suspend_never; | |||||
template<class... _Mutexes> | |||||
using scoped_lock = std::scoped_lock<_Mutexes...>; | |||||
using stop_source = milk::concurrency::stop_source; | |||||
using stop_token = milk::concurrency::stop_token; | |||||
template<typename Callback> | |||||
using stop_callback = milk::concurrency::stop_callback<Callback>; | |||||
using milk::concurrency::nostopstate; | |||||
/** | |||||
* @brief 版本号。 | |||||
*/ | |||||
constexpr size_t _Version = LIB_RESUMEF_VERSION; | |||||
/** | |||||
* @brief 获得当前线程下的调度器。 | |||||
*/ | |||||
scheduler_t* this_scheduler(); | |||||
} | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
extern std::mutex g_resumef_cout_mutex; | |||||
extern std::atomic<intptr_t> g_resumef_state_count; | |||||
extern std::atomic<intptr_t> g_resumef_task_count; | |||||
extern std::atomic<intptr_t> g_resumef_evtctx_count; | |||||
extern std::atomic<intptr_t> g_resumef_state_id; | |||||
#endif | |||||
namespace librf | |||||
{ | |||||
template<class T> | |||||
struct remove_cvref | |||||
{ | |||||
typedef std::remove_cv_t<std::remove_reference_t<T>> type; | |||||
}; | |||||
template<class T> | |||||
using remove_cvref_t = typename remove_cvref<T>::type; | |||||
template<class _Ty> | |||||
constexpr size_t _Align_size() | |||||
{ | |||||
const size_t _ALIGN_REQ = sizeof(void*) * 2; | |||||
return std::is_empty_v<_Ty> ? 0 : | |||||
(sizeof(_Ty) + _ALIGN_REQ - 1) & ~(_ALIGN_REQ - 1); | |||||
} | |||||
template<class _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); | |||||
} | |||||
template<class _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); | |||||
} | |||||
} | |||||
#include "exception.inl" | |||||
#endif //DOXYGEN_SKIP_PROPERTY |
#pragma once | |||||
#include "event_v2.h" | |||||
#include "event_v2.inl" | |||||
#pragma once | |||||
#include "event_v2.h" | |||||
#include "event_v2.inl" |
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | #ifndef DOXYGEN_SKIP_PROPERTY | ||||
namespace detail | namespace detail |
#pragma once | |||||
namespace resumef | |||||
{ | |||||
namespace detail | |||||
{ | |||||
struct state_event_base_t; | |||||
struct event_v2_impl : public std::enable_shared_from_this<event_v2_impl> | |||||
{ | |||||
event_v2_impl(bool initially) noexcept; | |||||
~event_v2_impl(); | |||||
bool is_signaled() const noexcept | |||||
{ | |||||
return _counter.load(std::memory_order_acquire) > 0; | |||||
} | |||||
void reset() noexcept | |||||
{ | |||||
_counter.store(0, std::memory_order_release); | |||||
} | |||||
void signal_all() noexcept; | |||||
void signal() noexcept; | |||||
public: | |||||
static constexpr bool USE_SPINLOCK = true; | |||||
static constexpr bool USE_LINK_QUEUE = false; | |||||
using lock_type = std::conditional_t<USE_SPINLOCK, spinlock, std::recursive_mutex>; | |||||
using state_event_ptr = counted_ptr<state_event_base_t>; | |||||
using link_state_queue = intrusive_link_queue<state_event_base_t, state_event_ptr>; | |||||
using wait_queue_type = std::conditional_t<USE_LINK_QUEUE, link_state_queue, std::list<state_event_ptr>>; | |||||
bool try_wait_one() noexcept | |||||
{ | |||||
if (_counter.load(std::memory_order_consume) > 0) | |||||
{ | |||||
if (_counter.fetch_add(-1, std::memory_order_acq_rel) > 0) | |||||
return true; | |||||
_counter.fetch_add(1); | |||||
} | |||||
return false; | |||||
} | |||||
void add_wait_list(state_event_base_t* state) noexcept | |||||
{ | |||||
assert(state != nullptr); | |||||
_wait_awakes.push_back(state); | |||||
} | |||||
lock_type _lock; //保证访问本对象是线程安全的 | |||||
private: | |||||
std::atomic<intptr_t> _counter; | |||||
wait_queue_type _wait_awakes; //等待队列 | |||||
// No copying/moving | |||||
event_v2_impl(const event_v2_impl&) = delete; | |||||
event_v2_impl(event_v2_impl&&) = delete; | |||||
event_v2_impl& operator=(const event_v2_impl&) = delete; | |||||
event_v2_impl& operator=(event_v2_impl&&) = delete; | |||||
}; | |||||
struct state_event_base_t : public state_base_t | |||||
{ | |||||
virtual void resume() override; | |||||
virtual bool has_handler() const noexcept override; | |||||
virtual void on_cancel() noexcept = 0; | |||||
virtual bool on_notify(event_v2_impl* eptr) = 0; | |||||
virtual bool on_timeout() = 0; | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
scheduler_t* on_await_suspend(coroutine_handle<_PromiseT> handler) noexcept | |||||
{ | |||||
_PromiseT& promise = handler.promise(); | |||||
auto* parent = promise.get_state(); | |||||
scheduler_t* sch = parent->get_scheduler(); | |||||
this->_scheduler = sch; | |||||
this->_coro = handler; | |||||
return sch; | |||||
} | |||||
inline void add_timeout_timer(std::chrono::system_clock::time_point tp) | |||||
{ | |||||
this->_thandler = this->_scheduler->timer()->add_handler(tp, | |||||
[st = counted_ptr<state_event_base_t>{ this }](bool canceld) | |||||
{ | |||||
if (!canceld) | |||||
st->on_timeout(); | |||||
}); | |||||
} | |||||
//为侵入式单向链表提供的next指针 | |||||
//counted_ptr<state_event_base_t> _next = nullptr; | |||||
timer_handler _thandler; | |||||
}; | |||||
struct state_event_t : public state_event_base_t | |||||
{ | |||||
state_event_t(event_v2_impl*& val) | |||||
: _value(&val) | |||||
{} | |||||
virtual void on_cancel() noexcept override; | |||||
virtual bool on_notify(event_v2_impl* eptr) override; | |||||
virtual bool on_timeout() override; | |||||
protected: | |||||
//_value引用awaitor保存的值,这样可以尽可能减少创建state的可能。而不必进入没有state就没有value实体被用于返回。 | |||||
//在调用on_notify()或on_timeout()任意之一后,置为nullptr。 | |||||
//这样来保证要么超时了,要么响应了signal的通知了。 | |||||
//这个指针在on_notify()和on_timeout()里,当作一个互斥的锁来防止同时进入两个函数 | |||||
std::atomic<event_v2_impl**> _value; | |||||
}; | |||||
struct state_event_all_t : public state_event_base_t | |||||
{ | |||||
state_event_all_t(intptr_t count, bool& val) | |||||
: _counter(count) | |||||
, _value(&val) | |||||
{} | |||||
virtual void on_cancel() noexcept override; | |||||
virtual bool on_notify(event_v2_impl* eptr) override; | |||||
virtual bool on_timeout() override; | |||||
std::atomic<intptr_t> _counter; | |||||
protected: | |||||
bool* _value; | |||||
}; | |||||
} | |||||
inline void event_t::signal_all() const noexcept | |||||
{ | |||||
_event->signal_all(); | |||||
} | |||||
inline void event_t::signal() const noexcept | |||||
{ | |||||
_event->signal(); | |||||
} | |||||
inline void event_t::reset() const noexcept | |||||
{ | |||||
_event->reset(); | |||||
} | |||||
struct [[nodiscard]] event_t::awaiter | |||||
{ | |||||
awaiter(detail::event_v2_impl* evt) noexcept | |||||
: _event(evt) | |||||
{ | |||||
} | |||||
bool await_ready() noexcept | |||||
{ | |||||
scoped_lock<detail::event_v2_impl::lock_type> lock_(_event->_lock); | |||||
return _event->try_wait_one(); | |||||
} | |||||
template<class _PromiseT, class _Timeout, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend2(coroutine_handle<_PromiseT> handler, const _Timeout& cb) | |||||
{ | |||||
(void)cb; | |||||
detail::event_v2_impl* evt = _event; | |||||
scoped_lock<detail::event_v2_impl::lock_type> lock_(evt->_lock); | |||||
if (evt->try_wait_one()) | |||||
return false; | |||||
_state = new detail::state_event_t(_event); | |||||
_event = nullptr; | |||||
(void)_state->on_await_suspend(handler); | |||||
if constexpr (!std::is_same_v<std::remove_reference_t<_Timeout>, std::nullptr_t>) | |||||
cb(); | |||||
evt->add_wait_list(_state.get()); | |||||
return true; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
return await_suspend2(handler, nullptr); | |||||
} | |||||
bool await_resume() noexcept | |||||
{ | |||||
return _event != nullptr; | |||||
} | |||||
protected: | |||||
detail::event_v2_impl* _event; | |||||
counted_ptr<detail::state_event_t> _state; | |||||
}; | |||||
inline event_t::awaiter event_t::operator co_await() const noexcept | |||||
{ | |||||
return { _event.get() }; | |||||
} | |||||
inline event_t::awaiter event_t::wait() const noexcept | |||||
{ | |||||
return { _event.get() }; | |||||
} | |||||
template<class _Btype> | |||||
struct event_t::timeout_awaitor_impl : public _Btype | |||||
{ | |||||
template<class... Args> | |||||
timeout_awaitor_impl(clock_type::time_point tp, Args&&... args) noexcept(std::is_nothrow_constructible_v<_Btype, Args&&...>) | |||||
: _Btype(std::forward<Args>(args)...) | |||||
, _tp(tp) | |||||
{} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
if (!_Btype::await_suspend2(handler, [this] | |||||
{ | |||||
this->_state->add_timeout_timer(_tp); | |||||
})) | |||||
return false; | |||||
return true; | |||||
} | |||||
protected: | |||||
clock_type::time_point _tp; | |||||
}; | |||||
struct [[nodiscard]] event_t::timeout_awaiter : timeout_awaitor_impl<awaiter> | |||||
{ | |||||
using timeout_awaitor_impl<awaiter>::timeout_awaitor_impl; | |||||
}; | |||||
template<class _Rep, class _Period> | |||||
inline event_t::timeout_awaiter event_t::wait_for(const std::chrono::duration<_Rep, _Period>& dt) const noexcept | |||||
{ | |||||
clock_type::time_point tp2 = clock_type::now() + std::chrono::duration_cast<clock_type::duration>(dt); | |||||
return { tp2, _event.get() }; | |||||
} | |||||
template<class _Clock, class _Duration> | |||||
inline event_t::timeout_awaiter event_t::wait_until(const std::chrono::time_point<_Clock, _Duration>& tp) const noexcept | |||||
{ | |||||
clock_type::time_point tp2 = std::chrono::time_point_cast<clock_type::duration>(tp); | |||||
return { tp2, _event.get() }; | |||||
} | |||||
template<class _Iter> | |||||
struct [[nodiscard]] event_t::any_awaiter | |||||
{ | |||||
any_awaiter(_Iter begin, _Iter end) noexcept | |||||
: _begin(begin) | |||||
, _end(end) | |||||
{ | |||||
} | |||||
bool await_ready() noexcept | |||||
{ | |||||
return _begin == _end; | |||||
} | |||||
template<class _PromiseT, class _Timeout, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend2(coroutine_handle<_PromiseT> handler, const _Timeout& cb) | |||||
{ | |||||
(void)cb; | |||||
using ref_lock_type = std::reference_wrapper<detail::event_v2_impl::lock_type>; | |||||
std::vector<ref_lock_type> lockes; | |||||
lockes.reserve(std::distance(_begin, _end)); | |||||
for (auto iter = _begin; iter != _end; ++iter) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
lockes.emplace_back(std::ref(evt->_lock)); | |||||
} | |||||
batch_lock_t<ref_lock_type> lock_(lockes); | |||||
for (auto iter = _begin; iter != _end; ++iter) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
if (evt->try_wait_one()) | |||||
{ | |||||
_event = evt; | |||||
return false; | |||||
} | |||||
} | |||||
_state = new detail::state_event_t(_event); | |||||
(void)_state->on_await_suspend(handler); | |||||
if constexpr (!std::is_same_v<std::remove_reference_t<_Timeout>, std::nullptr_t>) | |||||
cb(); | |||||
for (auto iter = _begin; iter != _end; ++iter) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
evt->add_wait_list(_state.get()); | |||||
} | |||||
return true; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
return await_suspend2(handler, nullptr); | |||||
} | |||||
intptr_t await_resume() noexcept | |||||
{ | |||||
if (_begin == _end) | |||||
return 0; | |||||
if (_event == nullptr) | |||||
return -1; | |||||
intptr_t idx = 0; | |||||
for (auto iter = _begin; iter != _end; ++iter, ++idx) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
if (evt == _event) | |||||
return idx; | |||||
} | |||||
return -1; | |||||
} | |||||
protected: | |||||
detail::event_v2_impl* _event = nullptr; | |||||
counted_ptr<detail::state_event_t> _state; | |||||
_Iter _begin; | |||||
_Iter _end; | |||||
}; | |||||
template<class _Iter> | |||||
requires(_IteratorOfT<_Iter, event_t>) | |||||
auto event_t::wait_any(_Iter begin_, _Iter end_) ->event_t::any_awaiter<_Iter> | |||||
{ | |||||
return { begin_, end_ }; | |||||
} | |||||
template<class _Cont> | |||||
requires(_ContainerOfT<_Cont, event_t>) | |||||
auto event_t::wait_any(const _Cont& cnt_) ->event_t::any_awaiter<decltype(std::begin(cnt_))> | |||||
{ | |||||
return { std::begin(cnt_), std::end(cnt_) }; | |||||
} | |||||
template<class _Iter> | |||||
struct [[nodiscard]] event_t::timeout_any_awaiter : timeout_awaitor_impl<any_awaiter<_Iter>> | |||||
{ | |||||
using timeout_awaitor_impl<any_awaiter<_Iter>>::timeout_awaitor_impl; | |||||
}; | |||||
template<class _Rep, class _Period, class _Iter> | |||||
requires(_IteratorOfT<_Iter, event_t>) | |||||
auto event_t::wait_any_for(const std::chrono::duration<_Rep, _Period>& dt, _Iter begin_, _Iter end_) | |||||
->event_t::timeout_any_awaiter<_Iter> | |||||
{ | |||||
clock_type::time_point tp = clock_type::now() + std::chrono::duration_cast<clock_type::duration>(dt); | |||||
return { tp, begin_, end_ }; | |||||
} | |||||
template<class _Rep, class _Period, class _Cont> | |||||
requires(_ContainerOfT<_Cont, event_t>) | |||||
auto event_t::wait_any_for(const std::chrono::duration<_Rep, _Period>& dt, const _Cont& cnt_) | |||||
->event_t::timeout_any_awaiter<decltype(std::begin(cnt_))> | |||||
{ | |||||
clock_type::time_point tp = clock_type::now() + std::chrono::duration_cast<clock_type::duration>(dt); | |||||
return { tp, std::begin(cnt_), std::end(cnt_) }; | |||||
} | |||||
template<class _Iter> | |||||
struct [[nodiscard]] event_t::all_awaiter | |||||
{ | |||||
all_awaiter(_Iter begin, _Iter end) noexcept | |||||
: _begin(begin) | |||||
, _end(end) | |||||
{ | |||||
} | |||||
bool await_ready() noexcept | |||||
{ | |||||
_value = _begin == _end; | |||||
return _value; | |||||
} | |||||
template<class _PromiseT, class _Timeout, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend2(coroutine_handle<_PromiseT> handler, const _Timeout& cb) | |||||
{ | |||||
(void)cb; | |||||
intptr_t count = std::distance(_begin, _end); | |||||
using ref_lock_type = std::reference_wrapper<detail::event_v2_impl::lock_type>; | |||||
std::vector<ref_lock_type> lockes; | |||||
lockes.reserve(count); | |||||
for (auto iter = _begin; iter != _end; ++iter) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
lockes.push_back(evt->_lock); | |||||
} | |||||
_state = new detail::state_event_all_t(count, _value); | |||||
(void)_state->on_await_suspend(handler); | |||||
if constexpr (!std::is_same_v<std::remove_reference_t<_Timeout>, std::nullptr_t>) | |||||
cb(); | |||||
batch_lock_t<ref_lock_type> lock_(lockes); | |||||
for (auto iter = _begin; iter != _end; ++iter) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
if (evt->try_wait_one()) | |||||
{ | |||||
_state->_counter.fetch_sub(1, std::memory_order_acq_rel); | |||||
} | |||||
else | |||||
{ | |||||
evt->add_wait_list(_state.get()); | |||||
} | |||||
} | |||||
if (_state->_counter.load(std::memory_order_relaxed) == 0) | |||||
{ | |||||
_state = nullptr; | |||||
_value = true; | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
return await_suspend2(handler, nullptr); | |||||
} | |||||
bool await_resume() noexcept | |||||
{ | |||||
return _value; | |||||
} | |||||
protected: | |||||
_Iter _begin; | |||||
_Iter _end; | |||||
counted_ptr<detail::state_event_all_t> _state; | |||||
bool _value = false; | |||||
}; | |||||
template<class _Iter> | |||||
requires(_IteratorOfT<_Iter, event_t>) | |||||
auto event_t::wait_all(_Iter begin_, _Iter end_) ->all_awaiter<_Iter> | |||||
{ | |||||
return { begin_, end_ }; | |||||
} | |||||
template<class _Cont> | |||||
requires(_ContainerOfT<_Cont, event_t>) | |||||
auto event_t::wait_all(const _Cont& cnt_) ->all_awaiter<decltype(std::begin(cnt_))> | |||||
{ | |||||
return { std::begin(cnt_), std::end(cnt_) }; | |||||
} | |||||
template<class _Iter> | |||||
struct [[nodiscard]] event_t::timeout_all_awaiter : timeout_awaitor_impl<all_awaiter<_Iter>> | |||||
{ | |||||
using timeout_awaitor_impl<all_awaiter<_Iter>>::timeout_awaitor_impl; | |||||
}; | |||||
template<class _Rep, class _Period, class _Iter> | |||||
requires(_IteratorOfT<_Iter, event_t>) | |||||
auto event_t::wait_all_for(const std::chrono::duration<_Rep, _Period>& dt, _Iter begin_, _Iter end_) | |||||
->event_t::timeout_all_awaiter<_Iter> | |||||
{ | |||||
clock_type::time_point tp = clock_type::now() + std::chrono::duration_cast<clock_type::duration>(dt); | |||||
return { tp, begin_, end_ }; | |||||
} | |||||
template<class _Rep, class _Period, class _Cont> | |||||
requires(_ContainerOfT<_Cont, event_t>) | |||||
auto event_t::wait_all_for(const std::chrono::duration<_Rep, _Period>& dt, const _Cont& cnt_) | |||||
->event_t::timeout_all_awaiter<decltype(std::begin(cnt_))> | |||||
{ | |||||
clock_type::time_point tp = clock_type::now() + std::chrono::duration_cast<clock_type::duration>(dt); | |||||
return { tp, std::begin(cnt_), std::end(cnt_) }; | |||||
} | |||||
} | |||||
#pragma once | |||||
namespace librf | |||||
{ | |||||
namespace detail | |||||
{ | |||||
struct state_event_base_t; | |||||
struct event_v2_impl : public std::enable_shared_from_this<event_v2_impl> | |||||
{ | |||||
event_v2_impl(bool initially) noexcept; | |||||
~event_v2_impl(); | |||||
bool is_signaled() const noexcept | |||||
{ | |||||
return _counter.load(std::memory_order_acquire) > 0; | |||||
} | |||||
void reset() noexcept | |||||
{ | |||||
_counter.store(0, std::memory_order_release); | |||||
} | |||||
void signal_all() noexcept; | |||||
void signal() noexcept; | |||||
public: | |||||
static constexpr bool USE_SPINLOCK = true; | |||||
static constexpr bool USE_LINK_QUEUE = false; | |||||
using lock_type = std::conditional_t<USE_SPINLOCK, spinlock, std::recursive_mutex>; | |||||
using state_event_ptr = counted_ptr<state_event_base_t>; | |||||
using link_state_queue = intrusive_link_queue<state_event_base_t, state_event_ptr>; | |||||
using wait_queue_type = std::conditional_t<USE_LINK_QUEUE, link_state_queue, std::list<state_event_ptr>>; | |||||
bool try_wait_one() noexcept | |||||
{ | |||||
if (_counter.load(std::memory_order_consume) > 0) | |||||
{ | |||||
if (_counter.fetch_add(-1, std::memory_order_acq_rel) > 0) | |||||
return true; | |||||
_counter.fetch_add(1); | |||||
} | |||||
return false; | |||||
} | |||||
void add_wait_list(state_event_base_t* state) noexcept | |||||
{ | |||||
assert(state != nullptr); | |||||
_wait_awakes.push_back(state); | |||||
} | |||||
lock_type _lock; //保证访问本对象是线程安全的 | |||||
private: | |||||
std::atomic<intptr_t> _counter; | |||||
wait_queue_type _wait_awakes; //等待队列 | |||||
// No copying/moving | |||||
event_v2_impl(const event_v2_impl&) = delete; | |||||
event_v2_impl(event_v2_impl&&) = delete; | |||||
event_v2_impl& operator=(const event_v2_impl&) = delete; | |||||
event_v2_impl& operator=(event_v2_impl&&) = delete; | |||||
}; | |||||
struct state_event_base_t : public state_base_t | |||||
{ | |||||
virtual void resume() override; | |||||
virtual bool has_handler() const noexcept override; | |||||
virtual void on_cancel() noexcept = 0; | |||||
virtual bool on_notify(event_v2_impl* eptr) = 0; | |||||
virtual bool on_timeout() = 0; | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
scheduler_t* on_await_suspend(coroutine_handle<_PromiseT> handler) noexcept | |||||
{ | |||||
_PromiseT& promise = handler.promise(); | |||||
auto* parent = promise.get_state(); | |||||
scheduler_t* sch = parent->get_scheduler(); | |||||
this->_scheduler = sch; | |||||
this->_coro = handler; | |||||
return sch; | |||||
} | |||||
inline void add_timeout_timer(std::chrono::system_clock::time_point tp) | |||||
{ | |||||
this->_thandler = this->_scheduler->timer()->add_handler(tp, | |||||
[st = counted_ptr<state_event_base_t>{ this }](bool canceld) | |||||
{ | |||||
if (!canceld) | |||||
st->on_timeout(); | |||||
}); | |||||
} | |||||
//为侵入式单向链表提供的next指针 | |||||
//counted_ptr<state_event_base_t> _next = nullptr; | |||||
timer_handler _thandler; | |||||
}; | |||||
struct state_event_t : public state_event_base_t | |||||
{ | |||||
state_event_t(event_v2_impl*& val) | |||||
: _value(&val) | |||||
{} | |||||
virtual void on_cancel() noexcept override; | |||||
virtual bool on_notify(event_v2_impl* eptr) override; | |||||
virtual bool on_timeout() override; | |||||
protected: | |||||
//_value引用awaitor保存的值,这样可以尽可能减少创建state的可能。而不必进入没有state就没有value实体被用于返回。 | |||||
//在调用on_notify()或on_timeout()任意之一后,置为nullptr。 | |||||
//这样来保证要么超时了,要么响应了signal的通知了。 | |||||
//这个指针在on_notify()和on_timeout()里,当作一个互斥的锁来防止同时进入两个函数 | |||||
std::atomic<event_v2_impl**> _value; | |||||
}; | |||||
struct state_event_all_t : public state_event_base_t | |||||
{ | |||||
state_event_all_t(intptr_t count, bool& val) | |||||
: _counter(count) | |||||
, _value(&val) | |||||
{} | |||||
virtual void on_cancel() noexcept override; | |||||
virtual bool on_notify(event_v2_impl* eptr) override; | |||||
virtual bool on_timeout() override; | |||||
std::atomic<intptr_t> _counter; | |||||
protected: | |||||
bool* _value; | |||||
}; | |||||
} | |||||
inline void event_t::signal_all() const noexcept | |||||
{ | |||||
_event->signal_all(); | |||||
} | |||||
inline void event_t::signal() const noexcept | |||||
{ | |||||
_event->signal(); | |||||
} | |||||
inline void event_t::reset() const noexcept | |||||
{ | |||||
_event->reset(); | |||||
} | |||||
struct [[nodiscard]] event_t::awaiter | |||||
{ | |||||
awaiter(detail::event_v2_impl* evt) noexcept | |||||
: _event(evt) | |||||
{ | |||||
} | |||||
bool await_ready() noexcept | |||||
{ | |||||
scoped_lock<detail::event_v2_impl::lock_type> lock_(_event->_lock); | |||||
return _event->try_wait_one(); | |||||
} | |||||
template<class _PromiseT, class _Timeout, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend2(coroutine_handle<_PromiseT> handler, const _Timeout& cb) | |||||
{ | |||||
(void)cb; | |||||
detail::event_v2_impl* evt = _event; | |||||
scoped_lock<detail::event_v2_impl::lock_type> lock_(evt->_lock); | |||||
if (evt->try_wait_one()) | |||||
return false; | |||||
_state = new detail::state_event_t(_event); | |||||
_event = nullptr; | |||||
(void)_state->on_await_suspend(handler); | |||||
if constexpr (!std::is_same_v<std::remove_reference_t<_Timeout>, std::nullptr_t>) | |||||
cb(); | |||||
evt->add_wait_list(_state.get()); | |||||
return true; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
return await_suspend2(handler, nullptr); | |||||
} | |||||
bool await_resume() noexcept | |||||
{ | |||||
return _event != nullptr; | |||||
} | |||||
protected: | |||||
detail::event_v2_impl* _event; | |||||
counted_ptr<detail::state_event_t> _state; | |||||
}; | |||||
inline event_t::awaiter event_t::operator co_await() const noexcept | |||||
{ | |||||
return { _event.get() }; | |||||
} | |||||
inline event_t::awaiter event_t::wait() const noexcept | |||||
{ | |||||
return { _event.get() }; | |||||
} | |||||
template<class _Btype> | |||||
struct event_t::timeout_awaitor_impl : public _Btype | |||||
{ | |||||
template<class... Args> | |||||
timeout_awaitor_impl(clock_type::time_point tp, Args&&... args) noexcept(std::is_nothrow_constructible_v<_Btype, Args&&...>) | |||||
: _Btype(std::forward<Args>(args)...) | |||||
, _tp(tp) | |||||
{} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
if (!_Btype::await_suspend2(handler, [this] | |||||
{ | |||||
this->_state->add_timeout_timer(_tp); | |||||
})) | |||||
return false; | |||||
return true; | |||||
} | |||||
protected: | |||||
clock_type::time_point _tp; | |||||
}; | |||||
struct [[nodiscard]] event_t::timeout_awaiter : timeout_awaitor_impl<awaiter> | |||||
{ | |||||
using timeout_awaitor_impl<awaiter>::timeout_awaitor_impl; | |||||
}; | |||||
template<class _Rep, class _Period> | |||||
inline event_t::timeout_awaiter event_t::wait_for(const std::chrono::duration<_Rep, _Period>& dt) const noexcept | |||||
{ | |||||
clock_type::time_point tp2 = clock_type::now() + std::chrono::duration_cast<clock_type::duration>(dt); | |||||
return { tp2, _event.get() }; | |||||
} | |||||
template<class _Clock, class _Duration> | |||||
inline event_t::timeout_awaiter event_t::wait_until(const std::chrono::time_point<_Clock, _Duration>& tp) const noexcept | |||||
{ | |||||
clock_type::time_point tp2 = std::chrono::time_point_cast<clock_type::duration>(tp); | |||||
return { tp2, _event.get() }; | |||||
} | |||||
template<class _Iter> | |||||
struct [[nodiscard]] event_t::any_awaiter | |||||
{ | |||||
any_awaiter(_Iter begin, _Iter end) noexcept | |||||
: _begin(begin) | |||||
, _end(end) | |||||
{ | |||||
} | |||||
bool await_ready() noexcept | |||||
{ | |||||
return _begin == _end; | |||||
} | |||||
template<class _PromiseT, class _Timeout, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend2(coroutine_handle<_PromiseT> handler, const _Timeout& cb) | |||||
{ | |||||
(void)cb; | |||||
using ref_lock_type = std::reference_wrapper<detail::event_v2_impl::lock_type>; | |||||
std::vector<ref_lock_type> lockes; | |||||
lockes.reserve(std::distance(_begin, _end)); | |||||
for (auto iter = _begin; iter != _end; ++iter) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
lockes.emplace_back(std::ref(evt->_lock)); | |||||
} | |||||
batch_lock_t<ref_lock_type> lock_(lockes); | |||||
for (auto iter = _begin; iter != _end; ++iter) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
if (evt->try_wait_one()) | |||||
{ | |||||
_event = evt; | |||||
return false; | |||||
} | |||||
} | |||||
_state = new detail::state_event_t(_event); | |||||
(void)_state->on_await_suspend(handler); | |||||
if constexpr (!std::is_same_v<std::remove_reference_t<_Timeout>, std::nullptr_t>) | |||||
cb(); | |||||
for (auto iter = _begin; iter != _end; ++iter) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
evt->add_wait_list(_state.get()); | |||||
} | |||||
return true; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
return await_suspend2(handler, nullptr); | |||||
} | |||||
intptr_t await_resume() noexcept | |||||
{ | |||||
if (_begin == _end) | |||||
return 0; | |||||
if (_event == nullptr) | |||||
return -1; | |||||
intptr_t idx = 0; | |||||
for (auto iter = _begin; iter != _end; ++iter, ++idx) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
if (evt == _event) | |||||
return idx; | |||||
} | |||||
return -1; | |||||
} | |||||
protected: | |||||
detail::event_v2_impl* _event = nullptr; | |||||
counted_ptr<detail::state_event_t> _state; | |||||
_Iter _begin; | |||||
_Iter _end; | |||||
}; | |||||
template<class _Iter> | |||||
requires(_IteratorOfT<_Iter, event_t>) | |||||
auto event_t::wait_any(_Iter begin_, _Iter end_) ->event_t::any_awaiter<_Iter> | |||||
{ | |||||
return { begin_, end_ }; | |||||
} | |||||
template<class _Cont> | |||||
requires(_ContainerOfT<_Cont, event_t>) | |||||
auto event_t::wait_any(const _Cont& cnt_) ->event_t::any_awaiter<decltype(std::begin(cnt_))> | |||||
{ | |||||
return { std::begin(cnt_), std::end(cnt_) }; | |||||
} | |||||
template<class _Iter> | |||||
struct [[nodiscard]] event_t::timeout_any_awaiter : timeout_awaitor_impl<any_awaiter<_Iter>> | |||||
{ | |||||
using timeout_awaitor_impl<any_awaiter<_Iter>>::timeout_awaitor_impl; | |||||
}; | |||||
template<class _Rep, class _Period, class _Iter> | |||||
requires(_IteratorOfT<_Iter, event_t>) | |||||
auto event_t::wait_any_for(const std::chrono::duration<_Rep, _Period>& dt, _Iter begin_, _Iter end_) | |||||
->event_t::timeout_any_awaiter<_Iter> | |||||
{ | |||||
clock_type::time_point tp = clock_type::now() + std::chrono::duration_cast<clock_type::duration>(dt); | |||||
return { tp, begin_, end_ }; | |||||
} | |||||
template<class _Rep, class _Period, class _Cont> | |||||
requires(_ContainerOfT<_Cont, event_t>) | |||||
auto event_t::wait_any_for(const std::chrono::duration<_Rep, _Period>& dt, const _Cont& cnt_) | |||||
->event_t::timeout_any_awaiter<decltype(std::begin(cnt_))> | |||||
{ | |||||
clock_type::time_point tp = clock_type::now() + std::chrono::duration_cast<clock_type::duration>(dt); | |||||
return { tp, std::begin(cnt_), std::end(cnt_) }; | |||||
} | |||||
template<class _Iter> | |||||
struct [[nodiscard]] event_t::all_awaiter | |||||
{ | |||||
all_awaiter(_Iter begin, _Iter end) noexcept | |||||
: _begin(begin) | |||||
, _end(end) | |||||
{ | |||||
} | |||||
bool await_ready() noexcept | |||||
{ | |||||
_value = _begin == _end; | |||||
return _value; | |||||
} | |||||
template<class _PromiseT, class _Timeout, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend2(coroutine_handle<_PromiseT> handler, const _Timeout& cb) | |||||
{ | |||||
(void)cb; | |||||
intptr_t count = std::distance(_begin, _end); | |||||
using ref_lock_type = std::reference_wrapper<detail::event_v2_impl::lock_type>; | |||||
std::vector<ref_lock_type> lockes; | |||||
lockes.reserve(count); | |||||
for (auto iter = _begin; iter != _end; ++iter) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
lockes.push_back(evt->_lock); | |||||
} | |||||
_state = new detail::state_event_all_t(count, _value); | |||||
(void)_state->on_await_suspend(handler); | |||||
if constexpr (!std::is_same_v<std::remove_reference_t<_Timeout>, std::nullptr_t>) | |||||
cb(); | |||||
batch_lock_t<ref_lock_type> lock_(lockes); | |||||
for (auto iter = _begin; iter != _end; ++iter) | |||||
{ | |||||
detail::event_v2_impl* evt = (*iter)._event.get(); | |||||
if (evt->try_wait_one()) | |||||
{ | |||||
_state->_counter.fetch_sub(1, std::memory_order_acq_rel); | |||||
} | |||||
else | |||||
{ | |||||
evt->add_wait_list(_state.get()); | |||||
} | |||||
} | |||||
if (_state->_counter.load(std::memory_order_relaxed) == 0) | |||||
{ | |||||
_state = nullptr; | |||||
_value = true; | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
bool await_suspend(coroutine_handle<_PromiseT> handler) | |||||
{ | |||||
return await_suspend2(handler, nullptr); | |||||
} | |||||
bool await_resume() noexcept | |||||
{ | |||||
return _value; | |||||
} | |||||
protected: | |||||
_Iter _begin; | |||||
_Iter _end; | |||||
counted_ptr<detail::state_event_all_t> _state; | |||||
bool _value = false; | |||||
}; | |||||
template<class _Iter> | |||||
requires(_IteratorOfT<_Iter, event_t>) | |||||
auto event_t::wait_all(_Iter begin_, _Iter end_) ->all_awaiter<_Iter> | |||||
{ | |||||
return { begin_, end_ }; | |||||
} | |||||
template<class _Cont> | |||||
requires(_ContainerOfT<_Cont, event_t>) | |||||
auto event_t::wait_all(const _Cont& cnt_) ->all_awaiter<decltype(std::begin(cnt_))> | |||||
{ | |||||
return { std::begin(cnt_), std::end(cnt_) }; | |||||
} | |||||
template<class _Iter> | |||||
struct [[nodiscard]] event_t::timeout_all_awaiter : timeout_awaitor_impl<all_awaiter<_Iter>> | |||||
{ | |||||
using timeout_awaitor_impl<all_awaiter<_Iter>>::timeout_awaitor_impl; | |||||
}; | |||||
template<class _Rep, class _Period, class _Iter> | |||||
requires(_IteratorOfT<_Iter, event_t>) | |||||
auto event_t::wait_all_for(const std::chrono::duration<_Rep, _Period>& dt, _Iter begin_, _Iter end_) | |||||
->event_t::timeout_all_awaiter<_Iter> | |||||
{ | |||||
clock_type::time_point tp = clock_type::now() + std::chrono::duration_cast<clock_type::duration>(dt); | |||||
return { tp, begin_, end_ }; | |||||
} | |||||
template<class _Rep, class _Period, class _Cont> | |||||
requires(_ContainerOfT<_Cont, event_t>) | |||||
auto event_t::wait_all_for(const std::chrono::duration<_Rep, _Period>& dt, const _Cont& cnt_) | |||||
->event_t::timeout_all_awaiter<decltype(std::begin(cnt_))> | |||||
{ | |||||
clock_type::time_point tp = clock_type::now() + std::chrono::duration_cast<clock_type::duration>(dt); | |||||
return { tp, std::begin(cnt_), std::end(cnt_) }; | |||||
} | |||||
} |
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
/** | /** |
| |||||
#pragma once | |||||
namespace resumef | |||||
{ | |||||
/** | |||||
* @brief 用于resumef协程的返回值。 | |||||
* @details 由于coroutines的限制,协程的返回值必须明确申明,而不能通过auto推导。\n | |||||
* 用在恢复函数(resumeable function)里,支持co_await和co_yield。\n | |||||
* 用在可等待函数(awaitable function)里,与awaitable_t<>配套使用。 | |||||
*/ | |||||
template<class _Ty> | |||||
struct [[nodiscard]] future_t | |||||
{ | |||||
using promise_type = promise_t<_Ty>; | |||||
using value_type = _Ty; | |||||
using state_type = state_t<value_type>; | |||||
using future_type = future_t<value_type>; | |||||
using lock_type = typename state_type::lock_type; | |||||
counted_ptr<state_type> _state; | |||||
future_t(counted_ptr<state_type> _st) noexcept | |||||
:_state(std::move(_st)) {} | |||||
future_t(const future_t&) noexcept = default; | |||||
future_t(future_t&&) noexcept = default; | |||||
future_t& operator = (const future_t&) noexcept = default; | |||||
future_t& operator = (future_t&&) = default; | |||||
bool await_ready() const noexcept | |||||
{ | |||||
return _state->future_await_ready(); | |||||
} | |||||
template<class _PromiseT/*, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>*/> | |||||
void await_suspend(coroutine_handle<_PromiseT> handler) const | |||||
{ | |||||
_state->future_await_suspend(handler); | |||||
} | |||||
_Ty await_resume() const | |||||
{ | |||||
return _state->future_await_resume(); | |||||
} | |||||
}; | |||||
} | |||||
| |||||
#pragma once | |||||
namespace librf | |||||
{ | |||||
/** | |||||
* @brief 用于librf协程的返回值。 | |||||
* @details 由于coroutines的限制,协程的返回值必须明确申明,而不能通过auto推导。\n | |||||
* 用在恢复函数(resumeable function)里,支持co_await和co_yield。\n | |||||
* 用在可等待函数(awaitable function)里,与awaitable_t<>配套使用。 | |||||
*/ | |||||
template<class _Ty> | |||||
struct [[nodiscard]] future_t | |||||
{ | |||||
using promise_type = promise_t<_Ty>; | |||||
using value_type = _Ty; | |||||
using state_type = state_t<value_type>; | |||||
using future_type = future_t<value_type>; | |||||
using lock_type = typename state_type::lock_type; | |||||
counted_ptr<state_type> _state; | |||||
future_t(counted_ptr<state_type> _st) noexcept | |||||
:_state(std::move(_st)) {} | |||||
future_t(const future_t&) noexcept = default; | |||||
future_t(future_t&&) noexcept = default; | |||||
future_t& operator = (const future_t&) noexcept = default; | |||||
future_t& operator = (future_t&&) = default; | |||||
bool await_ready() const noexcept | |||||
{ | |||||
return _state->future_await_ready(); | |||||
} | |||||
template<class _PromiseT/*, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>*/> | |||||
void await_suspend(coroutine_handle<_PromiseT> handler) const | |||||
{ | |||||
_state->future_await_suspend(handler); | |||||
} | |||||
_Ty await_resume() const | |||||
{ | |||||
return _state->future_await_resume(); | |||||
} | |||||
}; | |||||
} |
/* | |||||
* Modify from <experimental/generator_t.h> | |||||
* Purpose: Library support of coroutines. generator_t class | |||||
* http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0057r0.pdf | |||||
*/ | |||||
#pragma once | |||||
#pragma pack(push,_CRT_PACKING) | |||||
#pragma push_macro("new") | |||||
#undef new | |||||
namespace resumef | |||||
{ | |||||
template <typename _Ty, typename promise_type> | |||||
struct generator_iterator; | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
template<typename promise_type> | |||||
struct generator_iterator<void, promise_type> | |||||
{ | |||||
typedef std::input_iterator_tag iterator_category; | |||||
typedef ptrdiff_t difference_type; | |||||
coroutine_handle<promise_type> _Coro; | |||||
generator_iterator(std::nullptr_t) : _Coro(nullptr) | |||||
{ | |||||
} | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : _Coro(_CoroArg) | |||||
{ | |||||
} | |||||
generator_iterator& operator++() | |||||
{ | |||||
if (_Coro.done()) | |||||
_Coro = nullptr; | |||||
else | |||||
_Coro.resume(); | |||||
return *this; | |||||
} | |||||
void operator++(int) | |||||
{ | |||||
// This postincrement operator meets the requirements of the Ranges TS | |||||
// InputIterator concept, but not those of Standard C++ InputIterator. | |||||
++* this; | |||||
} | |||||
bool operator==(generator_iterator const& right_) const | |||||
{ | |||||
return _Coro == right_._Coro; | |||||
} | |||||
bool operator!=(generator_iterator const& right_) const | |||||
{ | |||||
return !(*this == right_); | |||||
} | |||||
}; | |||||
template <typename promise_type> | |||||
struct generator_iterator<std::nullptr_t, promise_type> : public generator_iterator<void, promise_type> | |||||
{ | |||||
generator_iterator(std::nullptr_t) : generator_iterator<void, promise_type>(nullptr) | |||||
{ | |||||
} | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : generator_iterator<void, promise_type>(_CoroArg) | |||||
{ | |||||
} | |||||
}; | |||||
template <typename _Ty, typename promise_type> | |||||
struct generator_iterator : public generator_iterator<void, promise_type> | |||||
{ | |||||
using value_type = _Ty; | |||||
using reference = _Ty const&; | |||||
using pointer = _Ty const*; | |||||
generator_iterator(std::nullptr_t) : generator_iterator<void, promise_type>(nullptr) | |||||
{ | |||||
} | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : generator_iterator<void, promise_type>(_CoroArg) | |||||
{ | |||||
} | |||||
reference operator*() const | |||||
{ | |||||
return *this->_Coro.promise()._CurrentValue; | |||||
} | |||||
pointer operator->() const | |||||
{ | |||||
return this->_Coro.promise()._CurrentValue; | |||||
} | |||||
}; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
/** | |||||
* @brief 专用于co_yield函数。 | |||||
*/ | |||||
template <typename _Ty, typename _Alloc> | |||||
struct generator_t | |||||
{ | |||||
using value_type = _Ty; | |||||
using state_type = state_generator_t; | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
struct promise_type | |||||
{ | |||||
using value_type = _Ty; | |||||
using state_type = state_generator_t; | |||||
using future_type = generator_t<value_type>; | |||||
_Ty const* _CurrentValue; | |||||
promise_type() | |||||
{ | |||||
get_state()->set_initial_suspend(coroutine_handle<promise_type>::from_promise(*this)); | |||||
} | |||||
promise_type(promise_type&& _Right) noexcept = default; | |||||
promise_type& operator = (promise_type&& _Right) noexcept = default; | |||||
promise_type(const promise_type&) = default; | |||||
promise_type& operator = (const promise_type&) = default; | |||||
generator_t get_return_object() | |||||
{ | |||||
return generator_t{ *this }; | |||||
} | |||||
suspend_always initial_suspend() noexcept | |||||
{ | |||||
return {}; | |||||
} | |||||
suspend_always final_suspend() noexcept | |||||
{ | |||||
return {}; | |||||
} | |||||
suspend_always yield_value(_Ty const& _Value) noexcept | |||||
{ | |||||
_CurrentValue = std::addressof(_Value); | |||||
return {}; | |||||
} | |||||
//template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>> | |||||
void return_value(_Ty const& _Value) noexcept | |||||
{ | |||||
_CurrentValue = std::addressof(_Value); | |||||
} | |||||
//template<class = std::enable_if_t<std::is_same_v<_Ty, void>, _Ty>> | |||||
void return_value() noexcept | |||||
{ | |||||
_CurrentValue = nullptr; | |||||
} | |||||
void set_exception(std::exception_ptr e) | |||||
{ | |||||
(void)e; | |||||
//ref_state()->set_exception(std::move(e)); | |||||
std::terminate(); | |||||
} | |||||
#if defined(__cpp_impl_coroutine) || defined(__clang__) || defined(__GNUC__) | |||||
void unhandled_exception() | |||||
{ | |||||
//this->ref_state()->set_exception(std::current_exception()); | |||||
std::terminate(); | |||||
} | |||||
#endif | |||||
template <typename _Uty> | |||||
_Uty&& await_transform(_Uty&& _Whatever) noexcept | |||||
{ | |||||
static_assert(std::is_same_v<_Uty, void>, | |||||
"co_await is not supported in coroutines of type std::experiemental::generator_t"); | |||||
return std::forward<_Uty>(_Whatever); | |||||
} | |||||
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) | |||||
char* ptr = reinterpret_cast<char*>(this) - _State_size; | |||||
return reinterpret_cast<state_type*>(ptr); | |||||
#else | |||||
#error "Unknown compiler" | |||||
#endif | |||||
#else | |||||
return _state.get(); | |||||
#endif | |||||
} | |||||
//counted_ptr<state_type> ref_state() noexcept | |||||
//{ | |||||
// return { get_state() }; | |||||
//} | |||||
state_type* ref_state() noexcept | |||||
{ | |||||
return get_state(); | |||||
} | |||||
using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc<char>; | |||||
static_assert(std::is_same_v<char*, typename std::allocator_traits<_Alloc_char>::pointer>, | |||||
"generator_t does not support allocators with fancy pointer types"); | |||||
static_assert(std::allocator_traits<_Alloc_char>::is_always_equal::value, | |||||
"generator_t only supports stateless allocators"); | |||||
void* 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)); | |||||
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 = state_type::_Construct(ptr); | |||||
st->lock(); | |||||
} | |||||
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<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; | |||||
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 | |||||
}; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
using iterator = generator_iterator<_Ty, promise_type>; | |||||
iterator begin() | |||||
{ | |||||
if (_Coro) | |||||
{ | |||||
_Coro.resume(); | |||||
if (_Coro.done()) | |||||
return{ nullptr }; | |||||
} | |||||
return { _Coro }; | |||||
} | |||||
iterator end() | |||||
{ | |||||
return{ nullptr }; | |||||
} | |||||
explicit generator_t(promise_type& _Prom) | |||||
: _Coro(coroutine_handle<promise_type>::from_promise(_Prom)) | |||||
{ | |||||
} | |||||
generator_t() = default; | |||||
generator_t(generator_t const&) = delete; | |||||
generator_t& operator=(generator_t const&) = delete; | |||||
generator_t(generator_t&& right_) noexcept | |||||
: _Coro(right_._Coro) | |||||
{ | |||||
right_._Coro = nullptr; | |||||
} | |||||
generator_t& operator=(generator_t&& right_) noexcept | |||||
{ | |||||
if (this != std::addressof(right_)) { | |||||
_Coro = right_._Coro; | |||||
right_._Coro = nullptr; | |||||
} | |||||
return *this; | |||||
} | |||||
~generator_t() | |||||
{ | |||||
if (_Coro) { | |||||
_Coro.destroy(); | |||||
} | |||||
} | |||||
state_type* detach_state() | |||||
{ | |||||
auto t = _Coro; | |||||
_Coro = nullptr; | |||||
return t.promise().get_state(); | |||||
} | |||||
private: | |||||
coroutine_handle<promise_type> _Coro = nullptr; | |||||
}; | |||||
} // namespace resumef | |||||
#pragma pop_macro("new") | |||||
#pragma pack(pop) | |||||
/* | |||||
* Modify from <experimental/generator_t.h> | |||||
* Purpose: Library support of coroutines. generator_t class | |||||
* http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0057r0.pdf | |||||
*/ | |||||
#pragma once | |||||
#pragma pack(push,_CRT_PACKING) | |||||
#pragma push_macro("new") | |||||
#undef new | |||||
namespace librf | |||||
{ | |||||
template <typename _Ty, typename promise_type> | |||||
struct generator_iterator; | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
template<typename promise_type> | |||||
struct generator_iterator<void, promise_type> | |||||
{ | |||||
typedef std::input_iterator_tag iterator_category; | |||||
typedef ptrdiff_t difference_type; | |||||
coroutine_handle<promise_type> _Coro; | |||||
generator_iterator(std::nullptr_t) : _Coro(nullptr) | |||||
{ | |||||
} | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : _Coro(_CoroArg) | |||||
{ | |||||
} | |||||
generator_iterator& operator++() | |||||
{ | |||||
if (_Coro.done()) | |||||
_Coro = nullptr; | |||||
else | |||||
_Coro.resume(); | |||||
return *this; | |||||
} | |||||
void operator++(int) | |||||
{ | |||||
// This postincrement operator meets the requirements of the Ranges TS | |||||
// InputIterator concept, but not those of Standard C++ InputIterator. | |||||
++* this; | |||||
} | |||||
bool operator==(generator_iterator const& right_) const | |||||
{ | |||||
return _Coro == right_._Coro; | |||||
} | |||||
bool operator!=(generator_iterator const& right_) const | |||||
{ | |||||
return !(*this == right_); | |||||
} | |||||
}; | |||||
template <typename promise_type> | |||||
struct generator_iterator<std::nullptr_t, promise_type> : public generator_iterator<void, promise_type> | |||||
{ | |||||
generator_iterator(std::nullptr_t) : generator_iterator<void, promise_type>(nullptr) | |||||
{ | |||||
} | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : generator_iterator<void, promise_type>(_CoroArg) | |||||
{ | |||||
} | |||||
}; | |||||
template <typename _Ty, typename promise_type> | |||||
struct generator_iterator : public generator_iterator<void, promise_type> | |||||
{ | |||||
using value_type = _Ty; | |||||
using reference = _Ty const&; | |||||
using pointer = _Ty const*; | |||||
generator_iterator(std::nullptr_t) : generator_iterator<void, promise_type>(nullptr) | |||||
{ | |||||
} | |||||
generator_iterator(coroutine_handle<promise_type> _CoroArg) : generator_iterator<void, promise_type>(_CoroArg) | |||||
{ | |||||
} | |||||
reference operator*() const | |||||
{ | |||||
return *this->_Coro.promise()._CurrentValue; | |||||
} | |||||
pointer operator->() const | |||||
{ | |||||
return this->_Coro.promise()._CurrentValue; | |||||
} | |||||
}; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
/** | |||||
* @brief 专用于co_yield函数。 | |||||
*/ | |||||
template <typename _Ty, typename _Alloc> | |||||
struct generator_t | |||||
{ | |||||
using value_type = _Ty; | |||||
using state_type = state_generator_t; | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
struct promise_type | |||||
{ | |||||
using value_type = _Ty; | |||||
using state_type = state_generator_t; | |||||
using future_type = generator_t<value_type>; | |||||
_Ty const* _CurrentValue; | |||||
promise_type() | |||||
{ | |||||
get_state()->set_initial_suspend(coroutine_handle<promise_type>::from_promise(*this)); | |||||
} | |||||
promise_type(promise_type&& _Right) noexcept = default; | |||||
promise_type& operator = (promise_type&& _Right) noexcept = default; | |||||
promise_type(const promise_type&) = default; | |||||
promise_type& operator = (const promise_type&) = default; | |||||
generator_t get_return_object() | |||||
{ | |||||
return generator_t{ *this }; | |||||
} | |||||
suspend_always initial_suspend() noexcept | |||||
{ | |||||
return {}; | |||||
} | |||||
suspend_always final_suspend() noexcept | |||||
{ | |||||
return {}; | |||||
} | |||||
suspend_always yield_value(_Ty const& _Value) noexcept | |||||
{ | |||||
_CurrentValue = std::addressof(_Value); | |||||
return {}; | |||||
} | |||||
//template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>> | |||||
void return_value(_Ty const& _Value) noexcept | |||||
{ | |||||
_CurrentValue = std::addressof(_Value); | |||||
} | |||||
//template<class = std::enable_if_t<std::is_same_v<_Ty, void>, _Ty>> | |||||
void return_value() noexcept | |||||
{ | |||||
_CurrentValue = nullptr; | |||||
} | |||||
void set_exception(std::exception_ptr e) | |||||
{ | |||||
(void)e; | |||||
//ref_state()->set_exception(std::move(e)); | |||||
std::terminate(); | |||||
} | |||||
#if defined(__cpp_impl_coroutine) || defined(__clang__) || defined(__GNUC__) | |||||
void unhandled_exception() | |||||
{ | |||||
//this->ref_state()->set_exception(std::current_exception()); | |||||
std::terminate(); | |||||
} | |||||
#endif | |||||
template <typename _Uty> | |||||
_Uty&& await_transform(_Uty&& _Whatever) noexcept | |||||
{ | |||||
static_assert(std::is_same_v<_Uty, void>, | |||||
"co_await is not supported in coroutines of type std::experiemental::generator_t"); | |||||
return std::forward<_Uty>(_Whatever); | |||||
} | |||||
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) | |||||
char* ptr = reinterpret_cast<char*>(this) - _State_size; | |||||
return reinterpret_cast<state_type*>(ptr); | |||||
#else | |||||
#error "Unknown compiler" | |||||
#endif | |||||
#else | |||||
return _state.get(); | |||||
#endif | |||||
} | |||||
//counted_ptr<state_type> ref_state() noexcept | |||||
//{ | |||||
// return { get_state() }; | |||||
//} | |||||
state_type* ref_state() noexcept | |||||
{ | |||||
return get_state(); | |||||
} | |||||
using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc<char>; | |||||
static_assert(std::is_same_v<char*, typename std::allocator_traits<_Alloc_char>::pointer>, | |||||
"generator_t does not support allocators with fancy pointer types"); | |||||
static_assert(std::allocator_traits<_Alloc_char>::is_always_equal::value, | |||||
"generator_t only supports stateless allocators"); | |||||
void* 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)); | |||||
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 = state_type::_Construct(ptr); | |||||
st->lock(); | |||||
} | |||||
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<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; | |||||
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 | |||||
}; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
using iterator = generator_iterator<_Ty, promise_type>; | |||||
iterator begin() | |||||
{ | |||||
if (_Coro) | |||||
{ | |||||
_Coro.resume(); | |||||
if (_Coro.done()) | |||||
return{ nullptr }; | |||||
} | |||||
return { _Coro }; | |||||
} | |||||
iterator end() | |||||
{ | |||||
return{ nullptr }; | |||||
} | |||||
explicit generator_t(promise_type& _Prom) | |||||
: _Coro(coroutine_handle<promise_type>::from_promise(_Prom)) | |||||
{ | |||||
} | |||||
generator_t() = default; | |||||
generator_t(generator_t const&) = delete; | |||||
generator_t& operator=(generator_t const&) = delete; | |||||
generator_t(generator_t&& right_) noexcept | |||||
: _Coro(right_._Coro) | |||||
{ | |||||
right_._Coro = nullptr; | |||||
} | |||||
generator_t& operator=(generator_t&& right_) noexcept | |||||
{ | |||||
if (this != std::addressof(right_)) { | |||||
_Coro = right_._Coro; | |||||
right_._Coro = nullptr; | |||||
} | |||||
return *this; | |||||
} | |||||
~generator_t() | |||||
{ | |||||
if (_Coro) { | |||||
_Coro.destroy(); | |||||
} | |||||
} | |||||
state_type* detach_state() | |||||
{ | |||||
auto t = _Coro; | |||||
_Coro = nullptr; | |||||
return t.promise().get_state(); | |||||
} | |||||
private: | |||||
coroutine_handle<promise_type> _Coro = nullptr; | |||||
}; | |||||
} // namespace librf | |||||
#pragma pop_macro("new") | |||||
#pragma pack(pop) |
#pragma once | |||||
#pragma once | |||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
template<class _Node, class _Nodeptr = _Node*, class _Sty = uint32_t> | template<class _Node, class _Nodeptr = _Node*, class _Sty = uint32_t> | ||||
struct intrusive_link_queue | struct intrusive_link_queue |
#pragma once | |||||
#pragma once | |||||
#ifndef _offset_of | #ifndef _offset_of | ||||
#define _offset_of(c, m) reinterpret_cast<size_t>(&static_cast<c *>(0)->m) | #define _offset_of(c, m) reinterpret_cast<size_t>(&static_cast<c *>(0)->m) | ||||
#define co_return_void co_return nullptr | #define co_return_void co_return nullptr | ||||
#if !defined(_DISABLE_RESUMEF_GO_MACRO) | #if !defined(_DISABLE_RESUMEF_GO_MACRO) | ||||
#define go (*::resumef::this_scheduler()) + | |||||
#define GO (*::resumef::this_scheduler()) + [=]()mutable->resumef::future_t<> | |||||
#define go (*::librf::this_scheduler()) + | |||||
#define GO (*::librf::this_scheduler()) + [=]()mutable->librf::future_t<> | |||||
#endif | #endif | ||||
#define current_scheduler() (co_await ::resumef::get_current_scheduler()) | |||||
#define root_state() (co_await ::resumef::get_root_state()) | |||||
#define current_task() (co_await ::resumef::get_current_task()) | |||||
#define current_scheduler() (co_await ::librf::get_current_scheduler()) | |||||
#define root_state() (co_await ::librf::get_root_state()) | |||||
#define current_task() (co_await ::librf::get_current_task()) | |||||
#if defined(__clang__) || defined(__GNUC__) | #if defined(__clang__) || defined(__GNUC__) | ||||
#ifndef likely | #ifndef likely |
#pragma once | |||||
#include "mutex_v2.h" | |||||
#include "mutex_v2.inl" | |||||
#pragma once | |||||
#include "mutex_v2.h" | |||||
#include "mutex_v2.inl" |
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | #ifndef DOXYGEN_SKIP_PROPERTY | ||||
namespace detail | namespace detail |
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
namespace detail | namespace detail | ||||
{ | { |
#undef new | #undef new | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | #ifndef DOXYGEN_SKIP_PROPERTY | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
/* | /* | ||||
Note: the awaiter object is part of coroutine state (as a temporary whose lifetime crosses a suspension point) | Note: the awaiter object is part of coroutine state (as a temporary whose lifetime crosses a suspension point) |
| | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
/* | /* |
#pragma once | |||||
namespace resumef | |||||
{ | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
/** | |||||
* @brief 协程任务类。 | |||||
* @details 每启动一个新的协程,则对应一个协程任务类。\n | |||||
* 一方面,task_t用于标记协程是否执行完毕;\n | |||||
* 另一方面,对于通过函数对象(functor/lambda)启动的协程,有很大概率,此协程的内部变量,依赖此函数对象的生存期。\n | |||||
* tast_t的针对函数对象的特化版本,会持有此函数对象的拷贝,从而保证协程内部变量的生存期。这便于减少外部使用协程函数对象的工作量。\n | |||||
* 如果不希望task_t持有此函数对象,则通过调用此函数对象来启动协程,即:\n | |||||
* go functor; \n | |||||
* 替换为\n | |||||
* go functor(); | |||||
*/ | |||||
struct task_t | |||||
{ | |||||
task_t() noexcept; | |||||
virtual ~task_t(); | |||||
/** | |||||
* @brief 获取stop_source,第一次获取时,会生成一个有效的stop_source。 | |||||
* @return stop_source | |||||
*/ | |||||
const stop_source & get_stop_source(); | |||||
/** | |||||
* @brief 获取一个跟stop_source绑定的,新的stop_token。 | |||||
* @return stop_token | |||||
*/ | |||||
stop_token get_stop_token() | |||||
{ | |||||
return get_stop_source().get_token(); | |||||
} | |||||
/** | |||||
* @brief 要求停止协程。 | |||||
* @return bool 返回操作成功与否。 | |||||
*/ | |||||
bool request_stop() | |||||
{ | |||||
return get_stop_source().request_stop(); | |||||
} | |||||
/** | |||||
* @brief 要求停止协程。 | |||||
* @return bool 返回操作成功与否。 | |||||
*/ | |||||
bool request_stop_if_possible() const | |||||
{ | |||||
if (_stop.stop_possible()) | |||||
return _stop.request_stop(); | |||||
return false; | |||||
} | |||||
protected: | |||||
friend scheduler_t; | |||||
counted_ptr<state_base_t> _state; | |||||
stop_source _stop; | |||||
}; | |||||
#endif | |||||
//---------------------------------------------------------------------------------------------- | |||||
template<class _Ty, class = std::void_t<>> | |||||
struct task_impl_t; | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
template<class _Ty> | |||||
struct task_impl_t<_Ty, std::void_t<traits::is_future<std::remove_reference_t<_Ty>>>> : public task_t | |||||
{ | |||||
using future_type = std::remove_reference_t<_Ty>; | |||||
using value_type = typename future_type::value_type; | |||||
using state_type = state_t<value_type>; | |||||
task_impl_t() noexcept = default; | |||||
task_impl_t(future_type& f) | |||||
{ | |||||
initialize(f); | |||||
} | |||||
protected: | |||||
void initialize(future_type& f) | |||||
{ | |||||
_state = f._state.get(); | |||||
} | |||||
}; | |||||
template<class _Ty> | |||||
struct task_impl_t<generator_t<_Ty>> : public task_t | |||||
{ | |||||
using value_type = _Ty; | |||||
using future_type = generator_t<value_type>; | |||||
using state_type = state_generator_t; | |||||
task_impl_t() noexcept = default; | |||||
task_impl_t(future_type& f) | |||||
{ | |||||
initialize(f); | |||||
} | |||||
protected: | |||||
void initialize(future_type& f) | |||||
{ | |||||
_state = f.detach_state(); | |||||
} | |||||
}; | |||||
//---------------------------------------------------------------------------------------------- | |||||
//ctx_task_t接受的是一个'函数对象' | |||||
//这个'函数对象'被调用后,返回generator<_Ty>/future_t<_Ty>类型 | |||||
//然后'函数对象'作为异步执行的上下文状态保存起来 | |||||
template<class _Ctx> | |||||
struct task_ctx_impl_t : public task_impl_t<remove_cvref_t<decltype(std::declval<_Ctx>()())>> | |||||
{ | |||||
using context_type = _Ctx; | |||||
context_type _context; | |||||
task_ctx_impl_t(context_type ctx) | |||||
: _context(std::move(ctx)) | |||||
{ | |||||
decltype(auto) f = _context(); | |||||
this->initialize(f); | |||||
} | |||||
}; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
} | |||||
#pragma once | |||||
namespace librf | |||||
{ | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
/** | |||||
* @brief 协程任务类。 | |||||
* @details 每启动一个新的协程,则对应一个协程任务类。\n | |||||
* 一方面,task_t用于标记协程是否执行完毕;\n | |||||
* 另一方面,对于通过函数对象(functor/lambda)启动的协程,有很大概率,此协程的内部变量,依赖此函数对象的生存期。\n | |||||
* tast_t的针对函数对象的特化版本,会持有此函数对象的拷贝,从而保证协程内部变量的生存期。这便于减少外部使用协程函数对象的工作量。\n | |||||
* 如果不希望task_t持有此函数对象,则通过调用此函数对象来启动协程,即:\n | |||||
* go functor; \n | |||||
* 替换为\n | |||||
* go functor(); | |||||
*/ | |||||
struct task_t | |||||
{ | |||||
task_t() noexcept; | |||||
virtual ~task_t(); | |||||
/** | |||||
* @brief 获取stop_source,第一次获取时,会生成一个有效的stop_source。 | |||||
* @return stop_source | |||||
*/ | |||||
const stop_source & get_stop_source(); | |||||
/** | |||||
* @brief 获取一个跟stop_source绑定的,新的stop_token。 | |||||
* @return stop_token | |||||
*/ | |||||
stop_token get_stop_token() | |||||
{ | |||||
return get_stop_source().get_token(); | |||||
} | |||||
/** | |||||
* @brief 要求停止协程。 | |||||
* @return bool 返回操作成功与否。 | |||||
*/ | |||||
bool request_stop() | |||||
{ | |||||
return get_stop_source().request_stop(); | |||||
} | |||||
/** | |||||
* @brief 要求停止协程。 | |||||
* @return bool 返回操作成功与否。 | |||||
*/ | |||||
bool request_stop_if_possible() const | |||||
{ | |||||
if (_stop.stop_possible()) | |||||
return _stop.request_stop(); | |||||
return false; | |||||
} | |||||
protected: | |||||
friend scheduler_t; | |||||
counted_ptr<state_base_t> _state; | |||||
stop_source _stop; | |||||
}; | |||||
#endif | |||||
//---------------------------------------------------------------------------------------------- | |||||
template<class _Ty, class = std::void_t<>> | |||||
struct task_impl_t; | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
template<class _Ty> | |||||
struct task_impl_t<_Ty, std::void_t<traits::is_future<std::remove_reference_t<_Ty>>>> : public task_t | |||||
{ | |||||
using future_type = std::remove_reference_t<_Ty>; | |||||
using value_type = typename future_type::value_type; | |||||
using state_type = state_t<value_type>; | |||||
task_impl_t() noexcept = default; | |||||
task_impl_t(future_type& f) | |||||
{ | |||||
initialize(f); | |||||
} | |||||
protected: | |||||
void initialize(future_type& f) | |||||
{ | |||||
_state = f._state.get(); | |||||
} | |||||
}; | |||||
template<class _Ty> | |||||
struct task_impl_t<generator_t<_Ty>> : public task_t | |||||
{ | |||||
using value_type = _Ty; | |||||
using future_type = generator_t<value_type>; | |||||
using state_type = state_generator_t; | |||||
task_impl_t() noexcept = default; | |||||
task_impl_t(future_type& f) | |||||
{ | |||||
initialize(f); | |||||
} | |||||
protected: | |||||
void initialize(future_type& f) | |||||
{ | |||||
_state = f.detach_state(); | |||||
} | |||||
}; | |||||
//---------------------------------------------------------------------------------------------- | |||||
//ctx_task_t接受的是一个'函数对象' | |||||
//这个'函数对象'被调用后,返回generator<_Ty>/future_t<_Ty>类型 | |||||
//然后'函数对象'作为异步执行的上下文状态保存起来 | |||||
template<class _Ctx> | |||||
struct task_ctx_impl_t : public task_impl_t<remove_cvref_t<decltype(std::declval<_Ctx>()())>> | |||||
{ | |||||
using context_type = _Ctx; | |||||
context_type _context; | |||||
task_ctx_impl_t(context_type ctx) | |||||
: _context(std::move(ctx)) | |||||
{ | |||||
decltype(auto) f = _context(); | |||||
this->initialize(f); | |||||
} | |||||
}; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
} |
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
//使用自旋锁完成的线程安全的环形队列。 | //使用自旋锁完成的线程安全的环形队列。 | ||||
//支持多个线程同时push和pop。 | //支持多个线程同时push和pop。 |
#pragma once | |||||
namespace resumef | |||||
{ | |||||
/** | |||||
* @brief 协程调度器。 | |||||
* @details librf的设计原则之一,就是要将协程绑定在固定的调度器里执行。 | |||||
* 通过控制调度器运行的线程和时机,从而控制协程所在的线程和运行时机。 | |||||
*/ | |||||
struct scheduler_t : public std::enable_shared_from_this<scheduler_t> | |||||
{ | |||||
private: | |||||
using state_sptr = counted_ptr<state_base_t>; | |||||
using state_vector = std::vector<state_sptr>; | |||||
using lock_type = spinlock; | |||||
using task_dictionary_type = std::unordered_map<state_base_t*, std::unique_ptr<task_t>>; | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
mutable spinlock _lock_running; | |||||
#endif | |||||
state_vector _runing_states; | |||||
state_vector _cached_states; | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
mutable spinlock _lock_ready; | |||||
#endif | |||||
task_dictionary_type _ready_task; | |||||
timer_mgr_ptr _timer; | |||||
task_t* new_task(task_t* task); | |||||
//void cancel_all_task_(); | |||||
public: | |||||
/** | |||||
* @brief 运行一批准备妥当的协程。 | |||||
* @details 这是协程调度器提供的主要接口。同一个调度器非线程安全,不可重入。\n | |||||
* 调用者要保证此函数始终在同一个线程里调用。 | |||||
*/ | |||||
bool run_one_batch(); | |||||
/** | |||||
* @brief 循环运行所有的协程,直到所有协程都运行完成。 | |||||
* @details 通常用于测试代码。 | |||||
*/ | |||||
void run_until_notask(); | |||||
//void break_all(); | |||||
/** | |||||
* @brief 将一个协程加入到调度器里开始运行。 | |||||
* @details 推荐使用go或者GO这两个宏来启动协程。\n | |||||
* go用于启动future_t<>/generator_t<>;\n | |||||
* GO用于启动一个所有变量按值捕获的lambda。 | |||||
* @param coro 协程对象。future_t<>,generator_t<>,或者一个调用后返回future_t<>/generator_t<>的函数对象。 | |||||
* @retval task_t* 返回代表一个新协程的协程任务类。\n | |||||
*/ | |||||
template<class _Ty> | |||||
requires(traits::is_callable_v<_Ty> || traits::is_future_v<_Ty> || traits::is_generator_v<_Ty>) | |||||
task_t* operator + (_Ty&& coro) | |||||
{ | |||||
if constexpr (traits::is_callable_v<_Ty>) | |||||
return new_task(new task_ctx_impl_t<_Ty>(coro)); | |||||
else | |||||
return new_task(new task_impl_t<_Ty>(coro)); | |||||
} | |||||
/** | |||||
* @brief 判断所有协程是否运行完毕。 | |||||
* @retval bool 以下条件全部满足,返回true:\n | |||||
* 1、所有协程运行完毕\n | |||||
* 2、没有正在准备执行的state\n | |||||
* 3、定时管理器的empty()返回true。 | |||||
*/ | |||||
bool empty() const | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock, spinlock> __guard(_lock_ready, _lock_running); | |||||
#endif | |||||
return _ready_task.empty() && _runing_states.empty() && _timer->empty(); | |||||
} | |||||
/** | |||||
* @brief 获得定时管理器。 | |||||
*/ | |||||
timer_manager* timer() const noexcept | |||||
{ | |||||
return _timer.get(); | |||||
} | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
void add_generator(state_base_t* sptr); | |||||
void del_final(state_base_t* sptr); | |||||
std::unique_ptr<task_t> del_switch(state_base_t* sptr); | |||||
void add_switch(std::unique_ptr<task_t> task); | |||||
task_t* find_task(state_base_t* sptr) const noexcept; | |||||
friend struct local_scheduler_t; | |||||
protected: | |||||
scheduler_t(); | |||||
public: | |||||
~scheduler_t(); | |||||
scheduler_t(scheduler_t&& right_) = delete; | |||||
scheduler_t& operator = (scheduler_t&& right_) = delete; | |||||
scheduler_t(const scheduler_t&) = delete; | |||||
scheduler_t& operator = (const scheduler_t&) = delete; | |||||
static scheduler_t g_scheduler; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
}; | |||||
/** | |||||
* @brief 创建一个线程相关的调度器。 | |||||
* @details 如果线程之前已经创建了调度器,则第一个调度器会跟线程绑定,此后local_scheduler_t不会创建更多的调度器。\n | |||||
* 否则,local_scheduler_t会创建一个调度器,并绑定到创建local_scheduler_t的线程上。\n | |||||
* 如果local_scheduler_t成功创建了一个调度器,则在local_scheduler_t生命周期结束后,会销毁创建的调度器,并解绑线程。\n | |||||
* 典型用法,是在非主线程里,开始运行协程之前,申明一个local_scheduler_t的局部变量。 | |||||
*/ | |||||
struct local_scheduler_t | |||||
{ | |||||
/** | |||||
* @brief 尽可能的创建一个线程相关的调度器。 | |||||
*/ | |||||
local_scheduler_t(); | |||||
/** | |||||
* @brief 将指定的调度器绑定到当前线程上。 | |||||
*/ | |||||
local_scheduler_t(scheduler_t & sch) noexcept; | |||||
/** | |||||
* @brief 如果当前线程绑定的调度器由local_scheduler_t所创建,则会销毁调度器,并解绑线程。 | |||||
*/ | |||||
~local_scheduler_t(); | |||||
local_scheduler_t(local_scheduler_t&& right_) = delete; | |||||
local_scheduler_t& operator = (local_scheduler_t&& right_) = delete; | |||||
local_scheduler_t(const local_scheduler_t&) = delete; | |||||
local_scheduler_t& operator = (const local_scheduler_t&) = delete; | |||||
private: | |||||
scheduler_t* _scheduler_ptr; | |||||
}; | |||||
inline void scheduler_t::add_generator(state_base_t* sptr) | |||||
{ | |||||
assert(sptr != nullptr); | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_running); | |||||
#endif | |||||
_runing_states.emplace_back(sptr); | |||||
} | |||||
inline void scheduler_t::del_final(state_base_t* sptr) | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
this->_ready_task.erase(sptr); | |||||
} | |||||
inline void scheduler_t::add_switch(std::unique_ptr<task_t> task) | |||||
{ | |||||
state_base_t* sptr = task->_state.get(); | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
this->_ready_task.emplace(sptr, std::move(task)); | |||||
} | |||||
inline task_t* scheduler_t::find_task(state_base_t* sptr) const noexcept | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
auto iter = this->_ready_task.find(sptr); | |||||
if (iter != this->_ready_task.end()) | |||||
return iter->second.get(); | |||||
return nullptr; | |||||
} | |||||
} | |||||
#pragma once | |||||
namespace librf | |||||
{ | |||||
/** | |||||
* @brief 协程调度器。 | |||||
* @details librf的设计原则之一,就是要将协程绑定在固定的调度器里执行。 | |||||
* 通过控制调度器运行的线程和时机,从而控制协程所在的线程和运行时机。 | |||||
*/ | |||||
struct scheduler_t : public std::enable_shared_from_this<scheduler_t> | |||||
{ | |||||
private: | |||||
using state_sptr = counted_ptr<state_base_t>; | |||||
using state_vector = std::vector<state_sptr>; | |||||
using lock_type = spinlock; | |||||
using task_dictionary_type = std::unordered_map<state_base_t*, std::unique_ptr<task_t>>; | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
mutable spinlock _lock_running; | |||||
#endif | |||||
state_vector _runing_states; | |||||
state_vector _cached_states; | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
mutable spinlock _lock_ready; | |||||
#endif | |||||
task_dictionary_type _ready_task; | |||||
timer_mgr_ptr _timer; | |||||
task_t* new_task(task_t* task); | |||||
//void cancel_all_task_(); | |||||
public: | |||||
/** | |||||
* @brief 运行一批准备妥当的协程。 | |||||
* @details 这是协程调度器提供的主要接口。同一个调度器非线程安全,不可重入。\n | |||||
* 调用者要保证此函数始终在同一个线程里调用。 | |||||
*/ | |||||
bool run_one_batch(); | |||||
/** | |||||
* @brief 循环运行所有的协程,直到所有协程都运行完成。 | |||||
* @details 通常用于测试代码。 | |||||
*/ | |||||
void run_until_notask(); | |||||
//void break_all(); | |||||
/** | |||||
* @brief 将一个协程加入到调度器里开始运行。 | |||||
* @details 推荐使用go或者GO这两个宏来启动协程。\n | |||||
* go用于启动future_t<>/generator_t<>;\n | |||||
* GO用于启动一个所有变量按值捕获的lambda。 | |||||
* @param coro 协程对象。future_t<>,generator_t<>,或者一个调用后返回future_t<>/generator_t<>的函数对象。 | |||||
* @retval task_t* 返回代表一个新协程的协程任务类。\n | |||||
*/ | |||||
template<class _Ty> | |||||
requires(traits::is_callable_v<_Ty> || traits::is_future_v<_Ty> || traits::is_generator_v<_Ty>) | |||||
task_t* operator + (_Ty&& coro) | |||||
{ | |||||
if constexpr (traits::is_callable_v<_Ty>) | |||||
return new_task(new task_ctx_impl_t<_Ty>(coro)); | |||||
else | |||||
return new_task(new task_impl_t<_Ty>(coro)); | |||||
} | |||||
/** | |||||
* @brief 判断所有协程是否运行完毕。 | |||||
* @retval bool 以下条件全部满足,返回true:\n | |||||
* 1、所有协程运行完毕\n | |||||
* 2、没有正在准备执行的state\n | |||||
* 3、定时管理器的empty()返回true。 | |||||
*/ | |||||
bool empty() const | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock, spinlock> __guard(_lock_ready, _lock_running); | |||||
#endif | |||||
return _ready_task.empty() && _runing_states.empty() && _timer->empty(); | |||||
} | |||||
/** | |||||
* @brief 获得定时管理器。 | |||||
*/ | |||||
timer_manager* timer() const noexcept | |||||
{ | |||||
return _timer.get(); | |||||
} | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
void add_generator(state_base_t* sptr); | |||||
void del_final(state_base_t* sptr); | |||||
std::unique_ptr<task_t> del_switch(state_base_t* sptr); | |||||
void add_switch(std::unique_ptr<task_t> task); | |||||
task_t* find_task(state_base_t* sptr) const noexcept; | |||||
friend struct local_scheduler_t; | |||||
protected: | |||||
scheduler_t(); | |||||
public: | |||||
~scheduler_t(); | |||||
scheduler_t(scheduler_t&& right_) = delete; | |||||
scheduler_t& operator = (scheduler_t&& right_) = delete; | |||||
scheduler_t(const scheduler_t&) = delete; | |||||
scheduler_t& operator = (const scheduler_t&) = delete; | |||||
static scheduler_t g_scheduler; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
}; | |||||
/** | |||||
* @brief 创建一个线程相关的调度器。 | |||||
* @details 如果线程之前已经创建了调度器,则第一个调度器会跟线程绑定,此后local_scheduler_t不会创建更多的调度器。\n | |||||
* 否则,local_scheduler_t会创建一个调度器,并绑定到创建local_scheduler_t的线程上。\n | |||||
* 如果local_scheduler_t成功创建了一个调度器,则在local_scheduler_t生命周期结束后,会销毁创建的调度器,并解绑线程。\n | |||||
* 典型用法,是在非主线程里,开始运行协程之前,申明一个local_scheduler_t的局部变量。 | |||||
*/ | |||||
struct local_scheduler_t | |||||
{ | |||||
/** | |||||
* @brief 尽可能的创建一个线程相关的调度器。 | |||||
*/ | |||||
local_scheduler_t(); | |||||
/** | |||||
* @brief 将指定的调度器绑定到当前线程上。 | |||||
*/ | |||||
local_scheduler_t(scheduler_t & sch) noexcept; | |||||
/** | |||||
* @brief 如果当前线程绑定的调度器由local_scheduler_t所创建,则会销毁调度器,并解绑线程。 | |||||
*/ | |||||
~local_scheduler_t(); | |||||
local_scheduler_t(local_scheduler_t&& right_) = delete; | |||||
local_scheduler_t& operator = (local_scheduler_t&& right_) = delete; | |||||
local_scheduler_t(const local_scheduler_t&) = delete; | |||||
local_scheduler_t& operator = (const local_scheduler_t&) = delete; | |||||
private: | |||||
scheduler_t* _scheduler_ptr; | |||||
}; | |||||
inline void scheduler_t::add_generator(state_base_t* sptr) | |||||
{ | |||||
assert(sptr != nullptr); | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_running); | |||||
#endif | |||||
_runing_states.emplace_back(sptr); | |||||
} | |||||
inline void scheduler_t::del_final(state_base_t* sptr) | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
this->_ready_task.erase(sptr); | |||||
} | |||||
inline void scheduler_t::add_switch(std::unique_ptr<task_t> task) | |||||
{ | |||||
state_base_t* sptr = task->_state.get(); | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
this->_ready_task.emplace(sptr, std::move(task)); | |||||
} | |||||
inline task_t* scheduler_t::find_task(state_base_t* sptr) const noexcept | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
auto iter = this->_ready_task.find(sptr); | |||||
if (iter != this->_ready_task.end()) | |||||
return iter->second.get(); | |||||
return nullptr; | |||||
} | |||||
} |
//协程的定时器 | |||||
//如果定时器被取消了,则会抛 timer_canceled_exception 异常 | |||||
//不使用co_await而单独sleep_for/sleep_until,是错误的用法,并不能达到等待的目的。而仅仅是添加了一个无效的定时器,造成无必要的内存使用 | |||||
// | |||||
#pragma once | |||||
namespace resumef | |||||
{ | |||||
/** | |||||
* @brief 协程专用的睡眠功能。 | |||||
* @details 不能使用操作系统提供的sleep功能,因为会阻塞协程。\n | |||||
* 此函数不会阻塞线程,仅仅将当前协程挂起,直到指定时刻。\n | |||||
* 其精度,取决与调度器循环的精度,以及std::chrono::system_clock的精度。简而言之,可以认为只要循环够快,精度到100ns。 | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。 | |||||
*/ | |||||
future_t<> sleep_until_(std::chrono::system_clock::time_point tp_, scheduler_t& scheduler_); | |||||
/** | |||||
* @brief 协程专用的睡眠功能。 | |||||
* @see 参考sleep_until_()函数\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。 | |||||
*/ | |||||
inline future_t<> sleep_for_(std::chrono::system_clock::duration dt_, scheduler_t& scheduler_) | |||||
{ | |||||
return sleep_until_(std::chrono::system_clock::now() + dt_, scheduler_); | |||||
} | |||||
/** | |||||
* @brief 协程专用的睡眠功能。 | |||||
* @see 参考sleep_until_()函数\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。 | |||||
*/ | |||||
template<class _Rep, class _Period> | |||||
inline future_t<> sleep_for(std::chrono::duration<_Rep, _Period> dt_, scheduler_t& scheduler_) | |||||
{ | |||||
return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), scheduler_); | |||||
} | |||||
/** | |||||
* @brief 协程专用的睡眠功能。 | |||||
* @see 参考sleep_until_()函数\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。 | |||||
*/ | |||||
template<class _Clock, class _Duration = typename _Clock::duration> | |||||
inline future_t<> sleep_until(std::chrono::time_point<_Clock, _Duration> tp_, scheduler_t& scheduler_) | |||||
{ | |||||
return sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), scheduler_); | |||||
} | |||||
/** | |||||
* @brief 协程专用的睡眠功能。 | |||||
* @see 参考sleep_until_()函数\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。 | |||||
*/ | |||||
template<class _Rep, class _Period> | |||||
inline future_t<> sleep_for(std::chrono::duration<_Rep, _Period> dt_) | |||||
{ | |||||
scheduler_t* sch = current_scheduler(); | |||||
co_await sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), *sch); | |||||
} | |||||
/** | |||||
* @brief 协程专用的睡眠功能。 | |||||
* @see 参考sleep_until_()函数\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。 | |||||
*/ | |||||
template<class _Clock, class _Duration> | |||||
inline future_t<> sleep_until(std::chrono::time_point<_Clock, _Duration> tp_) | |||||
{ | |||||
scheduler_t* sch = current_scheduler(); | |||||
co_await sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), *sch); | |||||
} | |||||
/** | |||||
* @brief 协程专用的睡眠功能。 | |||||
* @see 等同调用sleep_for(dt)\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。 | |||||
*/ | |||||
template <class Rep, class Period> | |||||
inline future_t<> operator co_await(std::chrono::duration<Rep, Period> dt_) | |||||
{ | |||||
scheduler_t* sch = current_scheduler(); | |||||
co_await sleep_for(dt_, *sch); | |||||
} | |||||
锘�//鍗忕▼鐨勫畾鏃跺櫒 | |||||
//濡傛灉瀹氭椂鍣ㄨ�鍙栨秷浜嗭紝鍒欎細鎶� timer_canceled_exception 寮傚父 | |||||
//涓嶄娇鐢╟o_await鑰屽崟鐙瑂leep_for/sleep_until锛屾槸閿欒�鐨勭敤娉曪紝骞朵笉鑳借揪鍒扮瓑寰呯殑鐩�殑銆傝€屼粎浠呮槸娣诲姞浜嗕竴涓�棤鏁堢殑瀹氭椂鍣�紝閫犳垚鏃犲繀瑕佺殑鍐呭瓨浣跨敤 | |||||
// | |||||
#pragma once | |||||
namespace librf | |||||
{ | |||||
/** | |||||
* @brief 鍗忕▼涓撶敤鐨勭潯鐪犲姛鑳姐€� | |||||
* @details 涓嶈兘浣跨敤鎿嶄綔绯荤粺鎻愪緵鐨剆leep鍔熻兘锛屽洜涓轰細闃诲�鍗忕▼銆俓n | |||||
* 姝ゅ嚱鏁颁笉浼氶樆濉炵嚎绋嬶紝浠呬粎灏嗗綋鍓嶅崗绋嬫寕璧凤紝鐩村埌鎸囧畾鏃跺埢銆俓n | |||||
* 鍏剁簿搴︼紝鍙栧喅涓庤皟搴﹀櫒寰�幆鐨勭簿搴︼紝浠ュ強std::chrono::system_clock鐨勭簿搴︺€傜畝鑰岃█涔嬶紝鍙�互璁や负鍙��寰�幆澶熷揩锛岀簿搴﹀埌100ns銆� | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 濡傛灉瀹氭椂鍣ㄨ�鍙栨秷锛屽垯鎶涙�寮傚父銆� | |||||
*/ | |||||
future_t<> sleep_until_(std::chrono::system_clock::time_point tp_, scheduler_t& scheduler_); | |||||
/** | |||||
* @brief 鍗忕▼涓撶敤鐨勭潯鐪犲姛鑳姐€� | |||||
* @see 鍙傝€僺leep_until_()鍑芥暟\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 濡傛灉瀹氭椂鍣ㄨ�鍙栨秷锛屽垯鎶涙�寮傚父銆� | |||||
*/ | |||||
inline future_t<> sleep_for_(std::chrono::system_clock::duration dt_, scheduler_t& scheduler_) | |||||
{ | |||||
return sleep_until_(std::chrono::system_clock::now() + dt_, scheduler_); | |||||
} | |||||
/** | |||||
* @brief 鍗忕▼涓撶敤鐨勭潯鐪犲姛鑳姐€� | |||||
* @see 鍙傝€僺leep_until_()鍑芥暟\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 濡傛灉瀹氭椂鍣ㄨ�鍙栨秷锛屽垯鎶涙�寮傚父銆� | |||||
*/ | |||||
template<class _Rep, class _Period> | |||||
inline future_t<> sleep_for(std::chrono::duration<_Rep, _Period> dt_, scheduler_t& scheduler_) | |||||
{ | |||||
return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), scheduler_); | |||||
} | |||||
/** | |||||
* @brief 鍗忕▼涓撶敤鐨勭潯鐪犲姛鑳姐€� | |||||
* @see 鍙傝€僺leep_until_()鍑芥暟\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 濡傛灉瀹氭椂鍣ㄨ�鍙栨秷锛屽垯鎶涙�寮傚父銆� | |||||
*/ | |||||
template<class _Clock, class _Duration = typename _Clock::duration> | |||||
inline future_t<> sleep_until(std::chrono::time_point<_Clock, _Duration> tp_, scheduler_t& scheduler_) | |||||
{ | |||||
return sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), scheduler_); | |||||
} | |||||
/** | |||||
* @brief 鍗忕▼涓撶敤鐨勭潯鐪犲姛鑳姐€� | |||||
* @see 鍙傝€僺leep_until_()鍑芥暟\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 濡傛灉瀹氭椂鍣ㄨ�鍙栨秷锛屽垯鎶涙�寮傚父銆� | |||||
*/ | |||||
template<class _Rep, class _Period> | |||||
inline future_t<> sleep_for(std::chrono::duration<_Rep, _Period> dt_) | |||||
{ | |||||
scheduler_t* sch = current_scheduler(); | |||||
co_await sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), *sch); | |||||
} | |||||
/** | |||||
* @brief 鍗忕▼涓撶敤鐨勭潯鐪犲姛鑳姐€� | |||||
* @see 鍙傝€僺leep_until_()鍑芥暟\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 濡傛灉瀹氭椂鍣ㄨ�鍙栨秷锛屽垯鎶涙�寮傚父銆� | |||||
*/ | |||||
template<class _Clock, class _Duration> | |||||
inline future_t<> sleep_until(std::chrono::time_point<_Clock, _Duration> tp_) | |||||
{ | |||||
scheduler_t* sch = current_scheduler(); | |||||
co_await sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), *sch); | |||||
} | |||||
/** | |||||
* @brief 鍗忕▼涓撶敤鐨勭潯鐪犲姛鑳姐€� | |||||
* @see 绛夊悓璋冪敤sleep_for(dt)\n | |||||
* @return [co_await] void | |||||
* @throw timer_canceled_exception 濡傛灉瀹氭椂鍣ㄨ�鍙栨秷锛屽垯鎶涙�寮傚父銆� | |||||
*/ | |||||
template <class Rep, class Period> | |||||
inline future_t<> operator co_await(std::chrono::duration<Rep, Period> dt_) | |||||
{ | |||||
scheduler_t* sch = current_scheduler(); | |||||
co_await sleep_for(dt_, *sch); | |||||
} | |||||
} | } |
//用于内部实现的循环锁 | |||||
#pragma once | |||||
namespace resumef | |||||
{ | |||||
#if defined(RESUMEF_USE_CUSTOM_SPINLOCK) | |||||
using spinlock = RESUMEF_USE_CUSTOM_SPINLOCK; | |||||
#else | |||||
/** | |||||
* @brief 一个自旋锁实现。 | |||||
*/ | |||||
struct spinlock | |||||
{ | |||||
static const size_t MAX_ACTIVE_SPIN = 4000; | |||||
static const size_t MAX_YIELD_SPIN = 8000; | |||||
static const int FREE_VALUE = 0; | |||||
static const int LOCKED_VALUE = 1; | |||||
std::atomic<int> lck; | |||||
#if _DEBUG | |||||
std::thread::id owner_thread_id; | |||||
#endif | |||||
/** | |||||
* @brief 初始为未加锁。 | |||||
*/ | |||||
spinlock() noexcept | |||||
{ | |||||
lck = FREE_VALUE; | |||||
} | |||||
/** | |||||
* @brief 获得锁。会一直阻塞线程直到获得锁。 | |||||
*/ | |||||
void lock() noexcept | |||||
{ | |||||
int val = FREE_VALUE; | |||||
if (!lck.compare_exchange_weak(val, LOCKED_VALUE, std::memory_order_acq_rel)) | |||||
{ | |||||
#if _DEBUG | |||||
//诊断错误的用法:进行了递归锁调用 | |||||
assert(owner_thread_id != std::this_thread::get_id()); | |||||
#endif | |||||
size_t spinCount = 0; | |||||
auto dt = std::chrono::milliseconds{ 1 }; | |||||
do | |||||
{ | |||||
while (lck.load(std::memory_order_relaxed) != FREE_VALUE) | |||||
{ | |||||
if (spinCount < MAX_ACTIVE_SPIN) | |||||
{ | |||||
++spinCount; | |||||
} | |||||
else if (spinCount < MAX_YIELD_SPIN) | |||||
{ | |||||
++spinCount; | |||||
std::this_thread::yield(); | |||||
} | |||||
else | |||||
{ | |||||
std::this_thread::sleep_for(dt); | |||||
dt = (std::min)(std::chrono::milliseconds{ 128 }, dt * 2); | |||||
} | |||||
} | |||||
val = FREE_VALUE; | |||||
} while (!lck.compare_exchange_weak(val, LOCKED_VALUE, std::memory_order_acq_rel)); | |||||
} | |||||
#if _DEBUG | |||||
owner_thread_id = std::this_thread::get_id(); | |||||
#endif | |||||
} | |||||
/** | |||||
* @brief 尝试获得锁一次。 | |||||
*/ | |||||
bool try_lock() noexcept | |||||
{ | |||||
int val = FREE_VALUE; | |||||
bool ret = lck.compare_exchange_strong(val, LOCKED_VALUE, std::memory_order_acq_rel); | |||||
#if _DEBUG | |||||
if (ret) owner_thread_id = std::this_thread::get_id(); | |||||
#endif | |||||
return ret; | |||||
} | |||||
/** | |||||
* @brief 释放锁。 | |||||
*/ | |||||
void unlock() noexcept | |||||
{ | |||||
#if _DEBUG | |||||
owner_thread_id = std::thread::id(); | |||||
#endif | |||||
lck.store(FREE_VALUE, std::memory_order_release); | |||||
} | |||||
}; | |||||
#endif | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
namespace detail | |||||
{ | |||||
template<class _Ty, class _Cont = std::vector<_Ty>> | |||||
struct _LockVectorAssembleT | |||||
{ | |||||
private: | |||||
_Cont& _Lks; | |||||
public: | |||||
_LockVectorAssembleT(_Cont& _LkN) | |||||
: _Lks(_LkN) | |||||
{} | |||||
size_t size() const | |||||
{ | |||||
return _Lks.size(); | |||||
} | |||||
_Ty& operator[](int _Idx) | |||||
{ | |||||
return _Lks[_Idx]; | |||||
} | |||||
void _Lock_ref(_Ty& _LkN) const | |||||
{ | |||||
_LkN.lock(); | |||||
} | |||||
bool _Try_lock_ref(_Ty& _LkN) const | |||||
{ | |||||
return _LkN.try_lock(); | |||||
} | |||||
void _Unlock_ref(_Ty& _LkN) const | |||||
{ | |||||
_LkN.unlock(); | |||||
} | |||||
void _Yield() const | |||||
{ | |||||
std::this_thread::yield(); | |||||
} | |||||
void _ReturnValue() const; | |||||
template<class U> | |||||
U _ReturnValue(U v) const; | |||||
}; | |||||
template<class _Ty, class _Cont> | |||||
struct _LockVectorAssembleT<std::reference_wrapper<_Ty>, _Cont> | |||||
{ | |||||
private: | |||||
_Cont& _Lks; | |||||
public: | |||||
_LockVectorAssembleT(_Cont& _LkN) | |||||
: _Lks(_LkN) | |||||
{} | |||||
size_t size() const | |||||
{ | |||||
return _Lks.size(); | |||||
} | |||||
std::reference_wrapper<_Ty> operator[](int _Idx) | |||||
{ | |||||
return _Lks[_Idx]; | |||||
} | |||||
void _Lock_ref(std::reference_wrapper<_Ty> _LkN) const | |||||
{ | |||||
_LkN.get().lock(); | |||||
} | |||||
void _Unlock_ref(std::reference_wrapper<_Ty> _LkN) const | |||||
{ | |||||
_LkN.get().unlock(); | |||||
} | |||||
bool _Try_lock_ref(std::reference_wrapper<_Ty> _LkN) const | |||||
{ | |||||
return _LkN.get().try_lock(); | |||||
} | |||||
void _Yield() const | |||||
{ | |||||
std::this_thread::yield(); | |||||
} | |||||
void _ReturnValue() const; | |||||
template<class U> | |||||
U _ReturnValue(U v) const; | |||||
}; | |||||
#define LOCK_ASSEMBLE_NAME(fnName) scoped_lock_range_##fnName | |||||
#define LOCK_ASSEMBLE_AWAIT(a) (a) | |||||
#define LOCK_ASSEMBLE_RETURN(a) return (a) | |||||
#include "without_deadlock_assemble.inl" | |||||
#undef LOCK_ASSEMBLE_NAME | |||||
#undef LOCK_ASSEMBLE_AWAIT | |||||
#undef LOCK_ASSEMBLE_RETURN | |||||
} | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
/** | |||||
* @brief 无死锁的批量枷锁。 | |||||
* @param _Ty 锁的类型。例如std::mutex,resumef::spinlock,resumef::mutex_t(线程用法)均可。 | |||||
* @param _Cont 容纳一批锁的容器。 | |||||
* @param _Assemble 与_Cont配套的锁集合,特化了如何操作_Ty。 | |||||
*/ | |||||
template<class _Ty, class _Cont = std::vector<_Ty>, class _Assemble = detail::_LockVectorAssembleT<_Ty, _Cont>> | |||||
class batch_lock_t | |||||
{ | |||||
public: | |||||
/** | |||||
* @brief 通过锁容器构造,并立刻应用加锁算法。 | |||||
*/ | |||||
explicit batch_lock_t(_Cont& locks_) | |||||
: _LkN(&locks_) | |||||
, _LA(*_LkN) | |||||
{ | |||||
detail::scoped_lock_range_lock_impl::_Lock_range(_LA); | |||||
} | |||||
/** | |||||
* @brief 通过锁容器和锁集合构造,并立刻应用加锁算法。 | |||||
*/ | |||||
explicit batch_lock_t(_Cont& locks_, _Assemble& la_) | |||||
: _LkN(&locks_) | |||||
, _LA(la_) | |||||
{ | |||||
detail::scoped_lock_range_lock_impl::_Lock_range(_LA); | |||||
} | |||||
/** | |||||
* @brief 通过锁容器构造,容器里的锁已经全部获得。 | |||||
*/ | |||||
explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_) | |||||
: _LkN(&locks_) | |||||
, _LA(*_LkN) | |||||
{ // construct but don't lock | |||||
} | |||||
/** | |||||
* @brief 通过锁容器和锁集合构造,容器里的锁已经全部获得。 | |||||
*/ | |||||
explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_, _Assemble& la_) | |||||
: _LkN(&locks_) | |||||
, _LA(la_) | |||||
{ // construct but don't lock | |||||
} | |||||
/** | |||||
* @brief 析构函数里,释放容器里的锁。 | |||||
*/ | |||||
~batch_lock_t() noexcept | |||||
{ | |||||
if (_LkN != nullptr) | |||||
detail::scoped_lock_range_lock_impl::_Unlock_locks(0, (int)_LA.size(), _LA); | |||||
} | |||||
/** | |||||
* @brief 手工释放容器里的锁,析构函数里将不再有释放操作。 | |||||
*/ | |||||
void unlock() | |||||
{ | |||||
if (_LkN != nullptr) | |||||
{ | |||||
_LkN = nullptr; | |||||
detail::scoped_lock_range_lock_impl::_Unlock_locks(0, (int)_LA.size(), _LA); | |||||
} | |||||
} | |||||
/** | |||||
* @brief 不支持拷贝构造。 | |||||
*/ | |||||
batch_lock_t(const batch_lock_t&) = delete; | |||||
/** | |||||
* @brief 不支持拷贝赋值。 | |||||
*/ | |||||
batch_lock_t& operator=(const batch_lock_t&) = delete; | |||||
/** | |||||
* @brief 支持移动构造。 | |||||
*/ | |||||
batch_lock_t(batch_lock_t&& _Right) | |||||
: _LkN(_Right._LkN) | |||||
, _LA(std::move(_Right._LA)) | |||||
{ | |||||
_Right._LkN = nullptr; | |||||
} | |||||
/** | |||||
* @brief 支持移动赋值。 | |||||
*/ | |||||
batch_lock_t& operator=(batch_lock_t&& _Right) | |||||
{ | |||||
if (this != &_Right) | |||||
{ | |||||
_LkN = _Right._LkN; | |||||
_Right._LkN = nullptr; | |||||
_LA = std::move(_Right._LA); | |||||
} | |||||
} | |||||
private: | |||||
_Cont* _LkN; | |||||
_Assemble _LA; | |||||
}; | |||||
} | |||||
//用于内部实现的循环锁 | |||||
#pragma once | |||||
namespace librf | |||||
{ | |||||
#if defined(RESUMEF_USE_CUSTOM_SPINLOCK) | |||||
using spinlock = RESUMEF_USE_CUSTOM_SPINLOCK; | |||||
#else | |||||
/** | |||||
* @brief 一个自旋锁实现。 | |||||
*/ | |||||
struct spinlock | |||||
{ | |||||
static const size_t MAX_ACTIVE_SPIN = 4000; | |||||
static const size_t MAX_YIELD_SPIN = 8000; | |||||
static const int FREE_VALUE = 0; | |||||
static const int LOCKED_VALUE = 1; | |||||
std::atomic<int> lck; | |||||
#if _DEBUG | |||||
std::thread::id owner_thread_id; | |||||
#endif | |||||
/** | |||||
* @brief 初始为未加锁。 | |||||
*/ | |||||
spinlock() noexcept | |||||
{ | |||||
lck = FREE_VALUE; | |||||
} | |||||
/** | |||||
* @brief 获得锁。会一直阻塞线程直到获得锁。 | |||||
*/ | |||||
void lock() noexcept | |||||
{ | |||||
int val = FREE_VALUE; | |||||
if (!lck.compare_exchange_weak(val, LOCKED_VALUE, std::memory_order_acq_rel)) | |||||
{ | |||||
#if _DEBUG | |||||
//诊断错误的用法:进行了递归锁调用 | |||||
assert(owner_thread_id != std::this_thread::get_id()); | |||||
#endif | |||||
size_t spinCount = 0; | |||||
auto dt = std::chrono::milliseconds{ 1 }; | |||||
do | |||||
{ | |||||
while (lck.load(std::memory_order_relaxed) != FREE_VALUE) | |||||
{ | |||||
if (spinCount < MAX_ACTIVE_SPIN) | |||||
{ | |||||
++spinCount; | |||||
} | |||||
else if (spinCount < MAX_YIELD_SPIN) | |||||
{ | |||||
++spinCount; | |||||
std::this_thread::yield(); | |||||
} | |||||
else | |||||
{ | |||||
std::this_thread::sleep_for(dt); | |||||
dt = (std::min)(std::chrono::milliseconds{ 128 }, dt * 2); | |||||
} | |||||
} | |||||
val = FREE_VALUE; | |||||
} while (!lck.compare_exchange_weak(val, LOCKED_VALUE, std::memory_order_acq_rel)); | |||||
} | |||||
#if _DEBUG | |||||
owner_thread_id = std::this_thread::get_id(); | |||||
#endif | |||||
} | |||||
/** | |||||
* @brief 尝试获得锁一次。 | |||||
*/ | |||||
bool try_lock() noexcept | |||||
{ | |||||
int val = FREE_VALUE; | |||||
bool ret = lck.compare_exchange_strong(val, LOCKED_VALUE, std::memory_order_acq_rel); | |||||
#if _DEBUG | |||||
if (ret) owner_thread_id = std::this_thread::get_id(); | |||||
#endif | |||||
return ret; | |||||
} | |||||
/** | |||||
* @brief 释放锁。 | |||||
*/ | |||||
void unlock() noexcept | |||||
{ | |||||
#if _DEBUG | |||||
owner_thread_id = std::thread::id(); | |||||
#endif | |||||
lck.store(FREE_VALUE, std::memory_order_release); | |||||
} | |||||
}; | |||||
#endif | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
namespace detail | |||||
{ | |||||
template<class _Ty, class _Cont = std::vector<_Ty>> | |||||
struct _LockVectorAssembleT | |||||
{ | |||||
private: | |||||
_Cont& _Lks; | |||||
public: | |||||
_LockVectorAssembleT(_Cont& _LkN) | |||||
: _Lks(_LkN) | |||||
{} | |||||
size_t size() const | |||||
{ | |||||
return _Lks.size(); | |||||
} | |||||
_Ty& operator[](int _Idx) | |||||
{ | |||||
return _Lks[_Idx]; | |||||
} | |||||
void _Lock_ref(_Ty& _LkN) const | |||||
{ | |||||
_LkN.lock(); | |||||
} | |||||
bool _Try_lock_ref(_Ty& _LkN) const | |||||
{ | |||||
return _LkN.try_lock(); | |||||
} | |||||
void _Unlock_ref(_Ty& _LkN) const | |||||
{ | |||||
_LkN.unlock(); | |||||
} | |||||
void _Yield() const | |||||
{ | |||||
std::this_thread::yield(); | |||||
} | |||||
void _ReturnValue() const; | |||||
template<class U> | |||||
U _ReturnValue(U v) const; | |||||
}; | |||||
template<class _Ty, class _Cont> | |||||
struct _LockVectorAssembleT<std::reference_wrapper<_Ty>, _Cont> | |||||
{ | |||||
private: | |||||
_Cont& _Lks; | |||||
public: | |||||
_LockVectorAssembleT(_Cont& _LkN) | |||||
: _Lks(_LkN) | |||||
{} | |||||
size_t size() const | |||||
{ | |||||
return _Lks.size(); | |||||
} | |||||
std::reference_wrapper<_Ty> operator[](int _Idx) | |||||
{ | |||||
return _Lks[_Idx]; | |||||
} | |||||
void _Lock_ref(std::reference_wrapper<_Ty> _LkN) const | |||||
{ | |||||
_LkN.get().lock(); | |||||
} | |||||
void _Unlock_ref(std::reference_wrapper<_Ty> _LkN) const | |||||
{ | |||||
_LkN.get().unlock(); | |||||
} | |||||
bool _Try_lock_ref(std::reference_wrapper<_Ty> _LkN) const | |||||
{ | |||||
return _LkN.get().try_lock(); | |||||
} | |||||
void _Yield() const | |||||
{ | |||||
std::this_thread::yield(); | |||||
} | |||||
void _ReturnValue() const; | |||||
template<class U> | |||||
U _ReturnValue(U v) const; | |||||
}; | |||||
#define LOCK_ASSEMBLE_NAME(fnName) scoped_lock_range_##fnName | |||||
#define LOCK_ASSEMBLE_AWAIT(a) (a) | |||||
#define LOCK_ASSEMBLE_RETURN(a) return (a) | |||||
#include "without_deadlock_assemble.inl" | |||||
#undef LOCK_ASSEMBLE_NAME | |||||
#undef LOCK_ASSEMBLE_AWAIT | |||||
#undef LOCK_ASSEMBLE_RETURN | |||||
} | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
/** | |||||
* @brief 无死锁的批量枷锁。 | |||||
* @param _Ty 锁的类型。例如std::mutex,librf::spinlock,librf::mutex_t(线程用法)均可。 | |||||
* @param _Cont 容纳一批锁的容器。 | |||||
* @param _Assemble 与_Cont配套的锁集合,特化了如何操作_Ty。 | |||||
*/ | |||||
template<class _Ty, class _Cont = std::vector<_Ty>, class _Assemble = detail::_LockVectorAssembleT<_Ty, _Cont>> | |||||
class batch_lock_t | |||||
{ | |||||
public: | |||||
/** | |||||
* @brief 通过锁容器构造,并立刻应用加锁算法。 | |||||
*/ | |||||
explicit batch_lock_t(_Cont& locks_) | |||||
: _LkN(&locks_) | |||||
, _LA(*_LkN) | |||||
{ | |||||
detail::scoped_lock_range_lock_impl::_Lock_range(_LA); | |||||
} | |||||
/** | |||||
* @brief 通过锁容器和锁集合构造,并立刻应用加锁算法。 | |||||
*/ | |||||
explicit batch_lock_t(_Cont& locks_, _Assemble& la_) | |||||
: _LkN(&locks_) | |||||
, _LA(la_) | |||||
{ | |||||
detail::scoped_lock_range_lock_impl::_Lock_range(_LA); | |||||
} | |||||
/** | |||||
* @brief 通过锁容器构造,容器里的锁已经全部获得。 | |||||
*/ | |||||
explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_) | |||||
: _LkN(&locks_) | |||||
, _LA(*_LkN) | |||||
{ // construct but don't lock | |||||
} | |||||
/** | |||||
* @brief 通过锁容器和锁集合构造,容器里的锁已经全部获得。 | |||||
*/ | |||||
explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_, _Assemble& la_) | |||||
: _LkN(&locks_) | |||||
, _LA(la_) | |||||
{ // construct but don't lock | |||||
} | |||||
/** | |||||
* @brief 析构函数里,释放容器里的锁。 | |||||
*/ | |||||
~batch_lock_t() noexcept | |||||
{ | |||||
if (_LkN != nullptr) | |||||
detail::scoped_lock_range_lock_impl::_Unlock_locks(0, (int)_LA.size(), _LA); | |||||
} | |||||
/** | |||||
* @brief 手工释放容器里的锁,析构函数里将不再有释放操作。 | |||||
*/ | |||||
void unlock() | |||||
{ | |||||
if (_LkN != nullptr) | |||||
{ | |||||
_LkN = nullptr; | |||||
detail::scoped_lock_range_lock_impl::_Unlock_locks(0, (int)_LA.size(), _LA); | |||||
} | |||||
} | |||||
/** | |||||
* @brief 不支持拷贝构造。 | |||||
*/ | |||||
batch_lock_t(const batch_lock_t&) = delete; | |||||
/** | |||||
* @brief 不支持拷贝赋值。 | |||||
*/ | |||||
batch_lock_t& operator=(const batch_lock_t&) = delete; | |||||
/** | |||||
* @brief 支持移动构造。 | |||||
*/ | |||||
batch_lock_t(batch_lock_t&& _Right) | |||||
: _LkN(_Right._LkN) | |||||
, _LA(std::move(_Right._LA)) | |||||
{ | |||||
_Right._LkN = nullptr; | |||||
} | |||||
/** | |||||
* @brief 支持移动赋值。 | |||||
*/ | |||||
batch_lock_t& operator=(batch_lock_t&& _Right) | |||||
{ | |||||
if (this != &_Right) | |||||
{ | |||||
_LkN = _Right._LkN; | |||||
_Right._LkN = nullptr; | |||||
_LA = std::move(_Right._LA); | |||||
} | |||||
} | |||||
private: | |||||
_Cont* _LkN; | |||||
_Assemble _LA; | |||||
}; | |||||
} |
#pragma once | |||||
namespace resumef | |||||
{ | |||||
/** | |||||
* @brief state基类,state用于在协程的promise和future之间共享数据。 | |||||
*/ | |||||
struct state_base_t | |||||
{ | |||||
using _Alloc_char = std::allocator<char>; | |||||
private: | |||||
std::atomic<intptr_t> _count{0}; | |||||
public: | |||||
void lock() noexcept | |||||
{ | |||||
_count.fetch_add(1, std::memory_order_acq_rel); | |||||
} | |||||
void unlock() | |||||
{ | |||||
if (unlikely(_count.fetch_sub(1, std::memory_order_acq_rel) == 1)) | |||||
{ | |||||
destroy_deallocate(); | |||||
} | |||||
} | |||||
protected: | |||||
scheduler_t* _scheduler = nullptr; | |||||
//可能来自协程里的promise产生的,则经过co_await操作后,_coro在初始时不会为nullptr。 | |||||
//也可能来自awaitable_t,如果 | |||||
// 一、经过co_await操作后,_coro在初始时不会为nullptr。 | |||||
// 二、没有co_await操作,直接加入到了调度器里,则_coro在初始时为nullptr。调度器需要特殊处理此种情况。 | |||||
coroutine_handle<> _coro; | |||||
virtual ~state_base_t(); | |||||
private: | |||||
virtual void destroy_deallocate(); | |||||
public: | |||||
virtual void resume() = 0; | |||||
virtual bool has_handler() const noexcept = 0; | |||||
virtual state_base_t* get_parent() const noexcept; | |||||
void set_scheduler(scheduler_t* sch) noexcept | |||||
{ | |||||
_scheduler = sch; | |||||
} | |||||
coroutine_handle<> get_handler() const noexcept | |||||
{ | |||||
return _coro; | |||||
} | |||||
state_base_t* get_root() const | |||||
{ | |||||
state_base_t* root = const_cast<state_base_t*>(this); | |||||
state_base_t* next = root->get_parent(); | |||||
while (next != nullptr) | |||||
{ | |||||
root = next; | |||||
next = next->get_parent(); | |||||
} | |||||
return root; | |||||
} | |||||
scheduler_t* get_scheduler() const | |||||
{ | |||||
return get_root()->_scheduler; | |||||
} | |||||
}; | |||||
/** | |||||
* @brief 专用于generator_t<>的state类。 | |||||
*/ | |||||
struct state_generator_t : public state_base_t | |||||
{ | |||||
private: | |||||
virtual void destroy_deallocate() override; | |||||
state_generator_t() = default; | |||||
public: | |||||
virtual void resume() override; | |||||
virtual bool has_handler() const noexcept override; | |||||
bool switch_scheduler_await_suspend(scheduler_t* sch); | |||||
void set_initial_suspend(coroutine_handle<> handler) noexcept | |||||
{ | |||||
_coro = handler; | |||||
} | |||||
#if RESUMEF_INLINE_STATE | |||||
static state_generator_t* _Construct(void* _Ptr) | |||||
{ | |||||
return new(_Ptr) state_generator_t(); | |||||
} | |||||
#endif | |||||
static state_generator_t* _Alloc_state(); | |||||
}; | |||||
/** | |||||
* @brief 专用于future_t<>的state基类,实现了针对于future_t<>的公共方法等。 | |||||
*/ | |||||
struct state_future_t : public state_base_t | |||||
{ | |||||
enum struct initor_type : uint8_t | |||||
{ | |||||
None, | |||||
Initial, | |||||
Final | |||||
}; | |||||
enum struct result_type : uint8_t | |||||
{ | |||||
None, | |||||
Value, | |||||
Exception, | |||||
}; | |||||
//typedef std::recursive_mutex lock_type; | |||||
typedef spinlock lock_type; | |||||
protected: | |||||
mutable lock_type _mtx; | |||||
coroutine_handle<> _initor; | |||||
state_future_t* _parent = nullptr; | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
intptr_t _id; | |||||
#endif | |||||
uint32_t _alloc_size = 0; | |||||
//注意:_has_value对齐到 4 Byte上,后面必须紧跟 _is_future变量。两者能组合成一个uint16_t数据。 | |||||
std::atomic<result_type> _has_value{ result_type::None }; | |||||
bool _is_future; | |||||
initor_type _is_initor = initor_type::None; | |||||
static_assert(sizeof(std::atomic<result_type>) == 1); | |||||
static_assert(alignof(std::atomic<result_type>) == 1); | |||||
static_assert(sizeof(bool) == 1); | |||||
static_assert(alignof(bool) == 1); | |||||
static_assert(sizeof(std::atomic<initor_type>) == 1); | |||||
static_assert(alignof(std::atomic<initor_type>) == 1); | |||||
protected: | |||||
explicit state_future_t(bool awaitor) noexcept | |||||
{ | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
_id = ++g_resumef_state_id; | |||||
#endif | |||||
_is_future = !awaitor; | |||||
} | |||||
public: | |||||
virtual void destroy_deallocate() override; | |||||
virtual void resume() override; | |||||
virtual bool has_handler() const noexcept override; | |||||
virtual state_base_t* get_parent() const noexcept override; | |||||
inline bool is_ready() const noexcept | |||||
{ | |||||
#pragma warning(disable : 6326) //warning C6326: Potential comparison of a constant with another constant. | |||||
//msvc认为是constexpr表达式(不写还给警告),然而,clang不这么认为。 | |||||
//放弃constexpr,反正合格的编译器都会优化掉这个if判断的。 | |||||
if | |||||
#if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) | |||||
constexpr | |||||
#endif | |||||
(_offset_of(state_future_t, _is_future) - _offset_of(state_future_t, _has_value) == 1) | |||||
return 0 != reinterpret_cast<const std::atomic<uint16_t> &>(_has_value).load(std::memory_order_acquire); | |||||
else | |||||
return _has_value.load(std::memory_order_acquire) != result_type::None || _is_future; | |||||
#pragma warning(default : 6326) | |||||
} | |||||
inline bool has_handler_skip_lock() const noexcept | |||||
{ | |||||
return (bool)_coro || _is_initor != initor_type::None; | |||||
} | |||||
inline uint32_t get_alloc_size() const noexcept | |||||
{ | |||||
return _alloc_size; | |||||
} | |||||
inline bool future_await_ready() const noexcept | |||||
{ | |||||
//scoped_lock<lock_type> __guard(this->_mtx); | |||||
return _has_value.load(std::memory_order_acquire) != result_type::None; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
void future_await_suspend(coroutine_handle<_PromiseT> handler); | |||||
bool switch_scheduler_await_suspend(scheduler_t* sch); | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
void promise_initial_suspend(coroutine_handle<_PromiseT> handler); | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
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> | |||||
static inline _Sty* _Alloc_state(bool awaitor) | |||||
{ | |||||
_Alloc_char _Al; | |||||
size_t _Size = _Align_size<_Sty>(); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << "state_future_t::alloc, size=" << _Size << std::endl; | |||||
#endif | |||||
char* _Ptr = _Al.allocate(_Size); | |||||
_Sty* st = new(_Ptr) _Sty(awaitor); | |||||
st->_alloc_size = static_cast<uint32_t>(_Size); | |||||
return st; | |||||
} | |||||
}; | |||||
/** | |||||
* @brief 专用于future_t<>的state类。 | |||||
*/ | |||||
template <typename _Ty> | |||||
struct state_t final : public state_future_t | |||||
{ | |||||
friend state_future_t; | |||||
using state_future_t::lock_type; | |||||
using value_type = _Ty; | |||||
private: | |||||
explicit state_t(bool awaitor) noexcept :state_future_t(awaitor) {} | |||||
public: | |||||
~state_t() | |||||
{ | |||||
switch (_has_value.load(std::memory_order_acquire)) | |||||
{ | |||||
case result_type::Value: | |||||
_value.~value_type(); | |||||
break; | |||||
case result_type::Exception: | |||||
_exception.~exception_ptr(); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
auto future_await_resume() -> value_type; | |||||
template<class _PromiseT, typename U, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
void promise_yield_value(_PromiseT* promise, U&& val); | |||||
void set_exception(std::exception_ptr e); | |||||
template<typename U> | |||||
void set_value(U&& val); | |||||
template<class _Exp> | |||||
inline void throw_exception(_Exp e) | |||||
{ | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | |||||
private: | |||||
union | |||||
{ | |||||
std::exception_ptr _exception; | |||||
value_type _value; | |||||
}; | |||||
template<typename U> | |||||
void set_value_internal(U&& val); | |||||
void set_exception_internal(std::exception_ptr e); | |||||
}; | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
template <typename _Ty> | |||||
struct state_t<_Ty&> final : public state_future_t | |||||
{ | |||||
friend state_future_t; | |||||
using state_future_t::lock_type; | |||||
using value_type = _Ty; | |||||
using reference_type = _Ty&; | |||||
private: | |||||
explicit state_t(bool awaitor) noexcept :state_future_t(awaitor) {} | |||||
public: | |||||
~state_t() | |||||
{ | |||||
if (_has_value.load(std::memory_order_acquire) == result_type::Exception) | |||||
_exception.~exception_ptr(); | |||||
} | |||||
auto future_await_resume()->reference_type; | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
void promise_yield_value(_PromiseT* promise, reference_type val); | |||||
void set_exception(std::exception_ptr e); | |||||
void set_value(reference_type val); | |||||
template<class _Exp> | |||||
inline void throw_exception(_Exp e) | |||||
{ | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | |||||
private: | |||||
union | |||||
{ | |||||
std::exception_ptr _exception; | |||||
value_type* _value; | |||||
}; | |||||
void set_value_internal(reference_type val); | |||||
void set_exception_internal(std::exception_ptr e); | |||||
}; | |||||
template<> | |||||
struct state_t<void> final : public state_future_t | |||||
{ | |||||
friend state_future_t; | |||||
using state_future_t::lock_type; | |||||
private: | |||||
explicit state_t(bool awaitor) noexcept :state_future_t(awaitor) {} | |||||
public: | |||||
void future_await_resume(); | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
void promise_yield_value(_PromiseT* promise); | |||||
void set_exception(std::exception_ptr e); | |||||
void set_value(); | |||||
template<class _Exp> | |||||
inline void throw_exception(_Exp e) | |||||
{ | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | |||||
private: | |||||
std::exception_ptr _exception; | |||||
}; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
} | |||||
#pragma once | |||||
namespace librf | |||||
{ | |||||
/** | |||||
* @brief state基类,state用于在协程的promise和future之间共享数据。 | |||||
*/ | |||||
struct state_base_t | |||||
{ | |||||
using _Alloc_char = std::allocator<char>; | |||||
private: | |||||
std::atomic<intptr_t> _count{0}; | |||||
public: | |||||
void lock() noexcept | |||||
{ | |||||
_count.fetch_add(1, std::memory_order_acq_rel); | |||||
} | |||||
void unlock() | |||||
{ | |||||
if (unlikely(_count.fetch_sub(1, std::memory_order_acq_rel) == 1)) | |||||
{ | |||||
destroy_deallocate(); | |||||
} | |||||
} | |||||
protected: | |||||
scheduler_t* _scheduler = nullptr; | |||||
//可能来自协程里的promise产生的,则经过co_await操作后,_coro在初始时不会为nullptr。 | |||||
//也可能来自awaitable_t,如果 | |||||
// 一、经过co_await操作后,_coro在初始时不会为nullptr。 | |||||
// 二、没有co_await操作,直接加入到了调度器里,则_coro在初始时为nullptr。调度器需要特殊处理此种情况。 | |||||
coroutine_handle<> _coro; | |||||
virtual ~state_base_t(); | |||||
private: | |||||
virtual void destroy_deallocate(); | |||||
public: | |||||
virtual void resume() = 0; | |||||
virtual bool has_handler() const noexcept = 0; | |||||
virtual state_base_t* get_parent() const noexcept; | |||||
void set_scheduler(scheduler_t* sch) noexcept | |||||
{ | |||||
_scheduler = sch; | |||||
} | |||||
coroutine_handle<> get_handler() const noexcept | |||||
{ | |||||
return _coro; | |||||
} | |||||
state_base_t* get_root() const | |||||
{ | |||||
state_base_t* root = const_cast<state_base_t*>(this); | |||||
state_base_t* next = root->get_parent(); | |||||
while (next != nullptr) | |||||
{ | |||||
root = next; | |||||
next = next->get_parent(); | |||||
} | |||||
return root; | |||||
} | |||||
scheduler_t* get_scheduler() const | |||||
{ | |||||
return get_root()->_scheduler; | |||||
} | |||||
}; | |||||
/** | |||||
* @brief 专用于generator_t<>的state类。 | |||||
*/ | |||||
struct state_generator_t : public state_base_t | |||||
{ | |||||
private: | |||||
virtual void destroy_deallocate() override; | |||||
state_generator_t() = default; | |||||
public: | |||||
virtual void resume() override; | |||||
virtual bool has_handler() const noexcept override; | |||||
bool switch_scheduler_await_suspend(scheduler_t* sch); | |||||
void set_initial_suspend(coroutine_handle<> handler) noexcept | |||||
{ | |||||
_coro = handler; | |||||
} | |||||
#if RESUMEF_INLINE_STATE | |||||
static state_generator_t* _Construct(void* _Ptr) | |||||
{ | |||||
return new(_Ptr) state_generator_t(); | |||||
} | |||||
#endif | |||||
static state_generator_t* _Alloc_state(); | |||||
}; | |||||
/** | |||||
* @brief 专用于future_t<>的state基类,实现了针对于future_t<>的公共方法等。 | |||||
*/ | |||||
struct state_future_t : public state_base_t | |||||
{ | |||||
enum struct initor_type : uint8_t | |||||
{ | |||||
None, | |||||
Initial, | |||||
Final | |||||
}; | |||||
enum struct result_type : uint8_t | |||||
{ | |||||
None, | |||||
Value, | |||||
Exception, | |||||
}; | |||||
//typedef std::recursive_mutex lock_type; | |||||
typedef spinlock lock_type; | |||||
protected: | |||||
mutable lock_type _mtx; | |||||
coroutine_handle<> _initor; | |||||
state_future_t* _parent = nullptr; | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
intptr_t _id; | |||||
#endif | |||||
uint32_t _alloc_size = 0; | |||||
//注意:_has_value对齐到 4 Byte上,后面必须紧跟 _is_future变量。两者能组合成一个uint16_t数据。 | |||||
std::atomic<result_type> _has_value{ result_type::None }; | |||||
bool _is_future; | |||||
initor_type _is_initor = initor_type::None; | |||||
static_assert(sizeof(std::atomic<result_type>) == 1); | |||||
static_assert(alignof(std::atomic<result_type>) == 1); | |||||
static_assert(sizeof(bool) == 1); | |||||
static_assert(alignof(bool) == 1); | |||||
static_assert(sizeof(std::atomic<initor_type>) == 1); | |||||
static_assert(alignof(std::atomic<initor_type>) == 1); | |||||
protected: | |||||
explicit state_future_t(bool awaitor) noexcept | |||||
{ | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
_id = ++g_resumef_state_id; | |||||
#endif | |||||
_is_future = !awaitor; | |||||
} | |||||
public: | |||||
virtual void destroy_deallocate() override; | |||||
virtual void resume() override; | |||||
virtual bool has_handler() const noexcept override; | |||||
virtual state_base_t* get_parent() const noexcept override; | |||||
inline bool is_ready() const noexcept | |||||
{ | |||||
#pragma warning(disable : 6326) //warning C6326: Potential comparison of a constant with another constant. | |||||
//msvc认为是constexpr表达式(不写还给警告),然而,clang不这么认为。 | |||||
//放弃constexpr,反正合格的编译器都会优化掉这个if判断的。 | |||||
if | |||||
#if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) | |||||
constexpr | |||||
#endif | |||||
(_offset_of(state_future_t, _is_future) - _offset_of(state_future_t, _has_value) == 1) | |||||
return 0 != reinterpret_cast<const std::atomic<uint16_t> &>(_has_value).load(std::memory_order_acquire); | |||||
else | |||||
return _has_value.load(std::memory_order_acquire) != result_type::None || _is_future; | |||||
#pragma warning(default : 6326) | |||||
} | |||||
inline bool has_handler_skip_lock() const noexcept | |||||
{ | |||||
return (bool)_coro || _is_initor != initor_type::None; | |||||
} | |||||
inline uint32_t get_alloc_size() const noexcept | |||||
{ | |||||
return _alloc_size; | |||||
} | |||||
inline bool future_await_ready() const noexcept | |||||
{ | |||||
//scoped_lock<lock_type> __guard(this->_mtx); | |||||
return _has_value.load(std::memory_order_acquire) != result_type::None; | |||||
} | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
void future_await_suspend(coroutine_handle<_PromiseT> handler); | |||||
bool switch_scheduler_await_suspend(scheduler_t* sch); | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
void promise_initial_suspend(coroutine_handle<_PromiseT> handler); | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
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> | |||||
static inline _Sty* _Alloc_state(bool awaitor) | |||||
{ | |||||
_Alloc_char _Al; | |||||
size_t _Size = _Align_size<_Sty>(); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << "state_future_t::alloc, size=" << _Size << std::endl; | |||||
#endif | |||||
char* _Ptr = _Al.allocate(_Size); | |||||
_Sty* st = new(_Ptr) _Sty(awaitor); | |||||
st->_alloc_size = static_cast<uint32_t>(_Size); | |||||
return st; | |||||
} | |||||
}; | |||||
/** | |||||
* @brief 专用于future_t<>的state类。 | |||||
*/ | |||||
template <typename _Ty> | |||||
struct state_t final : public state_future_t | |||||
{ | |||||
friend state_future_t; | |||||
using state_future_t::lock_type; | |||||
using value_type = _Ty; | |||||
private: | |||||
explicit state_t(bool awaitor) noexcept :state_future_t(awaitor) {} | |||||
public: | |||||
~state_t() | |||||
{ | |||||
switch (_has_value.load(std::memory_order_acquire)) | |||||
{ | |||||
case result_type::Value: | |||||
_value.~value_type(); | |||||
break; | |||||
case result_type::Exception: | |||||
_exception.~exception_ptr(); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
auto future_await_resume() -> value_type; | |||||
template<class _PromiseT, typename U, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
void promise_yield_value(_PromiseT* promise, U&& val); | |||||
void set_exception(std::exception_ptr e); | |||||
template<typename U> | |||||
void set_value(U&& val); | |||||
template<class _Exp> | |||||
inline void throw_exception(_Exp e) | |||||
{ | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | |||||
private: | |||||
union | |||||
{ | |||||
std::exception_ptr _exception; | |||||
value_type _value; | |||||
}; | |||||
template<typename U> | |||||
void set_value_internal(U&& val); | |||||
void set_exception_internal(std::exception_ptr e); | |||||
}; | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
template <typename _Ty> | |||||
struct state_t<_Ty&> final : public state_future_t | |||||
{ | |||||
friend state_future_t; | |||||
using state_future_t::lock_type; | |||||
using value_type = _Ty; | |||||
using reference_type = _Ty&; | |||||
private: | |||||
explicit state_t(bool awaitor) noexcept :state_future_t(awaitor) {} | |||||
public: | |||||
~state_t() | |||||
{ | |||||
if (_has_value.load(std::memory_order_acquire) == result_type::Exception) | |||||
_exception.~exception_ptr(); | |||||
} | |||||
auto future_await_resume()->reference_type; | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
void promise_yield_value(_PromiseT* promise, reference_type val); | |||||
void set_exception(std::exception_ptr e); | |||||
void set_value(reference_type val); | |||||
template<class _Exp> | |||||
inline void throw_exception(_Exp e) | |||||
{ | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | |||||
private: | |||||
union | |||||
{ | |||||
std::exception_ptr _exception; | |||||
value_type* _value; | |||||
}; | |||||
void set_value_internal(reference_type val); | |||||
void set_exception_internal(std::exception_ptr e); | |||||
}; | |||||
template<> | |||||
struct state_t<void> final : public state_future_t | |||||
{ | |||||
friend state_future_t; | |||||
using state_future_t::lock_type; | |||||
private: | |||||
explicit state_t(bool awaitor) noexcept :state_future_t(awaitor) {} | |||||
public: | |||||
void future_await_resume(); | |||||
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>> | |||||
void promise_yield_value(_PromiseT* promise); | |||||
void set_exception(std::exception_ptr e); | |||||
void set_value(); | |||||
template<class _Exp> | |||||
inline void throw_exception(_Exp e) | |||||
{ | |||||
set_exception(std::make_exception_ptr(std::move(e))); | |||||
} | |||||
private: | |||||
std::exception_ptr _exception; | |||||
}; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
} | |||||
| | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
template<class _PromiseT, typename _Enable> | template<class _PromiseT, typename _Enable> | ||||
void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler) | void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler) |
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
/** | /** | ||||
* @brief 切换协程的可等待对象。 | * @brief 切换协程的可等待对象。 | ||||
* 如果指定的协程不是本协程的调度器,则协程暂停后放入到目的协程的调度队列,等待下一次运行。 | * 如果指定的协程不是本协程的调度器,则协程暂停后放入到目的协程的调度队列,等待下一次运行。 | ||||
* @param sch 将要运行后续代码的协程 | * @param sch 将要运行后续代码的协程 | ||||
* @return [co_await] void | * @return [co_await] void | ||||
* @note 本函数是resumef名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 switch_scheduler_awaitor 类下。 | |||||
* @note 本函数是librf名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 switch_scheduler_awaitor 类下。 | |||||
*/ | */ | ||||
static switch_scheduler_awaitor via(scheduler_t& sch) noexcept; | static switch_scheduler_awaitor via(scheduler_t& sch) noexcept; | ||||
* 如果指定的协程不是本协程的调度器,则协程暂停后放入到目的协程的调度队列,等待下一次运行。 | * 如果指定的协程不是本协程的调度器,则协程暂停后放入到目的协程的调度队列,等待下一次运行。 | ||||
* @param sch 将要运行后续代码的协程 | * @param sch 将要运行后续代码的协程 | ||||
* @return [co_await] void | * @return [co_await] void | ||||
* @note 本函数是resumef名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 switch_scheduler_awaitor 类下。 | |||||
* @note 本函数是librf名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 switch_scheduler_awaitor 类下。 | |||||
*/ | */ | ||||
static switch_scheduler_awaitor via(scheduler_t* sch) noexcept; | static switch_scheduler_awaitor via(scheduler_t* sch) noexcept; | ||||
#endif //DOXYGEN_SKIP_PROPERTY | #endif //DOXYGEN_SKIP_PROPERTY |
#pragma once | |||||
namespace resumef | |||||
{ | |||||
struct timer_manager; | |||||
typedef std::shared_ptr<timer_manager> timer_mgr_ptr; | |||||
typedef std::weak_ptr<timer_manager> timer_mgr_wptr; | |||||
namespace detail | |||||
{ | |||||
typedef std::chrono::system_clock timer_clock_type; | |||||
typedef std::function<void(bool)> timer_callback_type; | |||||
/** | |||||
* @brief 定时器对象。 | |||||
*/ | |||||
struct timer_target : public std::enable_shared_from_this<timer_target> | |||||
{ | |||||
friend timer_manager; | |||||
private: | |||||
enum struct State : uint32_t | |||||
{ | |||||
Invalid, | |||||
Added, | |||||
Runing, | |||||
}; | |||||
timer_clock_type::time_point tp; | |||||
timer_callback_type cb; | |||||
State st = State::Invalid; | |||||
#if _DEBUG | |||||
private: | |||||
timer_manager * _manager = nullptr; | |||||
#endif | |||||
public: | |||||
timer_target(const timer_clock_type::time_point & tp_, const timer_callback_type & cb_) | |||||
: tp(tp_) | |||||
, cb(cb_) | |||||
{ | |||||
} | |||||
timer_target(const timer_clock_type::time_point & tp_, timer_callback_type && cb_) | |||||
: tp(tp_) | |||||
, cb(std::forward<timer_callback_type>(cb_)) | |||||
{ | |||||
} | |||||
private: | |||||
timer_target() = delete; | |||||
timer_target(const timer_target &) = delete; | |||||
timer_target(timer_target && right_) = delete; | |||||
timer_target & operator = (const timer_target &) = delete; | |||||
timer_target & operator = (timer_target && right_) = delete; | |||||
}; | |||||
typedef std::shared_ptr<timer_target> timer_target_ptr; | |||||
typedef std::weak_ptr<timer_target> timer_target_wptr; | |||||
} | |||||
/** | |||||
* @brief 定时器句柄。 | |||||
* @details 对定时器对象和定时器管理器都采用弱引用。 | |||||
*/ | |||||
struct timer_handler | |||||
{ | |||||
private: | |||||
timer_mgr_wptr _manager; | |||||
detail::timer_target_wptr _target; | |||||
public: | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
timer_handler() = default; | |||||
timer_handler(const timer_handler &) = default; | |||||
timer_handler(timer_handler && right_) noexcept; | |||||
timer_handler & operator = (const timer_handler &) = default; | |||||
timer_handler & operator = (timer_handler && right_) noexcept; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
timer_handler(timer_manager * manager_, const detail::timer_target_ptr & target_); | |||||
void reset(); | |||||
bool stop(); | |||||
bool expired() const; | |||||
}; | |||||
/** | |||||
* @brief 定时器管理器。 | |||||
*/ | |||||
struct timer_manager : public std::enable_shared_from_this<timer_manager> | |||||
{ | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
typedef detail::timer_target timer_target; | |||||
typedef detail::timer_target_ptr timer_target_ptr; | |||||
typedef detail::timer_clock_type clock_type; | |||||
typedef clock_type::duration duration_type; | |||||
typedef clock_type::time_point time_point_type; | |||||
typedef std::vector<timer_target_ptr> timer_vector_type; | |||||
typedef std::multimap<clock_type::time_point, timer_target_ptr> timer_map_type; | |||||
#endif | |||||
public: | |||||
timer_manager(); | |||||
~timer_manager(); | |||||
template<class _Rep, class _Period, class _Cb> | |||||
timer_target_ptr add(const std::chrono::duration<_Rep, _Period> & dt_, _Cb && cb_) | |||||
{ | |||||
return add_(std::chrono::duration_cast<duration_type>(dt_), std::forward<_Cb>(cb_)); | |||||
} | |||||
template<class _Clock, class _Duration = typename _Clock::duration, class _Cb> | |||||
timer_target_ptr add(const std::chrono::time_point<_Clock, _Duration> & tp_, _Cb && cb_) | |||||
{ | |||||
return add_(std::chrono::time_point_cast<duration_type>(tp_), std::forward<_Cb>(cb_)); | |||||
} | |||||
template<class _Rep, class _Period, class _Cb> | |||||
timer_handler add_handler(const std::chrono::duration<_Rep, _Period> & dt_, _Cb && cb_) | |||||
{ | |||||
return{ this, add(dt_, std::forward<_Cb>(cb_)) }; | |||||
} | |||||
template<class _Clock, class _Duration = typename _Clock::duration, class _Cb> | |||||
timer_handler add_handler(const std::chrono::time_point<_Clock, _Duration> & tp_, _Cb && cb_) | |||||
{ | |||||
return{ this, add(tp_, std::forward<_Cb>(cb_)) }; | |||||
} | |||||
bool stop(const timer_target_ptr & sptr); | |||||
inline bool empty() const | |||||
{ | |||||
return _runing_timers.empty() && _added_timers.empty(); | |||||
} | |||||
void clear(); | |||||
void update(); | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
template<class _Cb> | |||||
timer_target_ptr add_(const duration_type & dt_, _Cb && cb_) | |||||
{ | |||||
return add_(std::make_shared<timer_target>(clock_type::now() + dt_, std::forward<_Cb>(cb_))); | |||||
} | |||||
template<class _Cb> | |||||
timer_target_ptr add_(const time_point_type & tp_, _Cb && cb_) | |||||
{ | |||||
return add_(std::make_shared<timer_target>(tp_, std::forward<_Cb>(cb_))); | |||||
} | |||||
private: | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
spinlock _added_mtx; | |||||
#endif | |||||
timer_vector_type _added_timers; | |||||
timer_map_type _runing_timers; | |||||
timer_target_ptr add_(const timer_target_ptr & sptr); | |||||
static void call_target_(const timer_target_ptr & sptr, bool canceld); | |||||
#endif | |||||
}; | |||||
inline timer_handler::timer_handler(timer_manager * manager_, const detail::timer_target_ptr & target_) | |||||
: _manager(manager_->shared_from_this()) | |||||
, _target(target_) | |||||
{ | |||||
} | |||||
inline timer_handler::timer_handler(timer_handler && right_) noexcept | |||||
: _manager(std::move(right_._manager)) | |||||
, _target(std::move(right_._target)) | |||||
{ | |||||
} | |||||
inline timer_handler & timer_handler::operator = (timer_handler && right_) noexcept | |||||
{ | |||||
if (this != &right_) | |||||
{ | |||||
_manager = std::move(right_._manager); | |||||
_target = std::move(right_._target); | |||||
} | |||||
return *this; | |||||
} | |||||
inline void timer_handler::reset() | |||||
{ | |||||
_manager.reset(); | |||||
_target.reset(); | |||||
} | |||||
inline bool timer_handler::stop() | |||||
{ | |||||
bool result = false; | |||||
if (!_target.expired()) | |||||
{ | |||||
auto sptr = _manager.lock(); | |||||
if (sptr) | |||||
result = sptr->stop(_target.lock()); | |||||
_target.reset(); | |||||
} | |||||
_manager.reset(); | |||||
return result; | |||||
} | |||||
inline bool timer_handler::expired() const | |||||
{ | |||||
return _target.expired(); | |||||
} | |||||
#pragma once | |||||
namespace librf | |||||
{ | |||||
struct timer_manager; | |||||
typedef std::shared_ptr<timer_manager> timer_mgr_ptr; | |||||
typedef std::weak_ptr<timer_manager> timer_mgr_wptr; | |||||
namespace detail | |||||
{ | |||||
typedef std::chrono::system_clock timer_clock_type; | |||||
typedef std::function<void(bool)> timer_callback_type; | |||||
/** | |||||
* @brief 定时器对象。 | |||||
*/ | |||||
struct timer_target : public std::enable_shared_from_this<timer_target> | |||||
{ | |||||
friend timer_manager; | |||||
private: | |||||
enum struct State : uint32_t | |||||
{ | |||||
Invalid, | |||||
Added, | |||||
Runing, | |||||
}; | |||||
timer_clock_type::time_point tp; | |||||
timer_callback_type cb; | |||||
State st = State::Invalid; | |||||
#if _DEBUG | |||||
private: | |||||
timer_manager * _manager = nullptr; | |||||
#endif | |||||
public: | |||||
timer_target(const timer_clock_type::time_point & tp_, const timer_callback_type & cb_) | |||||
: tp(tp_) | |||||
, cb(cb_) | |||||
{ | |||||
} | |||||
timer_target(const timer_clock_type::time_point & tp_, timer_callback_type && cb_) | |||||
: tp(tp_) | |||||
, cb(std::forward<timer_callback_type>(cb_)) | |||||
{ | |||||
} | |||||
private: | |||||
timer_target() = delete; | |||||
timer_target(const timer_target &) = delete; | |||||
timer_target(timer_target && right_) = delete; | |||||
timer_target & operator = (const timer_target &) = delete; | |||||
timer_target & operator = (timer_target && right_) = delete; | |||||
}; | |||||
typedef std::shared_ptr<timer_target> timer_target_ptr; | |||||
typedef std::weak_ptr<timer_target> timer_target_wptr; | |||||
} | |||||
/** | |||||
* @brief 定时器句柄。 | |||||
* @details 对定时器对象和定时器管理器都采用弱引用。 | |||||
*/ | |||||
struct timer_handler | |||||
{ | |||||
private: | |||||
timer_mgr_wptr _manager; | |||||
detail::timer_target_wptr _target; | |||||
public: | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
timer_handler() = default; | |||||
timer_handler(const timer_handler &) = default; | |||||
timer_handler(timer_handler && right_) noexcept; | |||||
timer_handler & operator = (const timer_handler &) = default; | |||||
timer_handler & operator = (timer_handler && right_) noexcept; | |||||
#endif //DOXYGEN_SKIP_PROPERTY | |||||
timer_handler(timer_manager * manager_, const detail::timer_target_ptr & target_); | |||||
void reset(); | |||||
bool stop(); | |||||
bool expired() const; | |||||
}; | |||||
/** | |||||
* @brief 定时器管理器。 | |||||
*/ | |||||
struct timer_manager : public std::enable_shared_from_this<timer_manager> | |||||
{ | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
typedef detail::timer_target timer_target; | |||||
typedef detail::timer_target_ptr timer_target_ptr; | |||||
typedef detail::timer_clock_type clock_type; | |||||
typedef clock_type::duration duration_type; | |||||
typedef clock_type::time_point time_point_type; | |||||
typedef std::vector<timer_target_ptr> timer_vector_type; | |||||
typedef std::multimap<clock_type::time_point, timer_target_ptr> timer_map_type; | |||||
#endif | |||||
public: | |||||
timer_manager(); | |||||
~timer_manager(); | |||||
template<class _Rep, class _Period, class _Cb> | |||||
timer_target_ptr add(const std::chrono::duration<_Rep, _Period> & dt_, _Cb && cb_) | |||||
{ | |||||
return add_(std::chrono::duration_cast<duration_type>(dt_), std::forward<_Cb>(cb_)); | |||||
} | |||||
template<class _Clock, class _Duration = typename _Clock::duration, class _Cb> | |||||
timer_target_ptr add(const std::chrono::time_point<_Clock, _Duration> & tp_, _Cb && cb_) | |||||
{ | |||||
return add_(std::chrono::time_point_cast<duration_type>(tp_), std::forward<_Cb>(cb_)); | |||||
} | |||||
template<class _Rep, class _Period, class _Cb> | |||||
timer_handler add_handler(const std::chrono::duration<_Rep, _Period> & dt_, _Cb && cb_) | |||||
{ | |||||
return{ this, add(dt_, std::forward<_Cb>(cb_)) }; | |||||
} | |||||
template<class _Clock, class _Duration = typename _Clock::duration, class _Cb> | |||||
timer_handler add_handler(const std::chrono::time_point<_Clock, _Duration> & tp_, _Cb && cb_) | |||||
{ | |||||
return{ this, add(tp_, std::forward<_Cb>(cb_)) }; | |||||
} | |||||
bool stop(const timer_target_ptr & sptr); | |||||
inline bool empty() const | |||||
{ | |||||
return _runing_timers.empty() && _added_timers.empty(); | |||||
} | |||||
void clear(); | |||||
void update(); | |||||
#ifndef DOXYGEN_SKIP_PROPERTY | |||||
template<class _Cb> | |||||
timer_target_ptr add_(const duration_type & dt_, _Cb && cb_) | |||||
{ | |||||
return add_(std::make_shared<timer_target>(clock_type::now() + dt_, std::forward<_Cb>(cb_))); | |||||
} | |||||
template<class _Cb> | |||||
timer_target_ptr add_(const time_point_type & tp_, _Cb && cb_) | |||||
{ | |||||
return add_(std::make_shared<timer_target>(tp_, std::forward<_Cb>(cb_))); | |||||
} | |||||
private: | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
spinlock _added_mtx; | |||||
#endif | |||||
timer_vector_type _added_timers; | |||||
timer_map_type _runing_timers; | |||||
timer_target_ptr add_(const timer_target_ptr & sptr); | |||||
static void call_target_(const timer_target_ptr & sptr, bool canceld); | |||||
#endif | |||||
}; | |||||
inline timer_handler::timer_handler(timer_manager * manager_, const detail::timer_target_ptr & target_) | |||||
: _manager(manager_->shared_from_this()) | |||||
, _target(target_) | |||||
{ | |||||
} | |||||
inline timer_handler::timer_handler(timer_handler && right_) noexcept | |||||
: _manager(std::move(right_._manager)) | |||||
, _target(std::move(right_._target)) | |||||
{ | |||||
} | |||||
inline timer_handler & timer_handler::operator = (timer_handler && right_) noexcept | |||||
{ | |||||
if (this != &right_) | |||||
{ | |||||
_manager = std::move(right_._manager); | |||||
_target = std::move(right_._target); | |||||
} | |||||
return *this; | |||||
} | |||||
inline void timer_handler::reset() | |||||
{ | |||||
_manager.reset(); | |||||
_target.reset(); | |||||
} | |||||
inline bool timer_handler::stop() | |||||
{ | |||||
bool result = false; | |||||
if (!_target.expired()) | |||||
{ | |||||
auto sptr = _manager.lock(); | |||||
if (sptr) | |||||
result = sptr->stop(_target.lock()); | |||||
_target.reset(); | |||||
} | |||||
_manager.reset(); | |||||
return result; | |||||
} | |||||
inline bool timer_handler::expired() const | |||||
{ | |||||
return _target.expired(); | |||||
} | |||||
} | } |
#pragma once | |||||
#include <concepts> | |||||
namespace resumef | |||||
{ | |||||
template<typename T> | |||||
concept _AwaitorT = requires(T&& v) | |||||
{ | |||||
{ v.await_ready() } ->std::same_as<bool>; | |||||
{ v.await_suspend(std::declval<std::coroutine_handle<promise_t<>>>()) }; | |||||
{ 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> | |||||
concept _HasStateT = requires(T&& v) | |||||
{ | |||||
{ v._state }; | |||||
requires traits::is_state_pointer_v<decltype(v._state)>; | |||||
}; | |||||
template<typename T> | |||||
concept _FutureT = _AwaitorT<T> && _HasStateT<T> && requires | |||||
{ | |||||
{ T::value_type }; | |||||
{ T::state_type }; | |||||
{ T::promise_type }; | |||||
}; | |||||
template<typename T> | |||||
concept _CallableT = std::invocable<T>; | |||||
//template<typename T> | |||||
//concept _GeneratorT = std::is_same_v<T, generator_t<T>>; | |||||
template<typename T> | |||||
concept _AwaitableT = requires(T&& v) | |||||
{ | |||||
{ traits::get_awaitor(v) } ->_AwaitorT; | |||||
}; | |||||
template<typename T> | |||||
concept _WhenTaskT = _AwaitableT<T> || _CallableT<T>; | |||||
template<typename T> | |||||
concept _IteratorT = requires(T&& u, T&& v) | |||||
{ | |||||
{ ++u } ->std::common_with<T>; | |||||
{ u != v } ->std::same_as<bool>; | |||||
{ *u }; | |||||
}; | |||||
template<typename T, typename E> | |||||
concept _IteratorOfT = _IteratorT<T> && requires(T&& u) | |||||
{ | |||||
{ *u } ->std::common_with<E&>; | |||||
}; | |||||
template<typename T> | |||||
concept _WhenIterT = _IteratorT<T> && requires(T&& u) | |||||
{ | |||||
{ *u } ->_WhenTaskT; | |||||
}; | |||||
template<typename T> | |||||
concept _ContainerT = requires(T&& v) | |||||
{ | |||||
{ std::begin(v) } ->_IteratorT; | |||||
{ std::end(v) } ->_IteratorT; | |||||
requires std::same_as<decltype(std::begin(v)), decltype(std::end(v))>; | |||||
}; | |||||
template<typename T, typename E> | |||||
concept _ContainerOfT = _ContainerT<T> && requires(T&& v) | |||||
{ | |||||
{ *std::begin(v) } ->std::common_with<E&>; | |||||
//requires std::is_same_v<E, remove_cvref_t<decltype(*std::begin(v))>>; | |||||
}; | |||||
template<typename T> | |||||
concept _LockAssembleT = requires(T && v) | |||||
{ | |||||
{ v.size() }; | |||||
{ v[0] }; | |||||
{ v._Lock_ref(v[0]) }; | |||||
{ v._Try_lock_ref(v[0]) }; | |||||
{ v._Unlock_ref(v[0]) } ->std::same_as<void>; | |||||
{ v._Yield() }; | |||||
{ v._ReturnValue() }; | |||||
{ v._ReturnValue(0) }; | |||||
requires std::is_integral_v<decltype(v.size())>; | |||||
}; | |||||
} | |||||
#pragma once | |||||
#include <concepts> | |||||
namespace librf | |||||
{ | |||||
template<typename T> | |||||
concept _AwaitorT = requires(T&& v) | |||||
{ | |||||
{ v.await_ready() } ->std::same_as<bool>; | |||||
{ v.await_suspend(std::declval<std::coroutine_handle<promise_t<>>>()) }; | |||||
{ 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> | |||||
concept _HasStateT = requires(T&& v) | |||||
{ | |||||
{ v._state }; | |||||
requires traits::is_state_pointer_v<decltype(v._state)>; | |||||
}; | |||||
template<typename T> | |||||
concept _FutureT = _AwaitorT<T> && _HasStateT<T> && requires | |||||
{ | |||||
{ T::value_type }; | |||||
{ T::state_type }; | |||||
{ T::promise_type }; | |||||
}; | |||||
template<typename T> | |||||
concept _CallableT = std::invocable<T>; | |||||
//template<typename T> | |||||
//concept _GeneratorT = std::is_same_v<T, generator_t<T>>; | |||||
template<typename T> | |||||
concept _AwaitableT = requires(T&& v) | |||||
{ | |||||
{ traits::get_awaitor(v) } ->_AwaitorT; | |||||
}; | |||||
template<typename T> | |||||
concept _WhenTaskT = _AwaitableT<T> || _CallableT<T>; | |||||
template<typename T> | |||||
concept _IteratorT = requires(T&& u, T&& v) | |||||
{ | |||||
{ ++u } ->std::common_with<T>; | |||||
{ u != v } ->std::same_as<bool>; | |||||
{ *u }; | |||||
}; | |||||
template<typename T, typename E> | |||||
concept _IteratorOfT = _IteratorT<T> && requires(T&& u) | |||||
{ | |||||
{ *u } ->std::common_with<E&>; | |||||
}; | |||||
template<typename T> | |||||
concept _WhenIterT = _IteratorT<T> && requires(T&& u) | |||||
{ | |||||
{ *u } ->_WhenTaskT; | |||||
}; | |||||
template<typename T> | |||||
concept _ContainerT = requires(T&& v) | |||||
{ | |||||
{ std::begin(v) } ->_IteratorT; | |||||
{ std::end(v) } ->_IteratorT; | |||||
requires std::same_as<decltype(std::begin(v)), decltype(std::end(v))>; | |||||
}; | |||||
template<typename T, typename E> | |||||
concept _ContainerOfT = _ContainerT<T> && requires(T&& v) | |||||
{ | |||||
{ *std::begin(v) } ->std::common_with<E&>; | |||||
//requires std::is_same_v<E, remove_cvref_t<decltype(*std::begin(v))>>; | |||||
}; | |||||
template<typename T> | |||||
concept _LockAssembleT = requires(T && v) | |||||
{ | |||||
{ v.size() }; | |||||
{ v[0] }; | |||||
{ v._Lock_ref(v[0]) }; | |||||
{ v._Try_lock_ref(v[0]) }; | |||||
{ v._Unlock_ref(v[0]) } ->std::same_as<void>; | |||||
{ v._Yield() }; | |||||
{ v._ReturnValue() }; | |||||
{ v._ReturnValue(0) }; | |||||
requires std::is_integral_v<decltype(v.size())>; | |||||
}; | |||||
} |
#pragma once | |||||
锘�#pragma once | |||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
namespace traits | namespace traits | ||||
{ | { | ||||
//is_coroutine_handle<T> | //is_coroutine_handle<T> | ||||
//is_coroutine_handle_v<T> | //is_coroutine_handle_v<T> | ||||
//判断是不是coroutine_handle<>类型 | |||||
//鍒ゆ柇鏄�笉鏄痗oroutine_handle<>绫诲瀷 | |||||
// | // | ||||
//is_valid_await_suspend_return_v<T> | //is_valid_await_suspend_return_v<T> | ||||
//判断是不是awaitor的await_suspend()函数的有效返回值 | |||||
//鍒ゆ柇鏄�笉鏄痑waitor鐨刟wait_suspend()鍑芥暟鐨勬湁鏁堣繑鍥炲€� | |||||
// | // | ||||
//is_awaitor<T> | //is_awaitor<T> | ||||
//is_awaitor_v<T> | //is_awaitor_v<T> | ||||
//判断是不是一个awaitor规范。 | |||||
//一个awaitor可以被co_await操作,要求满足coroutine的awaitor的三个函数接口规范 | |||||
//鍒ゆ柇鏄�笉鏄�竴涓猘waitor瑙勮寖銆� | |||||
//涓€涓猘waitor鍙�互琚玞o_await鎿嶄綔锛岃�姹傛弧瓒砪oroutine鐨刟waitor鐨勪笁涓�嚱鏁版帴鍙h�鑼� | |||||
// | // | ||||
//is_future<T> | //is_future<T> | ||||
//is_future_v<T> | //is_future_v<T> | ||||
//判断是不是一个librf的future规范。 | |||||
//future除了要求是一个awaitor外,还要求定义了value_type/state_type/promise_type三个类型, | |||||
//并且具备counted_ptr<state_type>类型的_state变量。 | |||||
//鍒ゆ柇鏄�笉鏄�竴涓猯ibrf鐨刦uture瑙勮寖銆� | |||||
//future闄や簡瑕佹眰鏄�竴涓猘waitor澶栵紝杩樿�姹傚畾涔変簡value_type/state_type/promise_type涓変釜绫诲瀷锛� | |||||
//骞朵笖鍏峰�counted_ptr<state_type>绫诲瀷鐨刜state鍙橀噺銆� | |||||
// | // | ||||
//is_promise<T> | //is_promise<T> | ||||
//is_promise_v<T> | //is_promise_v<T> | ||||
//判断是不是一个librf的promise_t类 | |||||
//鍒ゆ柇鏄�笉鏄�竴涓猯ibrf鐨刾romise_t绫� | |||||
// | // | ||||
//is_generator<T> | //is_generator<T> | ||||
//is_generator_v<T> | //is_generator_v<T> | ||||
//判断是不是一个librf的generator_t类 | |||||
//鍒ゆ柇鏄�笉鏄�竴涓猯ibrf鐨刧enerator_t绫� | |||||
// | // | ||||
//is_state_pointer<T> | //is_state_pointer<T> | ||||
//is_state_pointer_v<T> | //is_state_pointer_v<T> | ||||
//判断是不是一个librf的state_t类的指针或智能指针 | |||||
//鍒ゆ柇鏄�笉鏄�竴涓猯ibrf鐨剆tate_t绫荤殑鎸囬拡鎴栨櫤鑳芥寚閽� | |||||
// | // | ||||
//has_state<T> | //has_state<T> | ||||
//has_state_v<T> | //has_state_v<T> | ||||
//判断是否具有_state的成员变量 | |||||
//鍒ゆ柇鏄�惁鍏锋湁_state鐨勬垚鍛樺彉閲� | |||||
// | // | ||||
//get_awaitor<T>(T&&t) | //get_awaitor<T>(T&&t) | ||||
//通过T获得其被co_await后的awaitor | |||||
//閫氳繃T鑾峰緱鍏惰�co_await鍚庣殑awaitor | |||||
// | // | ||||
//awaitor_traits<T> | //awaitor_traits<T> | ||||
//获得一个awaitor的特征。 | |||||
// type:awaitor的类型 | |||||
// value_type:awaitor::await_resume()的返回值类型 | |||||
//鑾峰緱涓€涓猘waitor鐨勭壒寰併€� | |||||
// type:awaitor鐨勭被鍨� | |||||
// value_type:awaitor::await_resume()鐨勮繑鍥炲€肩被鍨� | |||||
// | // | ||||
//is_awaitable<T> | //is_awaitable<T> | ||||
//is_awaitable_v<T> | //is_awaitable_v<T> | ||||
//判断是否可以被co_await操作。可以是一个awaitor,也可以是重载了成员变量的T::operator co_await(),或者被重载了全局的operator co_awaitor(T) | |||||
//鍒ゆ柇鏄�惁鍙�互琚玞o_await鎿嶄綔銆傚彲浠ユ槸涓€涓猘waitor锛屼篃鍙�互鏄�噸杞戒簡鎴愬憳鍙橀噺鐨凾::operator co_await()锛屾垨鑰呰�閲嶈浇浜嗗叏灞€鐨刼perator co_awaitor(T) | |||||
// | // | ||||
//is_callable<T> | //is_callable<T> | ||||
//is_callable_v<T> | //is_callable_v<T> | ||||
//判断是不是一个可被调用的类型,如函数,仿函数,lambda等 | |||||
//鍒ゆ柇鏄�笉鏄�竴涓�彲琚�皟鐢ㄧ殑绫诲瀷锛屽�鍑芥暟锛屼豢鍑芥暟锛宭ambda绛� | |||||
// | // | ||||
//is_iterator<T> | //is_iterator<T> | ||||
//is_iterator_v<T> | //is_iterator_v<T> | ||||
//判断是不是一个支持向后迭代的迭代器 | |||||
//鍒ゆ柇鏄�笉鏄�竴涓�敮鎸佸悜鍚庤凯浠g殑杩�唬鍣� | |||||
// | // | ||||
//is_iterator_of_v<T, E> | //is_iterator_of_v<T, E> | ||||
//判断是不是一个支持向后迭代的迭代器,并且迭代器通过 operator *()返回的类型是 E&。 | |||||
//鍒ゆ柇鏄�笉鏄�竴涓�敮鎸佸悜鍚庤凯浠g殑杩�唬鍣�紝骞朵笖杩�唬鍣ㄩ€氳繃 operator *()杩斿洖鐨勭被鍨嬫槸 E&銆� | |||||
// | // | ||||
//is_container<T> | //is_container<T> | ||||
//is_container_v<T> | //is_container_v<T> | ||||
//判断是不是一个封闭区间的容器,或者数组。 | |||||
//鍒ゆ柇鏄�笉鏄�竴涓�皝闂�尯闂寸殑瀹瑰櫒锛屾垨鑰呮暟缁勩€� | |||||
// | // | ||||
//is_container_of<T, E> | //is_container_of<T, E> | ||||
//is_container_of_v<T, E> | //is_container_of_v<T, E> | ||||
//判断是不是一个封闭区间的容器,或者数组。其元素类型是E。 | |||||
//鍒ゆ柇鏄�笉鏄�竴涓�皝闂�尯闂寸殑瀹瑰櫒锛屾垨鑰呮暟缁勩€傚叾鍏冪礌绫诲瀷鏄疎銆� | |||||
template<class _Ty> | template<class _Ty> | ||||
struct is_coroutine_handle : std::false_type {}; | struct is_coroutine_handle : std::false_type {}; |
#pragma once | |||||
//#include "when_v1.h" | |||||
#include "when_v2.h" | |||||
#pragma once | |||||
//#include "when_v1.h" | |||||
#include "when_v2.h" |
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
using any_t = std::any; | using any_t = std::any; | ||||
using std::any_cast; | using std::any_cast; | ||||
//最最重要的,要统一ranged when_any的返回值,还得做一个运行时通过下标设置std::variant<>的东西 | //最最重要的,要统一ranged when_any的返回值,还得做一个运行时通过下标设置std::variant<>的东西 | ||||
//std::any除了内存布局不太理想,其他方面几乎没缺点(在此应用下) | //std::any除了内存布局不太理想,其他方面几乎没缺点(在此应用下) | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
#ifndef DOXYGEN_SKIP_PROPERTY | #ifndef DOXYGEN_SKIP_PROPERTY | ||||
using when_any_pair = std::pair<intptr_t, any_t>; | using when_any_pair = std::pair<intptr_t, any_t>; |
| |||||
struct LOCK_ASSEMBLE_NAME(lock_impl) | |||||
{ | |||||
// FUNCTION TEMPLATE _Unlock_locks | |||||
template<_LockAssembleT _LA> | |||||
static void _Unlock_locks(int _First, int _Last, _LA& _LkN) noexcept /* terminates */ | |||||
{ | |||||
for (; _First != _Last; ++_First) { | |||||
_LkN._Unlock_ref(_LkN[_First]); | |||||
} | |||||
} | |||||
// FUNCTION TEMPLATE try_lock | |||||
template<_LockAssembleT _LA> | |||||
static auto _Try_lock_range(const int _First, const int _Last, _LA& _LkN) | |||||
->decltype(_LkN._ReturnValue(123)) | |||||
{ | |||||
int _Next = _First; | |||||
try { | |||||
for (; _Next != _Last; ++_Next) | |||||
{ | |||||
auto _Result__ = LOCK_ASSEMBLE_AWAIT(_LkN._Try_lock_ref(_LkN[_Next])); | |||||
if (!_Result__) | |||||
{ // try_lock failed, backout | |||||
_Unlock_locks(_First, _Next, _LkN); | |||||
LOCK_ASSEMBLE_RETURN(_Next); | |||||
} | |||||
} | |||||
} | |||||
catch (...) { | |||||
_Unlock_locks(_First, _Next, _LkN); | |||||
throw; | |||||
} | |||||
LOCK_ASSEMBLE_RETURN(-1); | |||||
} | |||||
// FUNCTION TEMPLATE lock | |||||
template<_LockAssembleT _LA> | |||||
static auto _Lock_attempt(const int _Hard_lock, _LA& _LkN) | |||||
->decltype(_LkN._ReturnValue(123)) | |||||
{ | |||||
// attempt to lock 3 or more locks, starting by locking _LkN[_Hard_lock] and trying to lock the rest | |||||
LOCK_ASSEMBLE_AWAIT(_LkN._Lock_ref(_LkN[_Hard_lock])); | |||||
int _Failed = -1; | |||||
int _Backout_start = _Hard_lock; // that is, unlock _Hard_lock | |||||
try { | |||||
_Failed = LOCK_ASSEMBLE_AWAIT(_Try_lock_range(0, _Hard_lock, _LkN)); | |||||
if (_Failed == -1) | |||||
{ | |||||
_Backout_start = 0; // that is, unlock [0, _Hard_lock] if the next throws | |||||
_Failed = LOCK_ASSEMBLE_AWAIT(_Try_lock_range(_Hard_lock + 1, (int)_LkN.size(), _LkN)); | |||||
if (_Failed == -1) { // we got all the locks | |||||
LOCK_ASSEMBLE_RETURN(-1); | |||||
} | |||||
} | |||||
} | |||||
catch (...) { | |||||
_Unlock_locks(_Backout_start, _Hard_lock + 1, _LkN); | |||||
throw; | |||||
} | |||||
// we didn't get all the locks, backout | |||||
_Unlock_locks(_Backout_start, _Hard_lock + 1, _LkN); | |||||
LOCK_ASSEMBLE_AWAIT(_LkN._Yield()); | |||||
LOCK_ASSEMBLE_RETURN(_Failed); | |||||
} | |||||
template<_LockAssembleT _LA> | |||||
static auto _Lock_nonmember3(_LA& _LkN) ->decltype(_LkN._ReturnValue()) | |||||
{ | |||||
// lock 3 or more locks, without deadlock | |||||
int _Hard_lock = 0; | |||||
while (_Hard_lock != -1) { | |||||
_Hard_lock = LOCK_ASSEMBLE_AWAIT(_Lock_attempt(_Hard_lock, _LkN)); | |||||
} | |||||
} | |||||
template<_LockAssembleT _LA> | |||||
static auto _Lock_attempt_small2(_LA& _LkN, const int _Idx0, const int _Idx1) | |||||
->decltype(_LkN._ReturnValue(false)) | |||||
{ | |||||
// attempt to lock 2 locks, by first locking _Lk0, and then trying to lock _Lk1 returns whether to try again | |||||
LOCK_ASSEMBLE_AWAIT(_LkN._Lock_ref(_LkN[_Idx0])); | |||||
try { | |||||
auto _Result__ = LOCK_ASSEMBLE_AWAIT(_LkN._Try_lock_ref(_LkN[_Idx1])); | |||||
if (_Result__) | |||||
LOCK_ASSEMBLE_RETURN(false); | |||||
} | |||||
catch (...) { | |||||
_LkN._Unlock_ref(_LkN[_Idx0]); | |||||
throw; | |||||
} | |||||
_LkN._Unlock_ref(_LkN[_Idx0]); | |||||
LOCK_ASSEMBLE_AWAIT(_LkN._Yield()); | |||||
LOCK_ASSEMBLE_RETURN(true); | |||||
} | |||||
template<_LockAssembleT _LA> | |||||
static auto _Lock_nonmember2(_LA& _LkN) ->decltype(_LkN._ReturnValue()) | |||||
{ | |||||
// lock 2 locks, without deadlock, special case for better codegen and reduced metaprogramming for common case | |||||
for (;;) | |||||
{ | |||||
auto _Result__ = LOCK_ASSEMBLE_AWAIT(_Lock_attempt_small2(_LkN, 0, 1)); | |||||
if (!_Result__) break; | |||||
_Result__ = LOCK_ASSEMBLE_AWAIT(_Lock_attempt_small2(_LkN, 1, 0)); | |||||
if (!_Result__) break; | |||||
} | |||||
} | |||||
template<_LockAssembleT _LA> | |||||
static auto _Lock_range(_LA& lockes) ->decltype(lockes._ReturnValue()) | |||||
{ | |||||
if (lockes.size() == 0) | |||||
{ | |||||
} | |||||
else if (lockes.size() == 1) | |||||
{ | |||||
LOCK_ASSEMBLE_AWAIT(lockes._Lock_ref(lockes[0])); | |||||
} | |||||
else if (lockes.size() == 2) | |||||
{ | |||||
(void)LOCK_ASSEMBLE_AWAIT(_Lock_nonmember2(lockes)); | |||||
} | |||||
else | |||||
{ | |||||
(void)LOCK_ASSEMBLE_AWAIT(_Lock_nonmember3(lockes)); | |||||
} | |||||
} | |||||
}; | |||||
| |||||
struct LOCK_ASSEMBLE_NAME(lock_impl) | |||||
{ | |||||
// FUNCTION TEMPLATE _Unlock_locks | |||||
template<_LockAssembleT _LA> | |||||
static void _Unlock_locks(int _First, int _Last, _LA& _LkN) noexcept /* terminates */ | |||||
{ | |||||
for (; _First != _Last; ++_First) { | |||||
_LkN._Unlock_ref(_LkN[_First]); | |||||
} | |||||
} | |||||
// FUNCTION TEMPLATE try_lock | |||||
template<_LockAssembleT _LA> | |||||
static auto _Try_lock_range(const int _First, const int _Last, _LA& _LkN) | |||||
->decltype(_LkN._ReturnValue(123)) | |||||
{ | |||||
int _Next = _First; | |||||
try { | |||||
for (; _Next != _Last; ++_Next) | |||||
{ | |||||
auto _Result__ = LOCK_ASSEMBLE_AWAIT(_LkN._Try_lock_ref(_LkN[_Next])); | |||||
if (!_Result__) | |||||
{ // try_lock failed, backout | |||||
_Unlock_locks(_First, _Next, _LkN); | |||||
LOCK_ASSEMBLE_RETURN(_Next); | |||||
} | |||||
} | |||||
} | |||||
catch (...) { | |||||
_Unlock_locks(_First, _Next, _LkN); | |||||
throw; | |||||
} | |||||
LOCK_ASSEMBLE_RETURN(-1); | |||||
} | |||||
// FUNCTION TEMPLATE lock | |||||
template<_LockAssembleT _LA> | |||||
static auto _Lock_attempt(const int _Hard_lock, _LA& _LkN) | |||||
->decltype(_LkN._ReturnValue(123)) | |||||
{ | |||||
// attempt to lock 3 or more locks, starting by locking _LkN[_Hard_lock] and trying to lock the rest | |||||
LOCK_ASSEMBLE_AWAIT(_LkN._Lock_ref(_LkN[_Hard_lock])); | |||||
int _Failed = -1; | |||||
int _Backout_start = _Hard_lock; // that is, unlock _Hard_lock | |||||
try { | |||||
_Failed = LOCK_ASSEMBLE_AWAIT(_Try_lock_range(0, _Hard_lock, _LkN)); | |||||
if (_Failed == -1) | |||||
{ | |||||
_Backout_start = 0; // that is, unlock [0, _Hard_lock] if the next throws | |||||
_Failed = LOCK_ASSEMBLE_AWAIT(_Try_lock_range(_Hard_lock + 1, (int)_LkN.size(), _LkN)); | |||||
if (_Failed == -1) { // we got all the locks | |||||
LOCK_ASSEMBLE_RETURN(-1); | |||||
} | |||||
} | |||||
} | |||||
catch (...) { | |||||
_Unlock_locks(_Backout_start, _Hard_lock + 1, _LkN); | |||||
throw; | |||||
} | |||||
// we didn't get all the locks, backout | |||||
_Unlock_locks(_Backout_start, _Hard_lock + 1, _LkN); | |||||
LOCK_ASSEMBLE_AWAIT(_LkN._Yield()); | |||||
LOCK_ASSEMBLE_RETURN(_Failed); | |||||
} | |||||
template<_LockAssembleT _LA> | |||||
static auto _Lock_nonmember3(_LA& _LkN) ->decltype(_LkN._ReturnValue()) | |||||
{ | |||||
// lock 3 or more locks, without deadlock | |||||
int _Hard_lock = 0; | |||||
while (_Hard_lock != -1) { | |||||
_Hard_lock = LOCK_ASSEMBLE_AWAIT(_Lock_attempt(_Hard_lock, _LkN)); | |||||
} | |||||
} | |||||
template<_LockAssembleT _LA> | |||||
static auto _Lock_attempt_small2(_LA& _LkN, const int _Idx0, const int _Idx1) | |||||
->decltype(_LkN._ReturnValue(false)) | |||||
{ | |||||
// attempt to lock 2 locks, by first locking _Lk0, and then trying to lock _Lk1 returns whether to try again | |||||
LOCK_ASSEMBLE_AWAIT(_LkN._Lock_ref(_LkN[_Idx0])); | |||||
try { | |||||
auto _Result__ = LOCK_ASSEMBLE_AWAIT(_LkN._Try_lock_ref(_LkN[_Idx1])); | |||||
if (_Result__) | |||||
LOCK_ASSEMBLE_RETURN(false); | |||||
} | |||||
catch (...) { | |||||
_LkN._Unlock_ref(_LkN[_Idx0]); | |||||
throw; | |||||
} | |||||
_LkN._Unlock_ref(_LkN[_Idx0]); | |||||
LOCK_ASSEMBLE_AWAIT(_LkN._Yield()); | |||||
LOCK_ASSEMBLE_RETURN(true); | |||||
} | |||||
template<_LockAssembleT _LA> | |||||
static auto _Lock_nonmember2(_LA& _LkN) ->decltype(_LkN._ReturnValue()) | |||||
{ | |||||
// lock 2 locks, without deadlock, special case for better codegen and reduced metaprogramming for common case | |||||
for (;;) | |||||
{ | |||||
auto _Result__ = LOCK_ASSEMBLE_AWAIT(_Lock_attempt_small2(_LkN, 0, 1)); | |||||
if (!_Result__) break; | |||||
_Result__ = LOCK_ASSEMBLE_AWAIT(_Lock_attempt_small2(_LkN, 1, 0)); | |||||
if (!_Result__) break; | |||||
} | |||||
} | |||||
template<_LockAssembleT _LA> | |||||
static auto _Lock_range(_LA& lockes) ->decltype(lockes._ReturnValue()) | |||||
{ | |||||
if (lockes.size() == 0) | |||||
{ | |||||
} | |||||
else if (lockes.size() == 1) | |||||
{ | |||||
LOCK_ASSEMBLE_AWAIT(lockes._Lock_ref(lockes[0])); | |||||
} | |||||
else if (lockes.size() == 2) | |||||
{ | |||||
(void)LOCK_ASSEMBLE_AWAIT(_Lock_nonmember2(lockes)); | |||||
} | |||||
else | |||||
{ | |||||
(void)LOCK_ASSEMBLE_AWAIT(_Lock_nonmember3(lockes)); | |||||
} | |||||
} | |||||
}; | |||||
#pragma once | #pragma once | ||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
/** | /** | ||||
* @brief 将本协程让渡出一次调用的可等待对象。 | * @brief 将本协程让渡出一次调用的可等待对象。 | ||||
/** | /** | ||||
* @brief 将本协程让渡出一次调用的可等待对象。 | * @brief 将本协程让渡出一次调用的可等待对象。 | ||||
* @return [co_await] void | * @return [co_await] void | ||||
* @note 本函数是resumef名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 yield_awaitor 类下。 | |||||
* @note 本函数是librf名字空间下的全局函数。由于doxygen使用上的问题,将之归纳到 yield_awaitor 类下。 | |||||
*/ | */ | ||||
static yield_awaitor yield() noexcept; | static yield_awaitor yield() noexcept; | ||||
#endif //DOXYGEN_SKIP_PROPERTY | #endif //DOXYGEN_SKIP_PROPERTY |
Subproject commit db31c6b762e898688d84ed6aea43442cd46e1176 | |||||
Subproject commit aa00d93f9fd1cfb3cd114b4e0984b2b35d259e18 |
#include "../librf.h" | |||||
#include "librf/librf.h" | |||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
namespace detail | namespace detail | ||||
{ | { |
#include "../librf.h" | |||||
#include "librf/librf.h" | |||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
namespace detail | namespace detail | ||||
{ | { |
#include "../librf.h" | |||||
namespace resumef | |||||
{ | |||||
task_t::task_t() noexcept | |||||
: _stop(nostopstate) | |||||
{ | |||||
} | |||||
task_t::~task_t() | |||||
{ | |||||
} | |||||
const stop_source & task_t::get_stop_source() | |||||
{ | |||||
_stop.make_sure_possible(); | |||||
return _stop; | |||||
} | |||||
} | |||||
#include "librf/librf.h" | |||||
namespace librf | |||||
{ | |||||
task_t::task_t() noexcept | |||||
: _stop(nostopstate) | |||||
{ | |||||
} | |||||
task_t::~task_t() | |||||
{ | |||||
} | |||||
const stop_source & task_t::get_stop_source() | |||||
{ | |||||
_stop.make_sure_possible(); | |||||
return _stop; | |||||
} | |||||
} |
#include "../librf.h" | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::mutex g_resumef_cout_mutex; | |||||
std::atomic<intptr_t> g_resumef_state_count = 0; | |||||
std::atomic<intptr_t> g_resumef_task_count = 0; | |||||
std::atomic<intptr_t> g_resumef_evtctx_count = 0; | |||||
std::atomic<intptr_t> g_resumef_state_id = 0; | |||||
#endif | |||||
namespace resumef | |||||
{ | |||||
const char * future_error_string[(size_t)error_code::max__] | |||||
{ | |||||
"none", | |||||
"not_ready", | |||||
"already_acquired", | |||||
"unlock_more", | |||||
"read_before_write", | |||||
"timer_canceled", | |||||
"not_await_lock", | |||||
"stop_requested", | |||||
}; | |||||
char sz_future_error_buffer[256]; | |||||
const char * get_error_string(error_code fe, const char * classname) | |||||
{ | |||||
if (classname) | |||||
{ | |||||
#if defined(__clang__) || defined(__GNUC__) | |||||
#define sprintf_s sprintf | |||||
#endif | |||||
sprintf_s(sz_future_error_buffer, "%s, code=%s", classname, future_error_string[(size_t)(fe)]); | |||||
return sz_future_error_buffer; | |||||
} | |||||
return future_error_string[(size_t)(fe)]; | |||||
} | |||||
thread_local scheduler_t * th_scheduler_ptr = nullptr; | |||||
//获得当前线程下的调度器 | |||||
scheduler_t * this_scheduler() | |||||
{ | |||||
return th_scheduler_ptr ? th_scheduler_ptr : &scheduler_t::g_scheduler; | |||||
} | |||||
local_scheduler_t::local_scheduler_t() | |||||
{ | |||||
if (th_scheduler_ptr == nullptr) | |||||
{ | |||||
_scheduler_ptr = new scheduler_t; | |||||
th_scheduler_ptr = _scheduler_ptr; | |||||
} | |||||
else | |||||
{ | |||||
_scheduler_ptr = nullptr; | |||||
} | |||||
} | |||||
local_scheduler_t::local_scheduler_t(scheduler_t& sch) noexcept | |||||
{ | |||||
if (th_scheduler_ptr == nullptr) | |||||
{ | |||||
th_scheduler_ptr = &sch; | |||||
} | |||||
_scheduler_ptr = nullptr; | |||||
} | |||||
local_scheduler_t::~local_scheduler_t() | |||||
{ | |||||
if (th_scheduler_ptr == _scheduler_ptr) | |||||
th_scheduler_ptr = nullptr; | |||||
delete _scheduler_ptr; | |||||
} | |||||
scheduler_t::scheduler_t() | |||||
: _timer(std::make_shared<timer_manager>()) | |||||
{ | |||||
_runing_states.reserve(1024); | |||||
_cached_states.reserve(1024); | |||||
if (th_scheduler_ptr == nullptr) | |||||
th_scheduler_ptr = this; | |||||
} | |||||
scheduler_t::~scheduler_t() | |||||
{ | |||||
//cancel_all_task_(); | |||||
if (th_scheduler_ptr == this) | |||||
th_scheduler_ptr = nullptr; | |||||
} | |||||
task_t* scheduler_t::new_task(task_t * task) | |||||
{ | |||||
state_base_t* sptr = task->_state.get(); | |||||
sptr->set_scheduler(this); | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
_ready_task.emplace(sptr, task); | |||||
} | |||||
//如果是单独的future,没有被co_await过,则handler是nullptr。 | |||||
if (sptr->has_handler()) | |||||
{ | |||||
add_generator(sptr); | |||||
} | |||||
return task; | |||||
} | |||||
std::unique_ptr<task_t> scheduler_t::del_switch(state_base_t* sptr) | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
std::unique_ptr<task_t> task_ptr; | |||||
auto iter = this->_ready_task.find(sptr); | |||||
if (iter != this->_ready_task.end()) | |||||
{ | |||||
task_ptr = std::exchange(iter->second, nullptr); | |||||
this->_ready_task.erase(iter); | |||||
} | |||||
return task_ptr; | |||||
} | |||||
/* | |||||
void scheduler_t::cancel_all_task_() | |||||
{ | |||||
scoped_lock<spinlock, spinlock> __guard(_lock_ready, _lock_running); | |||||
this->_ready_task.clear(); | |||||
this->_runing_states.clear(); | |||||
} | |||||
void scheduler_t::break_all() | |||||
{ | |||||
cancel_all_task_(); | |||||
this->_timer->clear(); | |||||
} | |||||
*/ | |||||
bool scheduler_t::run_one_batch() | |||||
{ | |||||
this->_timer->update(); | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_running); | |||||
#endif | |||||
if (likely(_runing_states.empty())) | |||||
return false; | |||||
std::swap(_cached_states, _runing_states); | |||||
} | |||||
for (state_sptr& sptr : _cached_states) | |||||
sptr->resume(); | |||||
_cached_states.clear(); | |||||
return true; | |||||
} | |||||
void scheduler_t::run_until_notask() | |||||
{ | |||||
for(;;) | |||||
{ | |||||
//介于网上有人做评测,导致单协程切换数据很难看,那就注释掉吧。 | |||||
//std::this_thread::yield(); | |||||
if (likely(this->run_one_batch())) continue; //当前运行了一个state,则认为还可能有任务未完成 | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
if (likely(!_ready_task.empty())) continue; //当前还存在task,则必然还有任务未完成 | |||||
} | |||||
if (unlikely(!_timer->empty())) continue; //定时器不为空,也需要等待定时器触发 | |||||
break; | |||||
}; | |||||
} | |||||
scheduler_t scheduler_t::g_scheduler; | |||||
} | |||||
#include "librf/librf.h" | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::mutex g_resumef_cout_mutex; | |||||
std::atomic<intptr_t> g_resumef_state_count = 0; | |||||
std::atomic<intptr_t> g_resumef_task_count = 0; | |||||
std::atomic<intptr_t> g_resumef_evtctx_count = 0; | |||||
std::atomic<intptr_t> g_resumef_state_id = 0; | |||||
#endif | |||||
namespace librf | |||||
{ | |||||
const char * future_error_string[(size_t)error_code::max__] | |||||
{ | |||||
"none", | |||||
"not_ready", | |||||
"already_acquired", | |||||
"unlock_more", | |||||
"read_before_write", | |||||
"timer_canceled", | |||||
"not_await_lock", | |||||
"stop_requested", | |||||
}; | |||||
char sz_future_error_buffer[256]; | |||||
const char * get_error_string(error_code fe, const char * classname) | |||||
{ | |||||
if (classname) | |||||
{ | |||||
#if defined(__clang__) || defined(__GNUC__) | |||||
#define sprintf_s sprintf | |||||
#endif | |||||
sprintf_s(sz_future_error_buffer, "%s, code=%s", classname, future_error_string[(size_t)(fe)]); | |||||
return sz_future_error_buffer; | |||||
} | |||||
return future_error_string[(size_t)(fe)]; | |||||
} | |||||
thread_local scheduler_t * th_scheduler_ptr = nullptr; | |||||
//获得当前线程下的调度器 | |||||
scheduler_t * this_scheduler() | |||||
{ | |||||
return th_scheduler_ptr ? th_scheduler_ptr : &scheduler_t::g_scheduler; | |||||
} | |||||
local_scheduler_t::local_scheduler_t() | |||||
{ | |||||
if (th_scheduler_ptr == nullptr) | |||||
{ | |||||
_scheduler_ptr = new scheduler_t; | |||||
th_scheduler_ptr = _scheduler_ptr; | |||||
} | |||||
else | |||||
{ | |||||
_scheduler_ptr = nullptr; | |||||
} | |||||
} | |||||
local_scheduler_t::local_scheduler_t(scheduler_t& sch) noexcept | |||||
{ | |||||
if (th_scheduler_ptr == nullptr) | |||||
{ | |||||
th_scheduler_ptr = &sch; | |||||
} | |||||
_scheduler_ptr = nullptr; | |||||
} | |||||
local_scheduler_t::~local_scheduler_t() | |||||
{ | |||||
if (th_scheduler_ptr == _scheduler_ptr) | |||||
th_scheduler_ptr = nullptr; | |||||
delete _scheduler_ptr; | |||||
} | |||||
scheduler_t::scheduler_t() | |||||
: _timer(std::make_shared<timer_manager>()) | |||||
{ | |||||
_runing_states.reserve(1024); | |||||
_cached_states.reserve(1024); | |||||
if (th_scheduler_ptr == nullptr) | |||||
th_scheduler_ptr = this; | |||||
} | |||||
scheduler_t::~scheduler_t() | |||||
{ | |||||
//cancel_all_task_(); | |||||
if (th_scheduler_ptr == this) | |||||
th_scheduler_ptr = nullptr; | |||||
} | |||||
task_t* scheduler_t::new_task(task_t * task) | |||||
{ | |||||
state_base_t* sptr = task->_state.get(); | |||||
sptr->set_scheduler(this); | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
_ready_task.emplace(sptr, task); | |||||
} | |||||
//如果是单独的future,没有被co_await过,则handler是nullptr。 | |||||
if (sptr->has_handler()) | |||||
{ | |||||
add_generator(sptr); | |||||
} | |||||
return task; | |||||
} | |||||
std::unique_ptr<task_t> scheduler_t::del_switch(state_base_t* sptr) | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
std::unique_ptr<task_t> task_ptr; | |||||
auto iter = this->_ready_task.find(sptr); | |||||
if (iter != this->_ready_task.end()) | |||||
{ | |||||
task_ptr = std::exchange(iter->second, nullptr); | |||||
this->_ready_task.erase(iter); | |||||
} | |||||
return task_ptr; | |||||
} | |||||
/* | |||||
void scheduler_t::cancel_all_task_() | |||||
{ | |||||
scoped_lock<spinlock, spinlock> __guard(_lock_ready, _lock_running); | |||||
this->_ready_task.clear(); | |||||
this->_runing_states.clear(); | |||||
} | |||||
void scheduler_t::break_all() | |||||
{ | |||||
cancel_all_task_(); | |||||
this->_timer->clear(); | |||||
} | |||||
*/ | |||||
bool scheduler_t::run_one_batch() | |||||
{ | |||||
this->_timer->update(); | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_running); | |||||
#endif | |||||
if (likely(_runing_states.empty())) | |||||
return false; | |||||
std::swap(_cached_states, _runing_states); | |||||
} | |||||
for (state_sptr& sptr : _cached_states) | |||||
sptr->resume(); | |||||
_cached_states.clear(); | |||||
return true; | |||||
} | |||||
void scheduler_t::run_until_notask() | |||||
{ | |||||
for(;;) | |||||
{ | |||||
//介于网上有人做评测,导致单协程切换数据很难看,那就注释掉吧。 | |||||
//std::this_thread::yield(); | |||||
if (likely(this->run_one_batch())) continue; //当前运行了一个state,则认为还可能有任务未完成 | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __guard(_lock_ready); | |||||
#endif | |||||
if (likely(!_ready_task.empty())) continue; //当前还存在task,则必然还有任务未完成 | |||||
} | |||||
if (unlikely(!_timer->empty())) continue; //定时器不为空,也需要等待定时器触发 | |||||
break; | |||||
}; | |||||
} | |||||
scheduler_t scheduler_t::g_scheduler; | |||||
} |
#include "../librf.h" | |||||
namespace resumef | |||||
{ | |||||
future_t<> sleep_until_(std::chrono::system_clock::time_point tp_, scheduler_t& scheduler_) | |||||
{ | |||||
awaitable_t<> awaitable; | |||||
(void)scheduler_.timer()->add(tp_, | |||||
[awaitable](bool cancellation_requested) | |||||
{ | |||||
if (cancellation_requested) | |||||
awaitable.throw_exception(canceled_exception{ error_code::timer_canceled }); | |||||
else | |||||
awaitable.set_value(); | |||||
}); | |||||
return awaitable.get_future(); | |||||
} | |||||
} | |||||
#include "librf/librf.h" | |||||
namespace librf | |||||
{ | |||||
future_t<> sleep_until_(std::chrono::system_clock::time_point tp_, scheduler_t& scheduler_) | |||||
{ | |||||
awaitable_t<> awaitable; | |||||
(void)scheduler_.timer()->add(tp_, | |||||
[awaitable](bool cancellation_requested) | |||||
{ | |||||
if (cancellation_requested) | |||||
awaitable.throw_exception(canceled_exception{ error_code::timer_canceled }); | |||||
else | |||||
awaitable.set_value(); | |||||
}); | |||||
return awaitable.get_future(); | |||||
} | |||||
} |
#include "../librf.h" | |||||
namespace resumef | |||||
{ | |||||
state_base_t::~state_base_t() | |||||
{ | |||||
} | |||||
void state_base_t::destroy_deallocate() | |||||
{ | |||||
delete this; | |||||
} | |||||
state_base_t* state_base_t::get_parent() const noexcept | |||||
{ | |||||
return nullptr; | |||||
} | |||||
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); | |||||
} | |||||
state_generator_t* state_generator_t::_Alloc_state() | |||||
{ | |||||
_Alloc_char _Al; | |||||
size_t _Size = _Align_size<state_generator_t>(); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << "state_generator_t::alloc, size=" << sizeof(state_generator_t) << std::endl; | |||||
#endif | |||||
char* _Ptr = _Al.allocate(_Size); | |||||
return new(_Ptr) state_generator_t(); | |||||
} | |||||
void state_generator_t::destroy_deallocate() | |||||
{ | |||||
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 | |||||
std::cout << "destroy_deallocate, size=" << _Size << std::endl; | |||||
#endif | |||||
this->~state_generator_t(); | |||||
_Alloc_char _Al; | |||||
return _Al.deallocate(reinterpret_cast<char*>(this), _Size); | |||||
} | |||||
void state_generator_t::resume() | |||||
{ | |||||
if (likely(_coro)) | |||||
{ | |||||
_coro.resume(); | |||||
if (likely(!_coro.done())) | |||||
{ | |||||
_scheduler->add_generator(this); | |||||
} | |||||
else | |||||
{ | |||||
coroutine_handle<> handler = _coro; | |||||
_coro = nullptr; | |||||
_scheduler->del_final(this); | |||||
handler.destroy(); | |||||
} | |||||
} | |||||
} | |||||
bool state_generator_t::has_handler() const noexcept | |||||
{ | |||||
return (bool)_coro; | |||||
} | |||||
bool state_generator_t::switch_scheduler_await_suspend(scheduler_t* sch) | |||||
{ | |||||
assert(sch != nullptr); | |||||
if (_scheduler != nullptr) | |||||
{ | |||||
if (_scheduler == sch) return false; | |||||
auto task_ptr = _scheduler->del_switch(this); | |||||
_scheduler = sch; | |||||
if (task_ptr != nullptr) | |||||
sch->add_switch(std::move(task_ptr)); | |||||
} | |||||
else | |||||
{ | |||||
_scheduler = sch; | |||||
} | |||||
return true; | |||||
} | |||||
state_base_t* state_future_t::get_parent() const noexcept | |||||
{ | |||||
return _parent; | |||||
} | |||||
void state_future_t::resume() | |||||
{ | |||||
std::unique_lock<lock_type> __guard(_mtx); | |||||
if (_is_initor == initor_type::Initial) | |||||
{ | |||||
assert((bool)_initor); | |||||
coroutine_handle<> handler = _initor; | |||||
_is_initor = initor_type::None; | |||||
__guard.unlock(); | |||||
handler.resume(); | |||||
return; | |||||
} | |||||
if (_coro) | |||||
{ | |||||
coroutine_handle<> handler = _coro; | |||||
_coro = nullptr; | |||||
__guard.unlock(); | |||||
handler.resume(); | |||||
return; | |||||
} | |||||
if (_is_initor == initor_type::Final) | |||||
{ | |||||
assert((bool)_initor); | |||||
coroutine_handle<> handler = _initor; | |||||
_is_initor = initor_type::None; | |||||
__guard.unlock(); | |||||
handler.destroy(); | |||||
return; | |||||
} | |||||
} | |||||
bool state_future_t::has_handler() const noexcept | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
return has_handler_skip_lock(); | |||||
} | |||||
bool state_future_t::switch_scheduler_await_suspend(scheduler_t* sch) | |||||
{ | |||||
assert(sch != nullptr); | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
if (_scheduler != nullptr) | |||||
{ | |||||
if (_scheduler == sch) return false; | |||||
auto task_ptr = _scheduler->del_switch(this); | |||||
_scheduler = sch; | |||||
if (task_ptr != nullptr) | |||||
sch->add_switch(std::move(task_ptr)); | |||||
} | |||||
else | |||||
{ | |||||
_scheduler = sch; | |||||
} | |||||
if (_parent != nullptr) | |||||
_parent->switch_scheduler_await_suspend(sch); | |||||
return true; | |||||
} | |||||
void state_t<void>::future_await_resume() | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
if (this->_exception) | |||||
std::rethrow_exception(std::move(this->_exception)); | |||||
if (this->_has_value.load(std::memory_order_acquire) == result_type::None) | |||||
std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready})); | |||||
} | |||||
void state_t<void>::set_value() | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
this->_has_value.store(result_type::Value, std::memory_order_release); | |||||
scheduler_t* sch = this->get_scheduler(); | |||||
if (sch != nullptr) | |||||
{ | |||||
if (this->has_handler_skip_lock()) | |||||
sch->add_generator(this); | |||||
else | |||||
sch->del_final(this); | |||||
} | |||||
} | |||||
void state_t<void>::set_exception(std::exception_ptr e) | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
this->_exception = std::move(e); | |||||
scheduler_t* sch = this->get_scheduler(); | |||||
if (sch != nullptr) | |||||
{ | |||||
if (this->has_handler_skip_lock()) | |||||
sch->add_generator(this); | |||||
else | |||||
sch->del_final(this); | |||||
} | |||||
} | |||||
} | |||||
#include "librf/librf.h" | |||||
namespace librf | |||||
{ | |||||
state_base_t::~state_base_t() | |||||
{ | |||||
} | |||||
void state_base_t::destroy_deallocate() | |||||
{ | |||||
delete this; | |||||
} | |||||
state_base_t* state_base_t::get_parent() const noexcept | |||||
{ | |||||
return nullptr; | |||||
} | |||||
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); | |||||
} | |||||
state_generator_t* state_generator_t::_Alloc_state() | |||||
{ | |||||
_Alloc_char _Al; | |||||
size_t _Size = _Align_size<state_generator_t>(); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << "state_generator_t::alloc, size=" << sizeof(state_generator_t) << std::endl; | |||||
#endif | |||||
char* _Ptr = _Al.allocate(_Size); | |||||
return new(_Ptr) state_generator_t(); | |||||
} | |||||
void state_generator_t::destroy_deallocate() | |||||
{ | |||||
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 | |||||
std::cout << "destroy_deallocate, size=" << _Size << std::endl; | |||||
#endif | |||||
this->~state_generator_t(); | |||||
_Alloc_char _Al; | |||||
return _Al.deallocate(reinterpret_cast<char*>(this), _Size); | |||||
} | |||||
void state_generator_t::resume() | |||||
{ | |||||
if (likely(_coro)) | |||||
{ | |||||
_coro.resume(); | |||||
if (likely(!_coro.done())) | |||||
{ | |||||
_scheduler->add_generator(this); | |||||
} | |||||
else | |||||
{ | |||||
coroutine_handle<> handler = _coro; | |||||
_coro = nullptr; | |||||
_scheduler->del_final(this); | |||||
handler.destroy(); | |||||
} | |||||
} | |||||
} | |||||
bool state_generator_t::has_handler() const noexcept | |||||
{ | |||||
return (bool)_coro; | |||||
} | |||||
bool state_generator_t::switch_scheduler_await_suspend(scheduler_t* sch) | |||||
{ | |||||
assert(sch != nullptr); | |||||
if (_scheduler != nullptr) | |||||
{ | |||||
if (_scheduler == sch) return false; | |||||
auto task_ptr = _scheduler->del_switch(this); | |||||
_scheduler = sch; | |||||
if (task_ptr != nullptr) | |||||
sch->add_switch(std::move(task_ptr)); | |||||
} | |||||
else | |||||
{ | |||||
_scheduler = sch; | |||||
} | |||||
return true; | |||||
} | |||||
state_base_t* state_future_t::get_parent() const noexcept | |||||
{ | |||||
return _parent; | |||||
} | |||||
void state_future_t::resume() | |||||
{ | |||||
std::unique_lock<lock_type> __guard(_mtx); | |||||
if (_is_initor == initor_type::Initial) | |||||
{ | |||||
assert((bool)_initor); | |||||
coroutine_handle<> handler = _initor; | |||||
_is_initor = initor_type::None; | |||||
__guard.unlock(); | |||||
handler.resume(); | |||||
return; | |||||
} | |||||
if (_coro) | |||||
{ | |||||
coroutine_handle<> handler = _coro; | |||||
_coro = nullptr; | |||||
__guard.unlock(); | |||||
handler.resume(); | |||||
return; | |||||
} | |||||
if (_is_initor == initor_type::Final) | |||||
{ | |||||
assert((bool)_initor); | |||||
coroutine_handle<> handler = _initor; | |||||
_is_initor = initor_type::None; | |||||
__guard.unlock(); | |||||
handler.destroy(); | |||||
return; | |||||
} | |||||
} | |||||
bool state_future_t::has_handler() const noexcept | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
return has_handler_skip_lock(); | |||||
} | |||||
bool state_future_t::switch_scheduler_await_suspend(scheduler_t* sch) | |||||
{ | |||||
assert(sch != nullptr); | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
if (_scheduler != nullptr) | |||||
{ | |||||
if (_scheduler == sch) return false; | |||||
auto task_ptr = _scheduler->del_switch(this); | |||||
_scheduler = sch; | |||||
if (task_ptr != nullptr) | |||||
sch->add_switch(std::move(task_ptr)); | |||||
} | |||||
else | |||||
{ | |||||
_scheduler = sch; | |||||
} | |||||
if (_parent != nullptr) | |||||
_parent->switch_scheduler_await_suspend(sch); | |||||
return true; | |||||
} | |||||
void state_t<void>::future_await_resume() | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
if (this->_exception) | |||||
std::rethrow_exception(std::move(this->_exception)); | |||||
if (this->_has_value.load(std::memory_order_acquire) == result_type::None) | |||||
std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready})); | |||||
} | |||||
void state_t<void>::set_value() | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
this->_has_value.store(result_type::Value, std::memory_order_release); | |||||
scheduler_t* sch = this->get_scheduler(); | |||||
if (sch != nullptr) | |||||
{ | |||||
if (this->has_handler_skip_lock()) | |||||
sch->add_generator(this); | |||||
else | |||||
sch->del_final(this); | |||||
} | |||||
} | |||||
void state_t<void>::set_exception(std::exception_ptr e) | |||||
{ | |||||
scoped_lock<lock_type> __guard(this->_mtx); | |||||
this->_exception = std::move(e); | |||||
scheduler_t* sch = this->get_scheduler(); | |||||
if (sch != nullptr) | |||||
{ | |||||
if (this->has_handler_skip_lock()) | |||||
sch->add_generator(this); | |||||
else | |||||
sch->del_final(this); | |||||
} | |||||
} | |||||
} |
#include "../librf.h" | |||||
namespace resumef | |||||
{ | |||||
timer_manager::timer_manager() | |||||
{ | |||||
_added_timers.reserve(128); | |||||
} | |||||
timer_manager::~timer_manager() | |||||
{ | |||||
clear(); | |||||
} | |||||
void timer_manager::call_target_(const timer_target_ptr & sptr, bool canceld) | |||||
{ | |||||
auto cb = std::move(sptr->cb); | |||||
sptr->st = timer_target::State::Invalid; | |||||
#if _DEBUG | |||||
sptr->_manager = nullptr; | |||||
#endif | |||||
if(cb) cb(canceld); | |||||
} | |||||
void timer_manager::clear() | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
std::unique_lock<spinlock> __lock(_added_mtx); | |||||
#endif | |||||
auto _atimer = std::move(_added_timers); | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
__lock.unlock(); | |||||
#endif | |||||
for (auto& sptr : _atimer) | |||||
call_target_(sptr, true); | |||||
auto _rtimer = std::move(_runing_timers); | |||||
for (auto & kv : _rtimer) | |||||
call_target_(kv.second, true); | |||||
} | |||||
detail::timer_target_ptr timer_manager::add_(const timer_target_ptr & sptr) | |||||
{ | |||||
assert(sptr); | |||||
assert(sptr->st == timer_target::State::Invalid); | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __lock(_added_mtx); | |||||
#endif | |||||
#if _DEBUG | |||||
assert(sptr->_manager == nullptr); | |||||
sptr->_manager = this; | |||||
#endif | |||||
sptr->st = timer_target::State::Added; | |||||
_added_timers.push_back(sptr); | |||||
return sptr; | |||||
} | |||||
bool timer_manager::stop(const timer_target_ptr & sptr) | |||||
{ | |||||
if (!sptr || sptr->st == timer_target::State::Invalid) | |||||
return false; | |||||
#if _DEBUG | |||||
assert(sptr->_manager == this); | |||||
#endif | |||||
sptr->st = timer_target::State::Invalid; | |||||
return true; | |||||
} | |||||
void timer_manager::update() | |||||
{ | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
std::unique_lock<spinlock> __lock(_added_mtx); | |||||
#endif | |||||
if (unlikely(_added_timers.size() > 0)) | |||||
{ | |||||
auto _atimer = std::move(_added_timers); | |||||
_added_timers.reserve(128); | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
__lock.unlock(); | |||||
#endif | |||||
for (auto& sptr : _atimer) | |||||
{ | |||||
if (sptr->st == timer_target::State::Added) | |||||
{ | |||||
sptr->st = timer_target::State::Runing; | |||||
_runing_timers.insert({ sptr->tp, sptr }); | |||||
} | |||||
else | |||||
{ | |||||
assert(sptr->st == timer_target::State::Invalid); | |||||
call_target_(sptr, true); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if (unlikely(_runing_timers.size() > 0)) | |||||
{ | |||||
auto now_ = clock_type::now(); | |||||
auto iter = _runing_timers.begin(); | |||||
for (; iter != _runing_timers.end(); ++iter) | |||||
{ | |||||
auto & kv = *iter; | |||||
if (kv.first > now_) | |||||
break; | |||||
call_target_(kv.second, kv.second->st == timer_target::State::Invalid); | |||||
} | |||||
_runing_timers.erase(_runing_timers.begin(), iter); | |||||
} | |||||
} | |||||
#include "librf/librf.h" | |||||
namespace librf | |||||
{ | |||||
timer_manager::timer_manager() | |||||
{ | |||||
_added_timers.reserve(128); | |||||
} | |||||
timer_manager::~timer_manager() | |||||
{ | |||||
clear(); | |||||
} | |||||
void timer_manager::call_target_(const timer_target_ptr & sptr, bool canceld) | |||||
{ | |||||
auto cb = std::move(sptr->cb); | |||||
sptr->st = timer_target::State::Invalid; | |||||
#if _DEBUG | |||||
sptr->_manager = nullptr; | |||||
#endif | |||||
if(cb) cb(canceld); | |||||
} | |||||
void timer_manager::clear() | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
std::unique_lock<spinlock> __lock(_added_mtx); | |||||
#endif | |||||
auto _atimer = std::move(_added_timers); | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
__lock.unlock(); | |||||
#endif | |||||
for (auto& sptr : _atimer) | |||||
call_target_(sptr, true); | |||||
auto _rtimer = std::move(_runing_timers); | |||||
for (auto & kv : _rtimer) | |||||
call_target_(kv.second, true); | |||||
} | |||||
detail::timer_target_ptr timer_manager::add_(const timer_target_ptr & sptr) | |||||
{ | |||||
assert(sptr); | |||||
assert(sptr->st == timer_target::State::Invalid); | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
scoped_lock<spinlock> __lock(_added_mtx); | |||||
#endif | |||||
#if _DEBUG | |||||
assert(sptr->_manager == nullptr); | |||||
sptr->_manager = this; | |||||
#endif | |||||
sptr->st = timer_target::State::Added; | |||||
_added_timers.push_back(sptr); | |||||
return sptr; | |||||
} | |||||
bool timer_manager::stop(const timer_target_ptr & sptr) | |||||
{ | |||||
if (!sptr || sptr->st == timer_target::State::Invalid) | |||||
return false; | |||||
#if _DEBUG | |||||
assert(sptr->_manager == this); | |||||
#endif | |||||
sptr->st = timer_target::State::Invalid; | |||||
return true; | |||||
} | |||||
void timer_manager::update() | |||||
{ | |||||
{ | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
std::unique_lock<spinlock> __lock(_added_mtx); | |||||
#endif | |||||
if (unlikely(_added_timers.size() > 0)) | |||||
{ | |||||
auto _atimer = std::move(_added_timers); | |||||
_added_timers.reserve(128); | |||||
#if !RESUMEF_DISABLE_MULT_THREAD | |||||
__lock.unlock(); | |||||
#endif | |||||
for (auto& sptr : _atimer) | |||||
{ | |||||
if (sptr->st == timer_target::State::Added) | |||||
{ | |||||
sptr->st = timer_target::State::Runing; | |||||
_runing_timers.insert({ sptr->tp, sptr }); | |||||
} | |||||
else | |||||
{ | |||||
assert(sptr->st == timer_target::State::Invalid); | |||||
call_target_(sptr, true); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if (unlikely(_runing_timers.size() > 0)) | |||||
{ | |||||
auto now_ = clock_type::now(); | |||||
auto iter = _runing_timers.begin(); | |||||
for (; iter != _runing_timers.end(); ++iter) | |||||
{ | |||||
auto & kv = *iter; | |||||
if (kv.first > now_) | |||||
break; | |||||
call_target_(kv.second, kv.second->st == timer_target::State::Invalid); | |||||
} | |||||
_runing_timers.erase(_runing_timers.begin(), iter); | |||||
} | |||||
} | |||||
} | } |
#include "../librf.h" | |||||
#include "librf/librf.h" | |||||
namespace resumef | |||||
namespace librf | |||||
{ | { | ||||
namespace detail | namespace detail | ||||
{ | { |
set(TUTORIAL_FILES "") | |||||
aux_source_directory("${CMAKE_SOURCE_DIR}/tutorial" TUTORIAL_FILES) | |||||
set(TUTORIAL_FILES "") | |||||
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} TUTORIAL_FILES) | |||||
foreach(TUTORIAL_FILE_PATH ${TUTORIAL_FILES}) | foreach(TUTORIAL_FILE_PATH ${TUTORIAL_FILES}) | ||||
string(REGEX REPLACE ".+[/\]([^/\.]+)\\.cpp" "\\1" TUTORIAL_FILE_NAME ${TUTORIAL_FILE_PATH}) | string(REGEX REPLACE ".+[/\]([^/\.]+)\\.cpp" "\\1" TUTORIAL_FILE_NAME ${TUTORIAL_FILE_PATH}) | ||||
message(STATUS "Generating test target: ${TUTORIAL_FILE_NAME}") | message(STATUS "Generating test target: ${TUTORIAL_FILE_NAME}") | ||||
add_executable(${TUTORIAL_FILE_NAME} ${TUTORIAL_FILE_PATH}) | add_executable(${TUTORIAL_FILE_NAME} ${TUTORIAL_FILE_PATH}) | ||||
target_link_libraries(${TUTORIAL_FILE_NAME} PUBLIC librf ${LIB_MIMALLOC}) | |||||
target_link_libraries(${TUTORIAL_FILE_NAME} PUBLIC librf) | |||||
endforeach(TUTORIAL_FILE_PATH) | endforeach(TUTORIAL_FILE_PATH) |
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
template<class _Ctype> | template<class _Ctype> | ||||
static void callback_get_long(int64_t val, _Ctype&& cb) | static void callback_get_long(int64_t val, _Ctype&& cb) |
#include <deque> | #include <deque> | ||||
#include <mutex> | #include <mutex> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
using namespace std::chrono; | using namespace std::chrono; | ||||
const size_t MAX_CHANNEL_QUEUE = 1; //0, 1, 5, 10, -1 | const size_t MAX_CHANNEL_QUEUE = 1; //0, 1, 5, 10, -1 | ||||
std::cout << val.value << ":"; | std::cout << val.value << ":"; | ||||
std::cout << std::endl; | std::cout << std::endl; | ||||
} | } | ||||
catch (resumef::channel_exception& e) | |||||
catch (librf::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; |
//验证channel是否线程安全 | |||||
//验证channel是否线程安全 | |||||
#include <chrono> | #include <chrono> | ||||
#include <iostream> | #include <iostream> | ||||
#include <deque> | #include <deque> | ||||
#include <mutex> | #include <mutex> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
using namespace std::chrono; | using namespace std::chrono; | ||||
static std::mutex cout_mutex; | static std::mutex cout_mutex; |
| |||||
#include <chrono> | #include <chrono> | ||||
#include <iostream> | #include <iostream> | ||||
#include <string> | #include <string> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
static const int M = 10; | static const int M = 10; | ||||
void test_dynamic_go() | void test_dynamic_go() | ||||
{ | { | ||||
auto co_star = [](int j) -> resumef::future_t<int> | |||||
auto co_star = [](int j) -> librf::future_t<int> | |||||
{ | { | ||||
for (int i = 0; i < M; ++i) | for (int i = 0; i < M; ++i) | ||||
{ | { | ||||
go[=]() -> resumef::generator_t<int> | |||||
go[=]() -> librf::generator_t<int> | |||||
{ | { | ||||
for (int k = 0; k < M; ++k) | for (int k = 0; k < M; ++k) | ||||
{ | { | ||||
go co_star(1); | go co_star(1); | ||||
go co_star(2); | go co_star(2); | ||||
resumef::this_scheduler()->run_until_notask(); | |||||
librf::this_scheduler()->run_until_notask(); | |||||
std::cout << "dynamic_go_count = " << dynamic_go_count << std::endl; | std::cout << "dynamic_go_count = " << dynamic_go_count << std::endl; | ||||
for (auto & j : dynamic_cells) | for (auto & j : dynamic_cells) |
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
//非协程的逻辑线程,或异步代码,可以通过event_t通知到协程,并且不会阻塞协程所在的线程。 | //非协程的逻辑线程,或异步代码,可以通过event_t通知到协程,并且不会阻塞协程所在的线程。 | ||||
static std::thread async_set_event(const event_t & e, std::chrono::milliseconds dt) | static std::thread async_set_event(const event_t & e, std::chrono::milliseconds dt) |
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
future_t<> resumalbe_set_event(const event_t & e, std::chrono::milliseconds dt) | future_t<> resumalbe_set_event(const event_t & e, std::chrono::milliseconds dt) | ||||
{ | { | ||||
co_await resumef::sleep_for(dt); | |||||
co_await librf::sleep_for(dt); | |||||
e.signal(); | e.signal(); | ||||
std::cout << "+"; | std::cout << "+"; | ||||
} | } |
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
using namespace std::chrono; | using namespace std::chrono; | ||||
//非协程的逻辑线程,或异步代码,可以通过event_t通知到协程,并且不会阻塞协程所在的线程。 | //非协程的逻辑线程,或异步代码,可以通过event_t通知到协程,并且不会阻塞协程所在的线程。 |
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
//请打开结构化异常(/EHa) | //请打开结构化异常(/EHa) | ||||
auto async_signal_exception(const intptr_t dividend) | auto async_signal_exception(const intptr_t dividend) |
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
#ifndef __GNUC__ //GCC: 没有提供__builtin_coro_frame这样的内置函数 | #ifndef __GNUC__ //GCC: 没有提供__builtin_coro_frame这样的内置函数 | ||||
//编译失败。因为这个函数不是"可恢复函数(resumeable function)",仅仅是"可等待函数(awaitable function)" | //编译失败。因为这个函数不是"可恢复函数(resumeable function)",仅仅是"可等待函数(awaitable function)" | ||||
//void* frame_ptr = _coro_frame_ptr(); | //void* frame_ptr = _coro_frame_ptr(); | ||||
resumef::awaitable_t<int64_t> awaitable; | |||||
librf::awaitable_t<int64_t> awaitable; | |||||
callback_get_long(a, b, [awaitable](int64_t val) | callback_get_long(a, b, [awaitable](int64_t val) | ||||
{ | { | ||||
awaitable.set_value(val); | awaitable.set_value(val); | ||||
#ifndef __GNUC__ //GCC: 没有提供__builtin_coro_frame这样的内置函数 | #ifndef __GNUC__ //GCC: 没有提供__builtin_coro_frame这样的内置函数 | ||||
go resumable_get_long_2(1, 2, 5); | go resumable_get_long_2(1, 2, 5); | ||||
#endif //#ifndef __GNUC__ | #endif //#ifndef __GNUC__ | ||||
resumef::this_scheduler()->run_until_notask(); | |||||
librf::this_scheduler()->run_until_notask(); | |||||
std::cout << __FUNCTION__ << " - end" << std::endl; | std::cout << __FUNCTION__ << " - end" << std::endl; | ||||
} | } |
#endif | #endif | ||||
} | } | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
#include "use_librf.h" | #include "use_librf.h" | ||||
static void example_librf() | static void example_librf() | ||||
} | } | ||||
}; | }; | ||||
resumef::this_scheduler()->run_until_notask(); | |||||
librf::this_scheduler()->run_until_notask(); | |||||
} | } | ||||
void resumable_main_modern_cb() | void resumable_main_modern_cb() |
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
static std::mutex cout_mutex; | static std::mutex cout_mutex; | ||||
//这是一个重度计算任务,只能单开线程来避免主线程被阻塞 | //这是一个重度计算任务,只能单开线程来避免主线程被阻塞 |
#include <thread> | #include <thread> | ||||
#include <deque> | #include <deque> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
using namespace std::chrono; | using namespace std::chrono; | ||||
static mutex_t g_lock; | static mutex_t g_lock; |
| |||||
#include <chrono> | #include <chrono> | ||||
#include <iostream> | #include <iostream> | ||||
#include <string> | #include <string> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
static std::mutex lock_console; | static std::mutex lock_console; | ||||
static const intptr_t N = 3000000; | static const intptr_t N = 3000000; | ||||
//static const int N = 10; | //static const int N = 10; | ||||
auto yield_switch(intptr_t coro) -> resumef::generator_t<intptr_t> | |||||
auto yield_switch(intptr_t coro) -> librf::generator_t<intptr_t> | |||||
{ | { | ||||
for (intptr_t i = N / coro; i > 0; --i) | for (intptr_t i = N / coro; i > 0; --i) | ||||
co_yield i; | co_yield i; | ||||
void resumable_switch(intptr_t coro, size_t idx) | void resumable_switch(intptr_t coro, size_t idx) | ||||
{ | { | ||||
resumef::local_scheduler_t ls; | |||||
librf::local_scheduler_t ls; | |||||
auto start = std::chrono::steady_clock::now(); | auto start = std::chrono::steady_clock::now(); | ||||
auto middle = std::chrono::steady_clock::now(); | auto middle = std::chrono::steady_clock::now(); | ||||
dump(idx, "BenchmarkCreate_" + std::to_string(coro), start, middle, coro); | dump(idx, "BenchmarkCreate_" + std::to_string(coro), start, middle, coro); | ||||
resumef::this_scheduler()->run_until_notask(); | |||||
librf::this_scheduler()->run_until_notask(); | |||||
auto end = std::chrono::steady_clock::now(); | auto end = std::chrono::steady_clock::now(); | ||||
dump(idx, "BenchmarkSwitch_" + std::to_string(coro), middle, end, N); | dump(idx, "BenchmarkSwitch_" + std::to_string(coro), middle, end, N); |
 | |||||
#include <chrono> | #include <chrono> | ||||
#include <iostream> | #include <iostream> | ||||
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
#ifndef __GNUC__ //GCC: ûÓÐÌṩ__builtin_coro_frameÕâÑùµÄÄÚÖú¯Êý | |||||
#ifndef __GNUC__ //GCC: 没有æ��ä¾›__builtin_coro_frameè¿™æ ·çš„å†…ç½®å‡½æ•° | |||||
future_t<> test_routine_use_timer() | future_t<> test_routine_use_timer() | ||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
for (size_t i = 0; i < 3; ++i) | for (size_t i = 0; i < 3; ++i) | ||||
{ | { | ||||
co_await resumef::sleep_for(100ms); | |||||
co_await librf::sleep_for(100ms); | |||||
std::cout << "timer after 100ms" << std::endl; | std::cout << "timer after 100ms" << std::endl; | ||||
std::cout << "1:frame=" << _coro_frame_ptr() << std::endl; | std::cout << "1:frame=" << _coro_frame_ptr() << std::endl; | ||||
} | } | ||||
{ | { | ||||
std::cout << __FUNCTION__ << std::endl; | std::cout << __FUNCTION__ << std::endl; | ||||
//go test_routine_use_timer_2(); | //go test_routine_use_timer_2(); | ||||
#ifndef __GNUC__ //GCC: ûÓÐÌṩ__builtin_coro_frameÕâÑùµÄÄÚÖú¯Êý | |||||
#ifndef __GNUC__ //GCC: 没有æ��ä¾›__builtin_coro_frameè¿™æ ·çš„å†…ç½®å‡½æ•° | |||||
go test_routine_use_timer(); | go test_routine_use_timer(); | ||||
#endif //#ifndef __GNUC__ | #endif //#ifndef __GNUC__ | ||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); |
| |||||
#include <chrono> | #include <chrono> | ||||
#include <iostream> | #include <iostream> | ||||
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
future_t<> test_sleep_use_timer() | future_t<> test_sleep_use_timer() | ||||
{ | { |
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
using namespace std::chrono; | using namespace std::chrono; | ||||
//_Ctype签名:void(bool, int64_t) | //_Ctype签名:void(bool, int64_t) |
| |||||
#include <chrono> | #include <chrono> | ||||
#include <iostream> | #include <iostream> | ||||
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
future_t<> test_loop_sleep(size_t _N, const char * ch) | future_t<> test_loop_sleep(size_t _N, const char * ch) | ||||
{ | { | ||||
for (size_t i = 0; i < _N; ++i) | for (size_t i = 0; i < _N; ++i) | ||||
{ | { | ||||
co_await resumef::sleep_for(100ms); | |||||
co_await librf::sleep_for(100ms); | |||||
std::cout << ch; | std::cout << ch; | ||||
} | } | ||||
std::cout << std::endl; | std::cout << std::endl; |
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
static scheduler_t* sch_in_main = nullptr; | static scheduler_t* sch_in_main = nullptr; | ||||
static std::atomic<scheduler_t*> sch_in_thread = nullptr; | static std::atomic<scheduler_t*> sch_in_thread = nullptr; |
| |||||
#include <chrono> | #include <chrono> | ||||
#include <iostream> | #include <iostream> | ||||
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
void resumable_main_timer() | void resumable_main_timer() | ||||
{ | { |
 | |||||
#include <chrono> | #include <chrono> | ||||
#include <iostream> | #include <iostream> | ||||
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
#if !defined(__GNUC__) | #if !defined(__GNUC__) | ||||
void test_when_any() | void test_when_any() | ||||
}); | }); | ||||
if (vals.first == 0) | if (vals.first == 0) | ||||
std::cout << "first done! value is " << resumef::any_cast<int>(vals.second) << std::endl; | |||||
std::cout << "first done! value is " << librf::any_cast<int>(vals.second) << std::endl; | |||||
else | else | ||||
std::cout << "any done! index is " << vals.first << std::endl; | std::cout << "any done! index is " << vals.first << std::endl; | ||||
//vals = co_await when_any(std::begin(v), std::end(v)); | //vals = co_await when_any(std::begin(v), std::end(v)); | ||||
vals = co_await when_any(v); | vals = co_await when_any(v); | ||||
std::cout << "any range done! index is " << vals.first << ", valus is " << resumef::any_cast<int>(vals.second) << std::endl; | |||||
std::cout << "any range done! index is " << vals.first << ", valus is " << librf::any_cast<int>(vals.second) << std::endl; | |||||
}; | }; | ||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); | ||||
} | } | ||||
); | ); | ||||
if (vals.first == 0) | if (vals.first == 0) | ||||
std::cout << "first done! value is " << resumef::any_cast<int>(vals.second) << std::endl; | |||||
std::cout << "first done! value is " << librf::any_cast<int>(vals.second) << std::endl; | |||||
else | else | ||||
std::cout << "any done! index is " << vals.first << std::endl; | std::cout << "any done! index is " << vals.first << std::endl; | ||||
}; | }; | ||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); | ||||
} | } | ||||
//ÕâÄÜÄ£ÄâgolangµÄselectÂð? | |||||
//这能模拟golang的select�? | |||||
void test_when_select() | void test_when_select() | ||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
if (vals.first == 0) | if (vals.first == 0) | ||||
std::cout << "time out!" << std::endl; | std::cout << "time out!" << std::endl; | ||||
else | else | ||||
std::cout << "index is " << vals.first << ", value is " << resumef::any_cast<int>(vals.second) << std::endl; | |||||
std::cout << "index is " << vals.first << ", value is " << librf::any_cast<int>(vals.second) << std::endl; | |||||
}; | }; | ||||
GO | GO |
| |||||
#include <chrono> | #include <chrono> | ||||
#include <iostream> | #include <iostream> | ||||
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
#include "librf.h" | |||||
#include "librf/librf.h" | |||||
using namespace resumef; | |||||
using namespace librf; | |||||
generator_t<int> test_yield_int() | generator_t<int> test_yield_int() | ||||
{ | { |
| |||||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||||
# Visual Studio Version 16 | |||||
VisualStudioVersion = 16.0.29814.53 | |||||
MinimumVisualStudioVersion = 10.0.40219.1 | |||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "librf", "librf.vcxproj", "{C1D4A6BD-592F-4E48-8178-7C87219BF80E}" | |||||
EndProject | |||||
Global | |||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||||
Debug|x64 = Debug|x64 | |||||
Debug|x86 = Debug|x86 | |||||
Release|x64 = Release|x64 | |||||
Release|x86 = Release|x86 | |||||
EndGlobalSection | |||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
{C1D4A6BD-592F-4E48-8178-7C87219BF80E}.Debug|x64.ActiveCfg = Debug|x64 | |||||
{C1D4A6BD-592F-4E48-8178-7C87219BF80E}.Debug|x64.Build.0 = Debug|x64 | |||||
{C1D4A6BD-592F-4E48-8178-7C87219BF80E}.Debug|x86.ActiveCfg = Debug|Win32 | |||||
{C1D4A6BD-592F-4E48-8178-7C87219BF80E}.Debug|x86.Build.0 = Debug|Win32 | |||||
{C1D4A6BD-592F-4E48-8178-7C87219BF80E}.Release|x64.ActiveCfg = Release|x64 | |||||
{C1D4A6BD-592F-4E48-8178-7C87219BF80E}.Release|x64.Build.0 = Release|x64 | |||||
{C1D4A6BD-592F-4E48-8178-7C87219BF80E}.Release|x86.ActiveCfg = Release|Win32 | |||||
{C1D4A6BD-592F-4E48-8178-7C87219BF80E}.Release|x86.Build.0 = Release|Win32 | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | |||||
HideSolutionNode = FALSE | |||||
EndGlobalSection | |||||
GlobalSection(ExtensibilityGlobals) = postSolution | |||||
SolutionGuid = {401D9E59-A4B3-4CA3-9696-B7D2D14D90FD} | |||||
EndGlobalSection | |||||
GlobalSection(Performance) = preSolution | |||||
HasPerformanceSessions = true | |||||
EndGlobalSection | |||||
GlobalSection(Performance) = preSolution | |||||
HasPerformanceSessions = true | |||||
EndGlobalSection | |||||
EndGlobal |
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<ItemGroup Label="ProjectConfigurations"> | |||||
<ProjectConfiguration Include="Debug|Win32"> | |||||
<Configuration>Debug</Configuration> | |||||
<Platform>Win32</Platform> | |||||
</ProjectConfiguration> | |||||
<ProjectConfiguration Include="Release|Win32"> | |||||
<Configuration>Release</Configuration> | |||||
<Platform>Win32</Platform> | |||||
</ProjectConfiguration> | |||||
<ProjectConfiguration Include="Debug|x64"> | |||||
<Configuration>Debug</Configuration> | |||||
<Platform>x64</Platform> | |||||
</ProjectConfiguration> | |||||
<ProjectConfiguration Include="Release|x64"> | |||||
<Configuration>Release</Configuration> | |||||
<Platform>x64</Platform> | |||||
</ProjectConfiguration> | |||||
</ItemGroup> | |||||
<PropertyGroup Label="Globals"> | |||||
<VCProjectVersion>15.0</VCProjectVersion> | |||||
<ProjectGuid>{C1D4A6BD-592F-4E48-8178-7C87219BF80E}</ProjectGuid> | |||||
<Keyword>Win32Proj</Keyword> | |||||
<RootNamespace>librf</RootNamespace> | |||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |||||
</PropertyGroup> | |||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> | |||||
<ConfigurationType>Application</ConfigurationType> | |||||
<PlatformToolset>v142</PlatformToolset> | |||||
<UseDebugLibraries>true</UseDebugLibraries> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> | |||||
<ConfigurationType>Application</ConfigurationType> | |||||
<UseDebugLibraries>false</UseDebugLibraries> | |||||
<PlatformToolset>v142</PlatformToolset> | |||||
<WholeProgramOptimization>true</WholeProgramOptimization> | |||||
<CharacterSet>NotSet</CharacterSet> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | |||||
<ConfigurationType>Application</ConfigurationType> | |||||
<PlatformToolset>v142</PlatformToolset> | |||||
<UseDebugLibraries>true</UseDebugLibraries> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | |||||
<ConfigurationType>Application</ConfigurationType> | |||||
<UseDebugLibraries>false</UseDebugLibraries> | |||||
<PlatformToolset>v142</PlatformToolset> | |||||
<WholeProgramOptimization>true</WholeProgramOptimization> | |||||
<CharacterSet>NotSet</CharacterSet> | |||||
</PropertyGroup> | |||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | |||||
<ImportGroup Label="ExtensionSettings"> | |||||
</ImportGroup> | |||||
<ImportGroup Label="Shared"> | |||||
</ImportGroup> | |||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
</ImportGroup> | |||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
</ImportGroup> | |||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
</ImportGroup> | |||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
</ImportGroup> | |||||
<PropertyGroup Label="UserMacros" /> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |||||
<LinkIncremental>true</LinkIncremental> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||||
<LinkIncremental>true</LinkIncremental> | |||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" /> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||||
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet> | |||||
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis> | |||||
</PropertyGroup> | |||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |||||
<ClCompile> | |||||
<WarningLevel>Level4</WarningLevel> | |||||
<Optimization>Disabled</Optimization> | |||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;_CONSOLE;ASIO_STANDALONE;_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING=1;ASIO_DISABLE_CONCEPTS=1;RESUMEF_ENABLE_MULT_SCHEDULER=1;_DEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
<AdditionalIncludeDirectories>..\librf;..\..\asio\asio\include;..\..\asio-1.10.6\include;..\modern_cb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | |||||
<AdditionalOptions>/await</AdditionalOptions> | |||||
<MultiProcessorCompilation>true</MultiProcessorCompilation> | |||||
<LanguageStandard>stdcpplatest</LanguageStandard> | |||||
<OmitFramePointers /> | |||||
<DisableSpecificWarnings>4834;4505</DisableSpecificWarnings> | |||||
<SDLCheck>true</SDLCheck> | |||||
<StringPooling>true</StringPooling> | |||||
</ClCompile> | |||||
<Link> | |||||
<SubSystem>Console</SubSystem> | |||||
<GenerateDebugInformation>true</GenerateDebugInformation> | |||||
</Link> | |||||
</ItemDefinitionGroup> | |||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||||
<ClCompile> | |||||
<WarningLevel>Level4</WarningLevel> | |||||
<Optimization>Disabled</Optimization> | |||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;_CONSOLE;ASIO_STANDALONE;_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING=1;ASIO_DISABLE_CONCEPTS=1;RESUMEF_ENABLE_MULT_SCHEDULER=1;RESUMEF_DEBUG_COUNTER=0;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
<AdditionalIncludeDirectories>..\librf;..\..\asio\asio\include;..\..\asio-1.10.6\include;..\modern_cb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | |||||
<AdditionalOptions> | |||||
</AdditionalOptions> | |||||
<MultiProcessorCompilation>true</MultiProcessorCompilation> | |||||
<LanguageStandard>stdcpplatest</LanguageStandard> | |||||
<CLanguageStandard>c11</CLanguageStandard> | |||||
<CppLanguageStandard>c++1y</CppLanguageStandard> | |||||
<DisableSpecificWarnings>4834;4505</DisableSpecificWarnings> | |||||
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet> | |||||
<LanguageStandard_C>stdc17</LanguageStandard_C> | |||||
</ClCompile> | |||||
<Link> | |||||
<SubSystem>Console</SubSystem> | |||||
<GenerateDebugInformation>true</GenerateDebugInformation> | |||||
</Link> | |||||
</ItemDefinitionGroup> | |||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |||||
<ClCompile> | |||||
<WarningLevel>Level4</WarningLevel> | |||||
<Optimization>Full</Optimization> | |||||
<IntrinsicFunctions>true</IntrinsicFunctions> | |||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;_CONSOLE;ASIO_STANDALONE;_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING=1;ASIO_DISABLE_CONCEPTS=1;RESUMEF_ENABLE_MULT_SCHEDULER=1;NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
<SDLCheck> | |||||
</SDLCheck> | |||||
<AdditionalIncludeDirectories>..\librf;..\..\asio\asio\include;..\..\asio-1.10.6\include;..\modern_cb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | |||||
<AdditionalOptions>/await</AdditionalOptions> | |||||
<MultiProcessorCompilation>true</MultiProcessorCompilation> | |||||
<LanguageStandard>stdcpplatest</LanguageStandard> | |||||
<StringPooling>true</StringPooling> | |||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> | |||||
<OmitFramePointers>true</OmitFramePointers> | |||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> | |||||
<BufferSecurityCheck>false</BufferSecurityCheck> | |||||
<DisableSpecificWarnings>4834;4505</DisableSpecificWarnings> | |||||
<FunctionLevelLinking>true</FunctionLevelLinking> | |||||
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration> | |||||
<RuntimeTypeInfo>true</RuntimeTypeInfo> | |||||
<ExceptionHandling>Async</ExceptionHandling> | |||||
</ClCompile> | |||||
<Link> | |||||
<SubSystem>Console</SubSystem> | |||||
<EnableCOMDATFolding>true</EnableCOMDATFolding> | |||||
<OptimizeReferences>true</OptimizeReferences> | |||||
<GenerateDebugInformation>true</GenerateDebugInformation> | |||||
<Profile> | |||||
</Profile> | |||||
</Link> | |||||
</ItemDefinitionGroup> | |||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||||
<ClCompile> | |||||
<WarningLevel>Level4</WarningLevel> | |||||
<Optimization>Full</Optimization> | |||||
<IntrinsicFunctions>true</IntrinsicFunctions> | |||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;_CONSOLE;ASIO_STANDALONE;_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING=1;ASIO_DISABLE_CONCEPTS=1;RESUMEF_ENABLE_MULT_SCHEDULER=1;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
<AdditionalIncludeDirectories>..\librf;..\..\asio\asio\include;..\..\asio-1.10.6\include;..\modern_cb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | |||||
<AdditionalOptions>/await</AdditionalOptions> | |||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> | |||||
<StringPooling>true</StringPooling> | |||||
<LanguageStandard>stdcpplatest</LanguageStandard> | |||||
<MultiProcessorCompilation>true</MultiProcessorCompilation> | |||||
<EnablePREfast>true</EnablePREfast> | |||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> | |||||
<BufferSecurityCheck>false</BufferSecurityCheck> | |||||
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration> | |||||
<DisableSpecificWarnings>4834;4505</DisableSpecificWarnings> | |||||
<FunctionLevelLinking>true</FunctionLevelLinking> | |||||
<RuntimeTypeInfo>true</RuntimeTypeInfo> | |||||
<ExceptionHandling>Async</ExceptionHandling> | |||||
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations> | |||||
</ClCompile> | |||||
<Link> | |||||
<SubSystem>Console</SubSystem> | |||||
<EnableCOMDATFolding>true</EnableCOMDATFolding> | |||||
<OptimizeReferences>true</OptimizeReferences> | |||||
<GenerateDebugInformation>true</GenerateDebugInformation> | |||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> | |||||
<Profile>true</Profile> | |||||
</Link> | |||||
</ItemDefinitionGroup> | |||||
<ItemGroup> | |||||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\benchmark\benchmark_async_mem.cpp" /> | |||||
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" /> | |||||
<ClCompile Include="..\benchmark\test_async_cinatra_client.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\event_v2.cpp" /> | |||||
<ClCompile Include="..\librf\src\mutex_v2.cpp" /> | |||||
<ClCompile Include="..\librf\src\rf_task.cpp" /> | |||||
<ClCompile Include="..\librf\src\scheduler.cpp" /> | |||||
<ClCompile Include="..\librf\src\sleep.cpp" /> | |||||
<ClCompile Include="..\librf\src\state.cpp" /> | |||||
<ClCompile Include="..\librf\src\timer.cpp" /> | |||||
<ClCompile Include="..\librf\src\when_v2.cpp" /> | |||||
<ClCompile Include="..\test_librf.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_event_v2.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_exception.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_stop_token.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_yield_return.cpp" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ClInclude Include="..\asio\asio_task.h" /> | |||||
<ClInclude Include="..\librf\librf.h" /> | |||||
<ClInclude Include="..\librf\librf_macro.h" /> | |||||
<ClInclude Include="..\librf\src\awaitable.h" /> | |||||
<ClInclude Include="..\librf\src\channel.h" /> | |||||
<ClInclude Include="..\librf\src\channel_v2.h" /> | |||||
<ClInclude Include="..\librf\src\config.h" /> | |||||
<ClInclude Include="..\librf\src\counted_ptr.h" /> | |||||
<ClInclude Include="..\librf\src\current_scheduler.h" /> | |||||
<ClInclude Include="..\librf\src\def.h" /> | |||||
<ClInclude Include="..\librf\src\event.h" /> | |||||
<ClInclude Include="..\librf\src\event_v2.h" /> | |||||
<ClInclude Include="..\librf\src\future.h" /> | |||||
<ClInclude Include="..\librf\src\generator.h" /> | |||||
<ClInclude Include="..\librf\src\intrusive_link_queue.h" /> | |||||
<ClInclude Include="..\librf\src\mutex_v2.h" /> | |||||
<ClInclude Include="..\librf\src\promise.h" /> | |||||
<ClInclude Include="..\librf\src\mutex.h" /> | |||||
<ClInclude Include="..\librf\src\rf_task.h" /> | |||||
<ClInclude Include="..\librf\src\ring_queue_lockfree.h" /> | |||||
<ClInclude Include="..\librf\src\ring_queue.h" /> | |||||
<ClInclude Include="..\librf\src\ring_queue_spinlock.h" /> | |||||
<ClInclude Include="..\librf\src\scheduler.h" /> | |||||
<ClInclude Include="..\librf\src\sleep.h" /> | |||||
<ClInclude Include="..\librf\src\spinlock.h" /> | |||||
<ClInclude Include="..\librf\src\state.h" /> | |||||
<ClInclude Include="..\librf\src\stop_token.hpp" /> | |||||
<ClInclude Include="..\librf\src\switch_scheduler.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\gcc_builtin.h" /> | |||||
<ClInclude Include="..\librf\src\when.h" /> | |||||
<ClInclude Include="..\librf\src\when_v2.h" /> | |||||
<ClInclude Include="..\librf\src\yield.h" /> | |||||
<ClInclude Include="..\librf\src\_awaker.h" /> | |||||
<ClInclude Include="..\tutorial\test_ring_queue.h" /> | |||||
<ClInclude Include="dcas.h" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="..\asio\asio_task_1.10.0.inl" /> | |||||
<None Include="..\asio\asio_task_1.12.0.inl" /> | |||||
<None Include="..\asio\asio_task_1.12.2.inl" /> | |||||
<None Include="..\config.h.in" /> | |||||
<None Include="..\librf\src\channel_v2.inl" /> | |||||
<None Include="..\librf\src\event_v2.inl" /> | |||||
<None Include="..\librf\src\exception.inl" /> | |||||
<None Include="..\librf\src\without_deadlock_assemble.inl" /> | |||||
<None Include="..\librf\src\macro_def.inl" /> | |||||
<None Include="..\librf\src\mutex_v2.inl" /> | |||||
<None Include="..\librf\src\promise.inl" /> | |||||
<None Include="..\librf\src\state.inl" /> | |||||
<None Include="..\librf\src\type_concept.inl" /> | |||||
<None Include="..\librf\src\type_traits.inl" /> | |||||
<None Include="..\README.md" /> | |||||
</ItemGroup> | |||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | |||||
<ImportGroup Label="ExtensionTargets"> | |||||
</ImportGroup> | |||||
</Project> |
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<ItemGroup> | |||||
<Filter Include="Source Files"> | |||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> | |||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> | |||||
</Filter> | |||||
<Filter Include="librf"> | |||||
<UniqueIdentifier>{27e93efb-a01d-48f5-b10b-155fc8d52101}</UniqueIdentifier> | |||||
</Filter> | |||||
<Filter Include="librf\src"> | |||||
<UniqueIdentifier>{7cbfb0bd-8820-4639-9235-93ff984a9bb3}</UniqueIdentifier> | |||||
</Filter> | |||||
<Filter Include="librf\src\unix"> | |||||
<UniqueIdentifier>{46825786-52e6-4092-9418-cad7045aa118}</UniqueIdentifier> | |||||
</Filter> | |||||
<Filter Include="tutorial"> | |||||
<UniqueIdentifier>{d82e4930-c171-4b70-9ebb-cdec7218ff9c}</UniqueIdentifier> | |||||
</Filter> | |||||
<Filter Include="benchmark"> | |||||
<UniqueIdentifier>{0fd1274a-193b-4d6a-b19e-58db935ed5c6}</UniqueIdentifier> | |||||
</Filter> | |||||
<Filter Include="asio"> | |||||
<UniqueIdentifier>{8b54e700-2c12-4fb3-b7b5-19502aa09f6a}</UniqueIdentifier> | |||||
</Filter> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ClCompile Include="..\librf\src\rf_task.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\scheduler.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\sleep.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\timer.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_cb.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_channel.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_dynamic_go.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_event.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_event_timeout.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_exception.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_mutex.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_resumable.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_routine.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_sleep.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_suspend_always.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_timer.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_yield_return.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\benchmark\benchmark_async_mem.cpp"> | |||||
<Filter>benchmark</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\state.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_multi_thread.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_when_all.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp"> | |||||
<Filter>benchmark</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_modern_cb.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp"> | |||||
<Filter>benchmark</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_memory_layout.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_switch_scheduler.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\event_v2.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_event_v2.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\when_v2.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\librf\src\mutex_v2.cpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\test_librf.cpp"> | |||||
<Filter>Source Files</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_stop_token.cpp"> | |||||
<Filter>tutorial</Filter> | |||||
</ClCompile> | |||||
<ClCompile Include="..\benchmark\test_async_cinatra_client.cpp"> | |||||
<Filter>benchmark</Filter> | |||||
</ClCompile> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ClInclude Include="..\librf\librf.h"> | |||||
<Filter>librf</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\_awaker.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\channel.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\def.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\event.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\future.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\mutex.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\rf_task.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\scheduler.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\sleep.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\spinlock.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\state.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\timer.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\unix\coroutine.h"> | |||||
<Filter>librf\src\unix</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\counted_ptr.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\when.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\promise.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\awaitable.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\generator.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\librf_macro.h"> | |||||
<Filter>librf</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\switch_scheduler.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\unix\clang_builtin.h"> | |||||
<Filter>librf\src\unix</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\event_v2.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="dcas.h"> | |||||
<Filter>Source Files</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\ring_queue_lockfree.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\ring_queue_spinlock.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\tutorial\test_ring_queue.h"> | |||||
<Filter>tutorial</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\channel_v2.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\ring_queue.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\intrusive_link_queue.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\current_scheduler.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\when_v2.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\mutex_v2.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\yield.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\config.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\unix\gcc_builtin.h"> | |||||
<Filter>librf\src\unix</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\asio\asio_task.h"> | |||||
<Filter>asio</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\stop_token.hpp"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="..\librf\src\promise.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
<None Include="..\librf\src\state.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
<None Include="..\librf\src\exception.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
<None Include="..\librf\src\type_traits.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
<None Include="..\README.md" /> | |||||
<None Include="..\librf\src\macro_def.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
<None Include="..\librf\src\channel_v2.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
<None Include="..\librf\src\event_v2.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
<None Include="..\librf\src\type_concept.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
<None Include="..\librf\src\mutex_v2.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
<None Include="..\librf\src\without_deadlock_assemble.inl"> | |||||
<Filter>librf\src</Filter> | |||||
</None> | |||||
<None Include="..\config.h.in" /> | |||||
<None Include="..\asio\asio_task_1.10.0.inl"> | |||||
<Filter>asio</Filter> | |||||
</None> | |||||
<None Include="..\asio\asio_task_1.12.0.inl"> | |||||
<Filter>asio</Filter> | |||||
</None> | |||||
<None Include="..\asio\asio_task_1.12.2.inl"> | |||||
<Filter>asio</Filter> | |||||
</None> | |||||
</ItemGroup> | |||||
</Project> |