]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/extras/include/boost/beast/test/yield_to.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / beast / test / extras / include / boost / beast / test / yield_to.hpp
1 //
2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9
10 #ifndef BOOST_BEAST_TEST_YIELD_TO_HPP
11 #define BOOST_BEAST_TEST_YIELD_TO_HPP
12
13 #include <boost/asio/io_context.hpp>
14 #include <boost/asio/spawn.hpp>
15 #include <boost/optional.hpp>
16 #include <condition_variable>
17 #include <functional>
18 #include <mutex>
19 #include <thread>
20 #include <vector>
21
22 namespace boost {
23 namespace beast {
24 namespace test {
25
26 /** Mix-in to support tests using asio coroutines.
27
28 Derive from this class and use yield_to to launch test
29 functions inside coroutines. This is handy for testing
30 asynchronous asio code.
31 */
32 class enable_yield_to
33 {
34 protected:
35 boost::asio::io_context ioc_;
36
37 private:
38 boost::optional<
39 boost::asio::executor_work_guard<
40 boost::asio::io_context::executor_type>> work_;
41 std::vector<std::thread> threads_;
42 std::mutex m_;
43 std::condition_variable cv_;
44 std::size_t running_ = 0;
45
46 public:
47 /// The type of yield context passed to functions.
48 using yield_context =
49 boost::asio::yield_context;
50
51 explicit
52 enable_yield_to(std::size_t concurrency = 1)
53 : work_(ioc_.get_executor())
54 {
55 threads_.reserve(concurrency);
56 while(concurrency--)
57 threads_.emplace_back(
58 [&]{ ioc_.run(); });
59 }
60
61 ~enable_yield_to()
62 {
63 work_ = boost::none;
64 for(auto& t : threads_)
65 t.join();
66 }
67
68 /// Return the `io_context` associated with the object
69 boost::asio::io_context&
70 get_io_service()
71 {
72 return ioc_;
73 }
74
75 /** Run one or more functions, each in a coroutine.
76
77 This call will block until all coroutines terminate.
78
79 Each functions should have this signature:
80 @code
81 void f(yield_context);
82 @endcode
83
84 @param fn... One or more functions to invoke.
85 */
86 #if BOOST_BEAST_DOXYGEN
87 template<class... FN>
88 void
89 yield_to(FN&&... fn)
90 #else
91 template<class F0, class... FN>
92 void
93 yield_to(F0&& f0, FN&&... fn);
94 #endif
95
96 private:
97 void
98 spawn()
99 {
100 }
101
102 template<class F0, class... FN>
103 void
104 spawn(F0&& f, FN&&... fn);
105 };
106
107 template<class F0, class... FN>
108 void
109 enable_yield_to::
110 yield_to(F0&& f0, FN&&... fn)
111 {
112 running_ = 1 + sizeof...(FN);
113 spawn(f0, fn...);
114 std::unique_lock<std::mutex> lock{m_};
115 cv_.wait(lock, [&]{ return running_ == 0; });
116 }
117
118 template<class F0, class... FN>
119 inline
120 void
121 enable_yield_to::
122 spawn(F0&& f, FN&&... fn)
123 {
124 boost::asio::spawn(ioc_,
125 [&](yield_context yield)
126 {
127 f(yield);
128 std::lock_guard<std::mutex> lock{m_};
129 if(--running_ == 0)
130 cv_.notify_all();
131 }
132 , boost::coroutines::attributes(2 * 1024 * 1024));
133 spawn(fn...);
134 }
135
136 } // test
137 } // beast
138 } // boost
139
140 #endif