diff --git a/asio/include/asio/impl/spawn.hpp b/asio/include/asio/impl/spawn.hpp index 1d0a8a1727..2813ef36e1 100644 --- a/asio/include/asio/impl/spawn.hpp +++ b/asio/include/asio/impl/spawn.hpp @@ -45,6 +45,14 @@ namespace asio { namespace detail { +#if !defined(ASIO_NO_EXCEPTIONS) +static void spawned_thread_rethrow(void* ex) +{ + if (*static_cast(ex)) + rethrow_exception(*static_cast(ex)); +} +#endif // !defined(ASIO_NO_EXCEPTIONS) + #if defined(ASIO_HAS_BOOST_COROUTINE) // Spawned thread implementation using Boost.Coroutine. @@ -117,6 +125,8 @@ class spawned_coroutine_thread : public spawned_thread_base { callee_type callee; callee.swap(callee_); + if (terminal_) + callee(); } private: @@ -139,8 +149,26 @@ class spawned_coroutine_thread : public spawned_thread_base *spawned_thread_out_ = &spawned_thread; spawned_thread_out_ = 0; spawned_thread.suspend(); - function(&spawned_thread); - spawned_thread.suspend(); +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) + { + function(&spawned_thread); + spawned_thread.terminal_ = true; + spawned_thread.suspend(); + } +#if !defined(ASIO_NO_EXCEPTIONS) + catch (const boost::coroutines::detail::forced_unwind&) + { + throw; + } + catch (...) + { + exception_ptr ex = current_exception(); + spawned_thread.terminal_ = true; + spawned_thread.suspend_with(spawned_thread_rethrow, &ex); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) } private: @@ -225,7 +253,8 @@ class spawned_fiber_thread : public spawned_thread_base void destroy() { fiber_type callee = ASIO_MOVE_CAST(fiber_type)(callee_); - (void)callee; + if (terminal_) + fiber_type(ASIO_MOVE_CAST(fiber_type)(callee)).resume(); } private: @@ -249,9 +278,27 @@ class spawned_fiber_thread : public spawned_thread_base *spawned_thread_out_ = &spawned_thread; spawned_thread_out_ = 0; spawned_thread.suspend(); - function(&spawned_thread); - spawned_thread.suspend(); - return {}; +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) + { + function(&spawned_thread); + spawned_thread.terminal_ = true; + spawned_thread.suspend(); + } +#if !defined(ASIO_NO_EXCEPTIONS) + catch (const boost::context::detail::forced_unwind&) + { + throw; + } + catch (...) + { + exception_ptr ex = current_exception(); + spawned_thread.terminal_ = true; + spawned_thread.suspend_with(spawned_thread_rethrow, &ex); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) + return ASIO_MOVE_CAST(fiber_type)(spawned_thread.caller_); } private: diff --git a/asio/include/asio/spawn.hpp b/asio/include/asio/spawn.hpp index 5bd56c074b..5495cb396e 100644 --- a/asio/include/asio/spawn.hpp +++ b/asio/include/asio/spawn.hpp @@ -42,7 +42,8 @@ class spawned_thread_base spawned_thread_base() : owner_(0), has_context_switched_(false), - throw_if_cancelled_(false) + throw_if_cancelled_(false), + terminal_(false) { } @@ -130,6 +131,7 @@ class spawned_thread_base asio::cancellation_state cancellation_state_; bool has_context_switched_; bool throw_if_cancelled_; + bool terminal_; private: // Disallow copying and assignment. diff --git a/asio/src/examples/cpp11/spawn/echo_server.cpp b/asio/src/examples/cpp11/spawn/echo_server.cpp index 39e3d04c2f..012718feb4 100644 --- a/asio/src/examples/cpp11/spawn/echo_server.cpp +++ b/asio/src/examples/cpp11/spawn/echo_server.cpp @@ -99,7 +99,12 @@ int main(int argc, char* argv[]) std::make_shared(io_context, std::move(socket))->go(); } } - }, asio::detached); + }, + [](std::exception_ptr e) + { + if (e) + std::rethrow_exception(e); + }); io_context.run(); }