Skip to content

Commit c1d9a26

Browse files
committed
common/async: blocked_completion uses our redirect_error
Generalizing it to exceptions, etc. Signed-off-by: Adam C. Emerson <[email protected]>
1 parent b0f2bb7 commit c1d9a26

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

src/common/async/blocked_completion.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,44 @@
1616
#ifndef CEPH_COMMON_ASYNC_BLOCKED_COMPLETION_H
1717
#define CEPH_COMMON_ASYNC_BLOCKED_COMPLETION_H
1818

19+
/// \file common/async/blocked_completion.h
20+
///
21+
/// \brief A blocking `completion token`
22+
///
23+
/// This completion token will actually hard-block your thread. Do not
24+
/// do so within an `io_context` thread.
25+
1926
#include <condition_variable>
2027
#include <mutex>
2128
#include <optional>
2229

2330
#include <boost/asio/async_result.hpp>
24-
#include <boost/asio/redirect_error.hpp>
31+
#include <boost/asio/disposition.hpp>
2532

2633
#include <boost/system/error_code.hpp>
2734

28-
#include <common/async/concepts.h>
35+
#include "common/async/redirect_error.h"
2936

3037
namespace ceph::async {
31-
32-
namespace bs = boost::system;
33-
38+
/// A \ref `completion token` type that blocks the current thread
39+
/// until the operation completes.
40+
///
41+
/// \warning Keep deadlocks in mind. Do not use in threads that expect
42+
/// to be asynchronous.
3443
class use_blocked_t {
3544
public:
3645
use_blocked_t() = default;
3746

38-
auto operator [](bs::error_code& ec) const {
39-
return boost::asio::redirect_error(use_blocked_t{}, ec);
47+
/// Redirect the \ref `disposition` of the operation to a
48+
/// variable. (A `disposition` is a concept generalizing error codes
49+
/// and exceptions.)
50+
template<boost::asio::disposition Disposition>
51+
auto operator [](Disposition& d) const {
52+
return redirect_error(use_blocked_t{}, d);
4053
}
4154
};
4255

56+
/// The archetypical instance of `use_blocked_t`
4357
inline constexpr use_blocked_t use_blocked;
4458

4559
namespace detail {

src/test/common/test_blocked_completion.cc

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@
1212
*
1313
*/
1414

15+
#include "common/async/blocked_completion.h"
16+
17+
#include <exception>
1518

1619
#include <boost/asio/append.hpp>
20+
#include <boost/asio/awaitable.hpp>
1721
#include <boost/asio/async_result.hpp>
22+
#include <boost/asio/co_spawn.hpp>
1823
#include <boost/asio/io_context.hpp>
1924
#include <boost/asio/post.hpp>
2025
#include <boost/asio/steady_timer.hpp>
@@ -23,7 +28,7 @@
2328

2429
#include <gtest/gtest.h>
2530

26-
#include "common/async/blocked_completion.h"
31+
2732
using namespace std::literals;
2833

2934
namespace asio = boost::asio;
@@ -152,6 +157,44 @@ TEST(BlockedCompletion, AnError)
152157
EXPECT_EQ(sys::error_code(EDOM, sys::system_category()), ec);
153158
}
154159

160+
TEST(BlockedCompletion, AnException)
161+
{
162+
context_thread t;
163+
std::exception_ptr e = nullptr;
164+
165+
ASSERT_FALSE(e);
166+
ASSERT_THROW(asio::co_spawn(t.get_executor(),
167+
[]() -> asio::awaitable<void> {
168+
throw std::exception{};
169+
co_return;
170+
}, async::use_blocked),
171+
std::exception);
172+
// Have yet to divert an exception
173+
ASSERT_FALSE(e);
174+
175+
ASSERT_NO_THROW(asio::co_spawn(t.get_executor(),
176+
[]() -> asio::awaitable<void> {
177+
throw std::exception{};
178+
co_return;
179+
}, async::use_blocked[e]));
180+
// Exception diverted
181+
ASSERT_TRUE(e);
182+
183+
ASSERT_NO_THROW(asio::co_spawn(t.get_executor(),
184+
[]() -> asio::awaitable<void> {
185+
co_return;
186+
}, async::use_blocked));
187+
// Previously diverted exception not overwritten
188+
ASSERT_TRUE(e);
189+
190+
ASSERT_NO_THROW(asio::co_spawn(t.get_executor(),
191+
[]() -> asio::awaitable<void> {
192+
co_return;
193+
}, async::use_blocked[e]));
194+
// Success diverted to overwrite previous exception
195+
ASSERT_FALSE(e);
196+
}
197+
155198
TEST(BlockedCompletion, MoveOnly)
156199
{
157200
context_thread t;

0 commit comments

Comments
 (0)