Skip to content

Commit

Permalink
Destroy spawned thread immediately if it completes within handler inv…
Browse files Browse the repository at this point in the history
…ocation.
  • Loading branch information
chriskohlhoff committed Jul 31, 2022
1 parent 656cc92 commit 26ab330
Showing 1 changed file with 79 additions and 51 deletions.
130 changes: 79 additions & 51 deletions asio/include/asio/impl/spawn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,57 @@ typedef spawned_coroutine_thread default_spawned_thread_type;
# error No spawn() implementation available
#endif

// Helper class to perform the initial resume on the correct executor.
class spawned_thread_resumer
{
public:
explicit spawned_thread_resumer(spawned_thread_base* spawned_thread)
: spawned_thread_(spawned_thread)
{
#if !defined(ASIO_HAS_MOVE)
spawned_thread->detach();
spawned_thread->attach(&spawned_thread_);
#endif // !defined(ASIO_HAS_MOVE)
}

#if defined(ASIO_HAS_MOVE)

spawned_thread_resumer(spawned_thread_resumer&& other) ASIO_NOEXCEPT
: spawned_thread_(other.spawned_thread_)
{
other.spawned_thread_ = 0;
}

#else // defined(ASIO_HAS_MOVE)

spawned_thread_resumer(
const spawned_thread_resumer& other) ASIO_NOEXCEPT
: spawned_thread_(other.spawned_thread_)
{
spawned_thread_->detach();
spawned_thread_->attach(&spawned_thread_);
}

#endif // defined(ASIO_HAS_MOVE)

~spawned_thread_resumer()
{
if (spawned_thread_)
spawned_thread_->destroy();
}

void operator()()
{
#if defined(ASIO_HAS_MOVE)
spawned_thread_->attach(&spawned_thread_);
#endif // defined(ASIO_HAS_MOVE)
spawned_thread_->resume();
}

private:
spawned_thread_base* spawned_thread_;
};

// Helper class to ensure spawned threads are destroyed on the correct executor.
class spawned_thread_destroyer
{
Expand Down Expand Up @@ -388,10 +439,9 @@ class spawn_handler_base

void resume()
{
#if defined(ASIO_HAS_MOVE)
spawned_thread_->attach(&spawned_thread_);
#endif // defined(ASIO_HAS_MOVE)
spawned_thread_->resume();
spawned_thread_resumer resumer(spawned_thread_);
spawned_thread_ = 0;
resumer();
}

protected:
Expand All @@ -400,23 +450,6 @@ class spawn_handler_base
asio::error_code* ec_;
};

// Helper class to perform the initial resume on the correct executor.
template <typename Executor>
class spawn_launcher
: public spawn_handler_base<Executor>
{
public:
spawn_launcher(const basic_yield_context<Executor>& yield)
: spawn_handler_base<Executor>(yield)
{
}

void operator()()
{
this->resume();
}
};

// Completion handlers for when basic_yield_context is used as a token.
template <typename Executor, typename Signature>
class spawn_handler;
Expand Down Expand Up @@ -1127,13 +1160,12 @@ class initiate_spawn
cancellation_state cancel_state(proxy_slot);

(dispatch)(executor_,
spawn_launcher<Executor>(
basic_yield_context<Executor>(
default_spawned_thread_type::spawn(
spawn_entry_point<Executor, function_type, handler_type>(
executor_, ASIO_MOVE_CAST(F)(f),
ASIO_MOVE_CAST(Handler)(handler)),
proxy_slot, cancel_state), executor_)));
spawned_thread_resumer(
default_spawned_thread_type::spawn(
spawn_entry_point<Executor, function_type, handler_type>(
executor_, ASIO_MOVE_CAST(F)(f),
ASIO_MOVE_CAST(Handler)(handler)),
proxy_slot, cancel_state)));
}

#if defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
Expand Down Expand Up @@ -1163,14 +1195,13 @@ class initiate_spawn
cancellation_state cancel_state(proxy_slot);

(dispatch)(executor_,
spawn_launcher<Executor>(
basic_yield_context<Executor>(
spawned_fiber_thread::spawn(allocator_arg_t(),
ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
spawn_entry_point<Executor, function_type, handler_type>(
executor_, ASIO_MOVE_CAST(F)(f),
ASIO_MOVE_CAST(Handler)(handler)),
proxy_slot, cancel_state), executor_)));
spawned_thread_resumer(
spawned_fiber_thread::spawn(allocator_arg_t(),
ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
spawn_entry_point<Executor, function_type, handler_type>(
executor_, ASIO_MOVE_CAST(F)(f),
ASIO_MOVE_CAST(Handler)(handler)),
proxy_slot, cancel_state)));
}

#endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
Expand Down Expand Up @@ -1454,13 +1485,12 @@ void spawn(ASIO_MOVE_ARG(Handler) handler,
executor_type ex((get_associated_executor)(handler));

(dispatch)(ex,
detail::spawn_launcher<executor_type>(
basic_yield_context<executor_type>(
detail::spawned_coroutine_thread::spawn(
detail::old_spawn_entry_point<executor_type,
function_type, void (*)()>(
ex, ASIO_MOVE_CAST(Function)(function),
&detail::default_spawn_handler), attributes), ex)));
detail::spawned_thread_resumer(
detail::spawned_coroutine_thread::spawn(
detail::old_spawn_entry_point<executor_type,
function_type, void (*)()>(
ex, ASIO_MOVE_CAST(Function)(function),
&detail::default_spawn_handler), attributes)));
}

template <typename Executor, typename Function>
Expand All @@ -1471,14 +1501,12 @@ void spawn(basic_yield_context<Executor> ctx,
typedef typename decay<Function>::type function_type;

(dispatch)(ctx.get_executor(),
detail::spawn_launcher<Executor>(
basic_yield_context<Executor>(
detail::spawned_coroutine_thread::spawn(
detail::old_spawn_entry_point<Executor,
function_type, void (*)()>(ctx.get_executor(),
ASIO_MOVE_CAST(Function)(function),
&detail::default_spawn_handler), attributes),
ctx.get_executor())));
detail::spawned_thread_resumer(
detail::spawned_coroutine_thread::spawn(
detail::old_spawn_entry_point<Executor,
function_type, void (*)()>(ctx.get_executor(),
ASIO_MOVE_CAST(Function)(function),
&detail::default_spawn_handler), attributes)));
}

template <typename Function, typename Executor>
Expand Down

0 comments on commit 26ab330

Please sign in to comment.