|
|
@@ -19,7 +19,9 @@ namespace sophiar {
|
|
|
class coro_worker {
|
|
|
public:
|
|
|
|
|
|
- using pointer = std::shared_ptr<coro_worker>;
|
|
|
+ using pointer = std::unique_ptr<coro_worker>;
|
|
|
+
|
|
|
+ static constexpr auto empty_func = []() {};
|
|
|
|
|
|
virtual ~coro_worker() {
|
|
|
assert(!is_running);
|
|
|
@@ -51,7 +53,7 @@ namespace sophiar {
|
|
|
|
|
|
};
|
|
|
|
|
|
- template<typename Executor, typename FuncType>
|
|
|
+ template<typename Executor, typename FuncType, typename ExitFuncType>
|
|
|
class coro_worker_impl : public coro_worker {
|
|
|
public:
|
|
|
|
|
|
@@ -59,10 +61,14 @@ namespace sophiar {
|
|
|
decltype(std::declval<FuncType>()()),
|
|
|
boost::asio::awaitable<bool>>);
|
|
|
|
|
|
- coro_worker_impl(Executor &_executor, FuncType &&_func)
|
|
|
+ static_assert(std::is_void<
|
|
|
+ decltype(std::declval<ExitFuncType>()())>());
|
|
|
+
|
|
|
+ coro_worker_impl(Executor &_executor, FuncType &&_func, ExitFuncType &&_exit_func)
|
|
|
: coro_worker(_executor),
|
|
|
executor(_executor),
|
|
|
- func(std::forward<FuncType>(_func)) {}
|
|
|
+ func(std::forward<FuncType>(_func)),
|
|
|
+ exit_func(std::forward<ExitFuncType>(_exit_func)) {}
|
|
|
|
|
|
~coro_worker_impl() override = default;
|
|
|
|
|
|
@@ -82,8 +88,10 @@ namespace sophiar {
|
|
|
|
|
|
private:
|
|
|
|
|
|
- using store_type = std::remove_cvref_t<FuncType>;
|
|
|
- store_type func;
|
|
|
+ using func_store_type = std::remove_cvref_t<FuncType>;
|
|
|
+ using exit_func_store_type = std::remove_cvref_t<ExitFuncType>;
|
|
|
+ func_store_type func;
|
|
|
+ exit_func_store_type exit_func;
|
|
|
|
|
|
Executor &executor;
|
|
|
|
|
|
@@ -92,6 +100,7 @@ namespace sophiar {
|
|
|
auto closer = sg::make_scope_guard([this]() {
|
|
|
is_running = false;
|
|
|
stop_finished_signal.try_notify_all();
|
|
|
+ exit_func();
|
|
|
});
|
|
|
for (;;) {
|
|
|
using namespace boost::asio::experimental::awaitable_operators;
|
|
|
@@ -104,14 +113,19 @@ namespace sophiar {
|
|
|
|
|
|
};
|
|
|
|
|
|
- template<typename Executor, typename FuncType>
|
|
|
- auto make_infinite_coro_worker(Executor &executor, FuncType &&func) {
|
|
|
- return coro_worker::pointer(new coro_worker_impl<Executor, FuncType>(
|
|
|
- executor, std::forward<FuncType>(func)));
|
|
|
+ template<typename Executor, typename FuncType,
|
|
|
+ typename ExitFuncType = decltype(coro_worker::empty_func) const &>
|
|
|
+ auto make_infinite_coro_worker(Executor &executor, FuncType &&func,
|
|
|
+ ExitFuncType &&exit_func = coro_worker::empty_func) {
|
|
|
+ return coro_worker::pointer(new coro_worker_impl<Executor, FuncType, ExitFuncType>(
|
|
|
+ executor, std::forward<FuncType>(func), std::forward<ExitFuncType>(exit_func))
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
- template<typename Executor, typename FuncType>
|
|
|
- auto make_interval_coro_worker(Executor &executor, std::chrono::milliseconds interval, FuncType &&func) {
|
|
|
+ template<typename Executor, typename FuncType,
|
|
|
+ typename ExitFuncType = decltype(coro_worker::empty_func) const &>
|
|
|
+ auto make_interval_coro_worker(Executor &executor, std::chrono::milliseconds interval,
|
|
|
+ FuncType &&func, ExitFuncType &&exit_func = coro_worker::empty_func) {
|
|
|
auto worker_func = [
|
|
|
interval,
|
|
|
func = std::forward<FuncType>(func),
|
|
|
@@ -122,7 +136,37 @@ namespace sophiar {
|
|
|
co_await timer.async_wait(boost::asio::use_awaitable);
|
|
|
co_return ret;
|
|
|
};
|
|
|
- return make_infinite_coro_worker(executor, std::move(worker_func));
|
|
|
+ return make_infinite_coro_worker(executor, std::move(worker_func),
|
|
|
+ std::forward<ExitFuncType>(exit_func));
|
|
|
+ }
|
|
|
+
|
|
|
+ static constexpr auto empty_exception_handler = [](std::exception &) {};
|
|
|
+
|
|
|
+ template<typename FuncType,
|
|
|
+ typename ErrorHandlerType = decltype(empty_exception_handler) const &>
|
|
|
+ auto make_noexcept_func(FuncType &&func,
|
|
|
+ ErrorHandlerType &&error_handler = empty_exception_handler) {
|
|
|
+ static_assert(std::is_convertible_v<
|
|
|
+ decltype(std::declval<FuncType>()()),
|
|
|
+ boost::asio::awaitable<bool>>);
|
|
|
+ static_assert(std::is_void<
|
|
|
+ decltype(std::declval<ErrorHandlerType>()(
|
|
|
+ std::declval<std::exception &>()))>());
|
|
|
+ auto noexcept_func = [
|
|
|
+ real_func = std::forward<FuncType>(func),
|
|
|
+ error_handler = std::forward<ErrorHandlerType>(error_handler)]() mutable noexcept
|
|
|
+ -> boost::asio::awaitable<bool> {
|
|
|
+ try {
|
|
|
+ auto ok = co_await real_func();
|
|
|
+ co_return ok;
|
|
|
+ } catch (std::exception &e) {
|
|
|
+ error_handler(e);
|
|
|
+ co_return false;
|
|
|
+ }
|
|
|
+ assert(false);
|
|
|
+ co_return false;
|
|
|
+ };
|
|
|
+ return std::move(noexcept_func);
|
|
|
}
|
|
|
|
|
|
}
|