]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/test/strand.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / asio / test / strand.cpp
1 //
2 // strand.cpp
3 // ~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2016 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 // Disable autolinking for unit tests.
12 #if !defined(BOOST_ALL_NO_LIB)
13 #define BOOST_ALL_NO_LIB 1
14 #endif // !defined(BOOST_ALL_NO_LIB)
15
16 // Test that header file is self-contained.
17 #include <boost/asio/strand.hpp>
18
19 #include <sstream>
20 #include <boost/asio/io_service.hpp>
21 #include <boost/asio/detail/thread.hpp>
22 #include "unit_test.hpp"
23
24 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
25 # include <boost/asio/deadline_timer.hpp>
26 #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
27 # include <boost/asio/steady_timer.hpp>
28 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
29
30 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
31 # include <boost/bind.hpp>
32 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
33 # include <functional>
34 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
35
36 using namespace boost::asio;
37
38 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
39 namespace bindns = boost;
40 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
41 namespace bindns = std;
42 #endif
43
44 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
45 typedef deadline_timer timer;
46 namespace chronons = boost::posix_time;
47 #elif defined(BOOST_ASIO_HAS_STD_CHRONO)
48 typedef steady_timer timer;
49 namespace chronons = std::chrono;
50 #elif defined(BOOST_ASIO_HAS_BOOST_CHRONO)
51 typedef steady_timer timer;
52 namespace chronons = boost::chrono;
53 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
54
55 void increment(int* count)
56 {
57 ++(*count);
58 }
59
60 void increment_without_lock(io_service::strand* s, int* count)
61 {
62 BOOST_ASIO_CHECK(!s->running_in_this_thread());
63
64 int original_count = *count;
65
66 s->dispatch(bindns::bind(increment, count));
67
68 // No other functions are currently executing through the locking dispatcher,
69 // so the previous call to dispatch should have successfully nested.
70 BOOST_ASIO_CHECK(*count == original_count + 1);
71 }
72
73 void increment_with_lock(io_service::strand* s, int* count)
74 {
75 BOOST_ASIO_CHECK(s->running_in_this_thread());
76
77 int original_count = *count;
78
79 s->dispatch(bindns::bind(increment, count));
80
81 // The current function already holds the strand's lock, so the
82 // previous call to dispatch should have successfully nested.
83 BOOST_ASIO_CHECK(*count == original_count + 1);
84 }
85
86 void sleep_increment(io_service* ios, int* count)
87 {
88 timer t(*ios, chronons::seconds(2));
89 t.wait();
90
91 ++(*count);
92 }
93
94 void start_sleep_increments(io_service* ios, io_service::strand* s, int* count)
95 {
96 // Give all threads a chance to start.
97 timer t(*ios, chronons::seconds(2));
98 t.wait();
99
100 // Start three increments.
101 s->post(bindns::bind(sleep_increment, ios, count));
102 s->post(bindns::bind(sleep_increment, ios, count));
103 s->post(bindns::bind(sleep_increment, ios, count));
104 }
105
106 void throw_exception()
107 {
108 throw 1;
109 }
110
111 void io_service_run(io_service* ios)
112 {
113 ios->run();
114 }
115
116 void strand_test()
117 {
118 io_service ios;
119 io_service::strand s(ios);
120 int count = 0;
121
122 ios.post(bindns::bind(increment_without_lock, &s, &count));
123
124 // No handlers can be called until run() is called.
125 BOOST_ASIO_CHECK(count == 0);
126
127 ios.run();
128
129 // The run() call will not return until all work has finished.
130 BOOST_ASIO_CHECK(count == 1);
131
132 count = 0;
133 ios.reset();
134 s.post(bindns::bind(increment_with_lock, &s, &count));
135
136 // No handlers can be called until run() is called.
137 BOOST_ASIO_CHECK(count == 0);
138
139 ios.run();
140
141 // The run() call will not return until all work has finished.
142 BOOST_ASIO_CHECK(count == 1);
143
144 count = 0;
145 ios.reset();
146 ios.post(bindns::bind(start_sleep_increments, &ios, &s, &count));
147 boost::asio::detail::thread thread1(bindns::bind(io_service_run, &ios));
148 boost::asio::detail::thread thread2(bindns::bind(io_service_run, &ios));
149
150 // Check all events run one after another even though there are two threads.
151 timer timer1(ios, chronons::seconds(3));
152 timer1.wait();
153 BOOST_ASIO_CHECK(count == 0);
154 timer1.expires_at(timer1.expires_at() + chronons::seconds(2));
155 timer1.wait();
156 BOOST_ASIO_CHECK(count == 1);
157 timer1.expires_at(timer1.expires_at() + chronons::seconds(2));
158 timer1.wait();
159 BOOST_ASIO_CHECK(count == 2);
160
161 thread1.join();
162 thread2.join();
163
164 // The run() calls will not return until all work has finished.
165 BOOST_ASIO_CHECK(count == 3);
166
167 count = 0;
168 int exception_count = 0;
169 ios.reset();
170 s.post(throw_exception);
171 s.post(bindns::bind(increment, &count));
172 s.post(bindns::bind(increment, &count));
173 s.post(throw_exception);
174 s.post(bindns::bind(increment, &count));
175
176 // No handlers can be called until run() is called.
177 BOOST_ASIO_CHECK(count == 0);
178 BOOST_ASIO_CHECK(exception_count == 0);
179
180 for (;;)
181 {
182 try
183 {
184 ios.run();
185 break;
186 }
187 catch (int)
188 {
189 ++exception_count;
190 }
191 }
192
193 // The run() calls will not return until all work has finished.
194 BOOST_ASIO_CHECK(count == 3);
195 BOOST_ASIO_CHECK(exception_count == 2);
196
197 count = 0;
198 ios.reset();
199
200 // Check for clean shutdown when handlers posted through an orphaned strand
201 // are abandoned.
202 {
203 strand s2(ios);
204 s2.post(bindns::bind(increment, &count));
205 s2.post(bindns::bind(increment, &count));
206 s2.post(bindns::bind(increment, &count));
207 }
208
209 // No handlers can be called until run() is called.
210 BOOST_ASIO_CHECK(count == 0);
211 }
212
213 BOOST_ASIO_TEST_SUITE
214 (
215 "strand",
216 BOOST_ASIO_TEST_CASE(strand_test)
217 )