From abfc4cab2a09d697f5e8a31f30c164d374fe10b7 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 2 Apr 2016 12:16:17 -0400 Subject: [PATCH] Defend yield_handler_base::operator() against immediate callback. If the async operation invoked by the asio async function immediately calls yield_handler_base::operator() even before control reaches async_result_base::get(), which would suspend the calling fiber, the context* bound by yield_handler_base's constructor is still the active() context. This may not be passed to context::migrate(). It probably shouldn't be passed to context::set_ready(), either. --- examples/asio/detail/yield.hpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/examples/asio/detail/yield.hpp b/examples/asio/detail/yield.hpp index b35f3a81..29077c08 100644 --- a/examples/asio/detail/yield.hpp +++ b/examples/asio/detail/yield.hpp @@ -85,16 +85,22 @@ public: ycomp_->completed_ = true; // set the error_code bound by yield_t * yt_.ec_ = ec; - // Are we permitted to wake up the suspended fiber on this thread, the - // thread that called the completion handler? - if ( ( ! ctx_->is_context( fibers::type::pinned_context) ) && yt_.allow_hop_) { - // We must not migrate a pinned_context to another thread. If this - // isn't a pinned_context, and the application passed yield_hop - // rather than yield, migrate this fiber to the running thread. - fibers::context::active()->migrate( ctx_); + // If ctx_ is still active, e.g. because the async operation + // immediately called its callback (this method!) before the asio + // async function called async_result_base::get(), we must neither + // migrate it nor set it ready. + if ( fibers::context::active() != ctx_ ) { + // Are we permitted to wake up the suspended fiber on this thread, the + // thread that called the completion handler? + if ( ( ! ctx_->is_context( fibers::type::pinned_context) ) && yt_.allow_hop_) { + // We must not migrate a pinned_context to another thread. If this + // isn't a pinned_context, and the application passed yield_hop + // rather than yield, migrate this fiber to the running thread. + fibers::context::active()->migrate( ctx_); + } + // either way, wake the fiber + fibers::context::active()->set_ready( ctx_); } - // either way, wake the fiber - fibers::context::active()->set_ready( ctx_); } //private: