Prevent blocking.always from being used with strand<>.

Previously, calling `require(E, blocking.always)` on a strand E compiled
but produced incorrect behaviour. Now, `require(E, blocking.always)`
will no longer compile. Furthermore, when used with an always-blocking
inner executor, the strand will report its blocking property as
blocking.possibly.
This commit is contained in:
Christopher Kohlhoff 2021-04-06 11:44:17 +10:00
parent 69f98d2cde
commit ef0c424b00

View File

@ -18,6 +18,7 @@
#include "asio/detail/config.hpp"
#include "asio/detail/strand_executor_service.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/execution/blocking.hpp"
#include "asio/execution/executor.hpp"
#include "asio/is_executor.hpp"
@ -157,7 +158,7 @@ public:
/// Forward a query to the underlying executor.
/**
* Do not call this function directly. It is intended for use with the
* execution::execute customisation point.
* asio::query customisation point.
*
* For example:
* @code asio::strand<my_executor_type> ex = ...;
@ -168,12 +169,17 @@ public:
template <typename Property>
typename constraint<
can_query<const Executor&, Property>::value,
typename query_result<const Executor&, Property>::type
typename conditional<
is_convertible<Property, execution::blocking_t>::value,
execution::blocking_t,
typename query_result<const Executor&, Property>::type
>::type
>::type query(const Property& p) const
ASIO_NOEXCEPT_IF((
is_nothrow_query<const Executor&, Property>::value))
{
return asio::query(executor_, p);
return this->query_helper(
is_convertible<Property, execution::blocking_t>(), p);
}
/// Forward a requirement to the underlying executor.
@ -188,7 +194,8 @@ public:
*/
template <typename Property>
typename constraint<
can_require<const Executor&, Property>::value,
can_require<const Executor&, Property>::value
&& !is_convertible<Property, execution::blocking_t::always_t>::value,
strand<typename decay<
typename require_result<const Executor&, Property>::type
>::type>
@ -213,7 +220,8 @@ public:
*/
template <typename Property>
typename constraint<
can_prefer<const Executor&, Property>::value,
can_prefer<const Executor&, Property>::value
&& !is_convertible<Property, execution::blocking_t::always_t>::value,
strand<typename decay<
typename prefer_result<const Executor&, Property>::type
>::type>
@ -406,6 +414,21 @@ private:
{
}
template <typename Property>
typename query_result<const Executor&, Property>::type query_helper(
false_type, const Property& property) const
{
return asio::query(executor_, property);
}
template <typename Property>
execution::blocking_t query_helper(true_type, const Property& property) const
{
execution::blocking_t result = asio::query(executor_, property);
return result == execution::blocking.always
? execution::blocking.possibly : result;
}
Executor executor_;
implementation_type impl_;
};
@ -481,7 +504,10 @@ struct query_member<strand<Executor>, Property,
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
(is_nothrow_query<Executor, Property>::value));
typedef typename query_result<Executor, Property>::type result_type;
typedef typename conditional<
is_convertible<Property, execution::blocking_t>::value,
execution::blocking_t, typename query_result<Executor, Property>::type
>::type result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
@ -492,6 +518,7 @@ template <typename Executor, typename Property>
struct require_member<strand<Executor>, Property,
typename enable_if<
can_require<const Executor&, Property>::value
&& !is_convertible<Property, execution::blocking_t::always_t>::value
>::type>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
@ -510,6 +537,7 @@ template <typename Executor, typename Property>
struct prefer_member<strand<Executor>, Property,
typename enable_if<
can_prefer<const Executor&, Property>::value
&& !is_convertible<Property, execution::blocking_t::always_t>::value
>::type>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);