]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/example/cpp11/invocation/prioritised_handlers.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / asio / example / cpp11 / invocation / prioritised_handlers.cpp
1 //
2 // prioritised_handlers.cpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10
11 #include <boost/asio.hpp>
12 #include <iostream>
13 #include <memory>
14 #include <queue>
15
16 using boost::asio::ip::tcp;
17
18 class handler_priority_queue : boost::asio::execution_context
19 {
20 public:
21 template <typename Function>
22 void add(int priority, Function function)
23 {
24 std::unique_ptr<queued_handler_base> handler(
25 new queued_handler<Function>(
26 priority, std::move(function)));
27
28 handlers_.push(std::move(handler));
29 }
30
31 void execute_all()
32 {
33 while (!handlers_.empty())
34 {
35 handlers_.top()->execute();
36 handlers_.pop();
37 }
38 }
39
40 class executor
41 {
42 public:
43 executor(handler_priority_queue& q, int p)
44 : context_(q), priority_(p)
45 {
46 }
47
48 handler_priority_queue& context() const noexcept
49 {
50 return context_;
51 }
52
53 template <typename Function, typename Allocator>
54 void dispatch(Function f, const Allocator&) const
55 {
56 context_.add(priority_, std::move(f));
57 }
58
59 template <typename Function, typename Allocator>
60 void post(Function f, const Allocator&) const
61 {
62 context_.add(priority_, std::move(f));
63 }
64
65 template <typename Function, typename Allocator>
66 void defer(Function f, const Allocator&) const
67 {
68 context_.add(priority_, std::move(f));
69 }
70
71 void on_work_started() const noexcept {}
72 void on_work_finished() const noexcept {}
73
74 bool operator==(const executor& other) const noexcept
75 {
76 return &context_ == &other.context_ && priority_ == other.priority_;
77 }
78
79 bool operator!=(const executor& other) const noexcept
80 {
81 return !operator==(other);
82 }
83
84 private:
85 handler_priority_queue& context_;
86 int priority_;
87 };
88
89 template <typename Handler>
90 boost::asio::executor_binder<Handler, executor>
91 wrap(int priority, Handler handler)
92 {
93 return boost::asio::bind_executor(
94 executor(*this, priority), std::move(handler));
95 }
96
97 private:
98 class queued_handler_base
99 {
100 public:
101 queued_handler_base(int p)
102 : priority_(p)
103 {
104 }
105
106 virtual ~queued_handler_base()
107 {
108 }
109
110 virtual void execute() = 0;
111
112 friend bool operator<(const std::unique_ptr<queued_handler_base>& a,
113 const std::unique_ptr<queued_handler_base>& b) noexcept
114 {
115 return a->priority_ < b->priority_;
116 }
117
118 private:
119 int priority_;
120 };
121
122 template <typename Function>
123 class queued_handler : public queued_handler_base
124 {
125 public:
126 queued_handler(int p, Function f)
127 : queued_handler_base(p), function_(std::move(f))
128 {
129 }
130
131 void execute() override
132 {
133 function_();
134 }
135
136 private:
137 Function function_;
138 };
139
140 std::priority_queue<std::unique_ptr<queued_handler_base>> handlers_;
141 };
142
143 //----------------------------------------------------------------------
144
145 void high_priority_handler(const boost::system::error_code& /*ec*/)
146 {
147 std::cout << "High priority handler\n";
148 }
149
150 void middle_priority_handler(const boost::system::error_code& /*ec*/)
151 {
152 std::cout << "Middle priority handler\n";
153 }
154
155 struct low_priority_handler
156 {
157 // Make the handler a move-only type.
158 low_priority_handler() = default;
159 low_priority_handler(const low_priority_handler&) = delete;
160 low_priority_handler(low_priority_handler&&) = default;
161
162 void operator()()
163 {
164 std::cout << "Low priority handler\n";
165 }
166 };
167
168 int main()
169 {
170 boost::asio::io_context io_context;
171
172 handler_priority_queue pri_queue;
173
174 // Post a completion handler to be run immediately.
175 boost::asio::post(io_context, pri_queue.wrap(0, low_priority_handler()));
176
177 // Start an asynchronous accept that will complete immediately.
178 tcp::endpoint endpoint(boost::asio::ip::address_v4::loopback(), 0);
179 tcp::acceptor acceptor(io_context, endpoint);
180 tcp::socket server_socket(io_context);
181 acceptor.async_accept(server_socket,
182 pri_queue.wrap(100, high_priority_handler));
183 tcp::socket client_socket(io_context);
184 client_socket.connect(acceptor.local_endpoint());
185
186 // Set a deadline timer to expire immediately.
187 boost::asio::steady_timer timer(io_context);
188 timer.expires_at(boost::asio::steady_timer::clock_type::time_point::min());
189 timer.async_wait(pri_queue.wrap(42, middle_priority_handler));
190
191 while (io_context.run_one())
192 {
193 // The custom invocation hook adds the handlers to the priority queue
194 // rather than executing them from within the poll_one() call.
195 while (io_context.poll_one())
196 ;
197
198 pri_queue.execute_all();
199 }
200
201 return 0;
202 }