]> git.proxmox.com Git - ceph.git/blob - ceph/src/Beast/extras/beast/test/yield_to.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / Beast / extras / beast / test / yield_to.hpp
1 //
2 // Copyright (c) 2013-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
8 #ifndef BEAST_TEST_YIELD_TO_HPP
9 #define BEAST_TEST_YIELD_TO_HPP
10
11 #include <boost/asio/io_service.hpp>
12 #include <boost/asio/spawn.hpp>
13 #include <boost/optional.hpp>
14 #include <condition_variable>
15 #include <functional>
16 #include <mutex>
17 #include <thread>
18
19 namespace beast {
20 namespace test {
21
22 /** Mix-in to support tests using asio coroutines.
23
24 Derive from this class and use yield_to to launch test
25 functions inside coroutines. This is handy for testing
26 asynchronous asio code.
27 */
28 class enable_yield_to
29 {
30 protected:
31 boost::asio::io_service ios_;
32
33 private:
34 boost::optional<boost::asio::io_service::work> work_;
35 std::thread thread_;
36 std::mutex m_;
37 std::condition_variable cv_;
38 bool running_ = false;
39
40 public:
41 /// The type of yield context passed to functions.
42 using yield_context =
43 boost::asio::yield_context;
44
45 enable_yield_to()
46 : work_(ios_)
47 , thread_([&]
48 {
49 ios_.run();
50 }
51 )
52 {
53 }
54
55 ~enable_yield_to()
56 {
57 work_ = boost::none;
58 thread_.join();
59 }
60
61 /// Return the `io_service` associated with the object
62 boost::asio::io_service&
63 get_io_service()
64 {
65 return ios_;
66 }
67
68 /** Run a function in a coroutine.
69
70 This call will block until the coroutine terminates.
71
72 Function will be called with this signature:
73
74 @code
75 void f(args..., yield_context);
76 @endcode
77
78 @param f The Callable object to invoke.
79
80 @param args Optional arguments forwarded to the callable object.
81 */
82 #if BEAST_DOXYGEN
83 template<class F, class... Args>
84 void
85 yield_to(F&& f, Args&&... args);
86 #else
87 template<class F>
88 void
89 yield_to(F&& f);
90
91 template<class Function, class Arg, class... Args>
92 void
93 yield_to(Function&& f, Arg&& arg, Args&&... args)
94 {
95 yield_to(std::bind(f,
96 std::forward<Arg>(arg),
97 std::forward<Args>(args)...,
98 std::placeholders::_1));
99 }
100 #endif
101 };
102
103 template<class Function>
104 void
105 enable_yield_to::yield_to(Function&& f)
106 {
107 {
108 std::lock_guard<std::mutex> lock(m_);
109 running_ = true;
110 }
111 boost::asio::spawn(ios_,
112 [&](boost::asio::yield_context do_yield)
113 {
114 f(do_yield);
115 std::lock_guard<std::mutex> lock(m_);
116 running_ = false;
117 cv_.notify_all();
118 }
119 , boost::coroutines::attributes(2 * 1024 * 1024));
120
121 std::unique_lock<std::mutex> lock(m_);
122 cv_.wait(lock, [&]{ return ! running_; });
123 }
124
125 } // test
126 } // beast
127
128 #endif