2
0
mirror of https://github.com/boostorg/fiber.git synced 2026-02-21 02:52:18 +00:00

Eliminate yield_hop_t, therefore yield_base type.

The whole yield / yield_hop dichotomy becomes much easier to read and explain
if we stick to a single yield_t class. Since the intention is for a consumer
to pass canonical instances rather than manipulating that class in any other
way, we can instantiate it however we want.

This gets rid of lots of ugly redundant boost::asio::handler_type<>
specializations.
This commit is contained in:
Nat Goodspeed
2016-03-23 21:43:01 -04:00
parent 85c0d26d11
commit cba1a74b70
2 changed files with 25 additions and 59 deletions

View File

@@ -54,11 +54,11 @@ struct yield_completion {
// should be instantiated only once.
class yield_handler_base {
public:
yield_handler_base( yield_base const& y) :
yield_handler_base( yield_t const& y) :
// capture the context* associated with the running fiber
ctx_( boost::fibers::context::active() ),
// capture the passed yield_base
yb_( y )
// capture the passed yield_t
yt_( y )
{}
// completion callback passing only (error_code)
@@ -67,7 +67,7 @@ public:
BOOST_ASSERT_MSG( ycomp_,
"Must inject yield_completion* "
"before calling yield_handler_base::operator()()");
BOOST_ASSERT_MSG( yb_.ec_,
BOOST_ASSERT_MSG( yt_.ec_,
"Must inject boost::system::error_code* "
"before calling yield_handler_base::operator()()");
// If originating fiber is busy testing completed_ flag, wait until it
@@ -77,13 +77,13 @@ public:
// suspend.
ycomp_->completed_ = true;
// set the error_code bound by yield_t
* yb_.ec_ = ec;
* 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 )) && yb_.allow_hop_ ) {
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_t
// rather than yield_t, migrate this fiber to the running thread.
// 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
@@ -92,7 +92,7 @@ public:
//private:
boost::fibers::context * ctx_;
yield_base yb_;
yield_t yt_;
// We depend on this pointer to yield_completion, which will be injected
// by async_result.
yield_completion * ycomp_{ nullptr };
@@ -107,7 +107,7 @@ template< typename T >
class yield_handler: public yield_handler_base {
public:
// asio passes the completion token to the handler constructor
explicit yield_handler( yield_base const& y) :
explicit yield_handler( yield_t const& y) :
yield_handler_base( y)
{}
@@ -142,7 +142,7 @@ public:
template<>
class yield_handler< void >: public yield_handler_base {
public:
explicit yield_handler( yield_base const& y) :
explicit yield_handler( yield_t const& y) :
yield_handler_base( y)
{}
@@ -175,8 +175,8 @@ public:
// error_code* point to an error_code local to this object so
// yield_handler_base::operator() can unconditionally store through
// its error_code*
if ( ! h.yb_.ec_) {
h.yb_.ec_ = & ec_;
if ( ! h.yt_.ec_) {
h.yt_.ec_ = & ec_;
}
}
@@ -255,42 +255,24 @@ public:
// When 'yield' is passed as a completion handler which accepts no parameters,
// use yield_handler<void>.
template< typename ReturnType >
struct handler_type< fibers::asio::yield_base, ReturnType() >
{ typedef fibers::asio::detail::yield_handler< void > type; };
template< typename ReturnType >
struct handler_type< fibers::asio::yield_t, ReturnType() >
{ typedef fibers::asio::detail::yield_handler< void > type; };
template< typename ReturnType >
struct handler_type< fibers::asio::yield_hop_t, ReturnType() >
{ typedef fibers::asio::detail::yield_handler< void > type; };
// Handler type specialisation for fibers::asio::yield.
// When 'yield' is passed as a completion handler which accepts a data
// parameter, use yield_handler<parameter type> to return that parameter to
// the caller.
template< typename ReturnType, typename Arg1 >
struct handler_type< fibers::asio::yield_base, ReturnType( Arg1) >
{ typedef fibers::asio::detail::yield_handler< Arg1 > type; };
template< typename ReturnType, typename Arg1 >
struct handler_type< fibers::asio::yield_t, ReturnType( Arg1) >
{ typedef fibers::asio::detail::yield_handler< Arg1 > type; };
template< typename ReturnType, typename Arg1 >
struct handler_type< fibers::asio::yield_hop_t, ReturnType( Arg1) >
{ typedef fibers::asio::detail::yield_handler< Arg1 > type; };
// Handler type specialisation for fibers::asio::yield.
// When 'yield' is passed as a completion handler which accepts only
// error_code, use yield_handler<void>. yield_handler will take care of the
// error_code one way or another.
template< typename ReturnType >
struct handler_type< fibers::asio::yield_base, ReturnType( boost::system::error_code) >
{ typedef fibers::asio::detail::yield_handler< void > type; };
template< typename ReturnType >
struct handler_type< fibers::asio::yield_t, ReturnType( boost::system::error_code) >
{ typedef fibers::asio::detail::yield_handler< void > type; };
template< typename ReturnType >
struct handler_type< fibers::asio::yield_hop_t, ReturnType( boost::system::error_code) >
{ typedef fibers::asio::detail::yield_handler< void > type; };
// Handler type specialisation for fibers::asio::yield.
// When 'yield' is passed as a completion handler which accepts a data
@@ -298,14 +280,8 @@ struct handler_type< fibers::asio::yield_hop_t, ReturnType( boost::system::error
// just the parameter to the caller. yield_handler will take care of the
// error_code one way or another.
template< typename ReturnType, typename Arg2 >
struct handler_type< fibers::asio::yield_base, ReturnType( boost::system::error_code, Arg2) >
{ typedef fibers::asio::detail::yield_handler< Arg2 > type; };
template< typename ReturnType, typename Arg2 >
struct handler_type< fibers::asio::yield_t, ReturnType( boost::system::error_code, Arg2) >
{ typedef fibers::asio::detail::yield_handler< Arg2 > type; };
template< typename ReturnType, typename Arg2 >
struct handler_type< fibers::asio::yield_hop_t, ReturnType( boost::system::error_code, Arg2) >
{ typedef fibers::asio::detail::yield_handler< Arg2 > type; };
} // namespace asio
} // namespace boost

View File

@@ -13,8 +13,6 @@
#ifndef BOOST_FIBERS_ASIO_YIELD_HPP
#define BOOST_FIBERS_ASIO_YIELD_HPP
#include <memory>
#include <boost/config.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
@@ -25,24 +23,26 @@ namespace boost {
namespace fibers {
namespace asio {
class yield_base {
class yield_t {
public:
constexpr yield_base() = default;
yield_t(bool hop):
allow_hop_( hop)
{}
/**
* @code
* static yield_base yield;
* static yield_t yield;
* boost::system::error_code myec;
* func(yield[myec]);
* @endcode
* @c yield[myec] returns an instance of @c yield_base whose @c ec_ points
* @c yield[myec] returns an instance of @c yield_t whose @c ec_ points
* to @c myec. The expression @c yield[myec] "binds" @c myec to that
* (anonymous) @c yield_base instance, instructing @c func() to store any
* (anonymous) @c yield_t instance, instructing @c func() to store any
* @c error_code it might produce into @c myec rather than throwing @c
* boost::system::system_error.
*/
yield_base operator[]( boost::system::error_code & ec) const {
yield_base tmp{ *this };
yield_t operator[]( boost::system::error_code & ec) const {
yield_t tmp{ *this };
tmp.ec_ = & ec;
return tmp;
}
@@ -52,23 +52,13 @@ public:
boost::system::error_code * ec_{ nullptr };
// allow calling fiber to "hop" to another thread if it could resume more
// quickly that way
bool allow_hop_{ false };
};
class yield_t : public yield_base {
};
class yield_hop_t : public yield_base {
public:
yield_hop_t() {
allow_hop_ = true;
}
bool allow_hop_;
};
// canonical instance with allow_hop_ == false
thread_local yield_t yield{};
thread_local yield_t yield(false);
// canonical instance with allow_hop_ == true
thread_local yield_hop_t yield_hop{};
thread_local yield_t yield_hop(true);
}}}