]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/fiber/test/test_fiber_dispatch.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / fiber / test / test_fiber_dispatch.cpp
1
2 // Copyright Oliver Kowalke 2013.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // This test is based on the tests of Boost.Thread
8
9 #include <chrono>
10 #include <mutex>
11 #include <sstream>
12 #include <string>
13
14 #include <boost/assert.hpp>
15 #include <boost/test/unit_test.hpp>
16
17 #include <boost/fiber/all.hpp>
18
19 int value1 = 0;
20 std::string value2 = "";
21
22 struct X {
23 int value;
24
25 void foo( int i) {
26 value = i;
27 }
28 };
29
30 class copyable {
31 public:
32 bool state;
33 int value;
34
35 copyable() :
36 state( false),
37 value( -1) {
38 }
39
40 copyable( int v) :
41 state( true),
42 value( v) {
43 }
44
45 void operator()() {
46 value1 = value;
47 }
48 };
49
50 class moveable {
51 public:
52 bool state;
53 int value;
54
55 moveable() :
56 state( false),
57 value( -1) {
58 }
59
60 moveable( int v) :
61 state( true),
62 value( v) {
63 }
64
65 moveable( moveable && other) :
66 state( other.state),
67 value( other.value) {
68 other.state = false;
69 other.value = -1;
70 }
71
72 moveable & operator=( moveable && other) {
73 if ( this == & other) return * this;
74 state = other.state;
75 value = other.value;
76 other.state = false;
77 other.value = -1;
78 return * this;
79 }
80
81 moveable( moveable const& other) = delete;
82 moveable & operator=( moveable const& other) = delete;
83
84 void operator()() {
85 value1 = value;
86 }
87 };
88
89 class detachable {
90 private:
91 int alive_count_;
92
93 public:
94 static int alive_count;
95 static bool was_running;
96
97 detachable() :
98 alive_count_( 1) {
99 ++alive_count;
100 }
101
102 detachable( detachable const& g) :
103 alive_count_( g.alive_count_) {
104 ++alive_count;
105 }
106
107 ~detachable() {
108 alive_count_ = 0;
109 --alive_count;
110 }
111
112 void operator()() {
113 BOOST_CHECK_EQUAL(1, alive_count_);
114 was_running = true;
115 }
116 };
117
118 int detachable::alive_count = 0;
119 bool detachable::was_running = false;
120
121 void fn1() {
122 value1 = 1;
123 }
124
125 void fn2( int i, std::string const& s) {
126 value1 = i;
127 value2 = s;
128 }
129
130 void fn3( int & i) {
131 i = 1;
132 boost::this_fiber::yield();
133 i = 1;
134 boost::this_fiber::yield();
135 i = 2;
136 boost::this_fiber::yield();
137 i = 3;
138 boost::this_fiber::yield();
139 i = 5;
140 boost::this_fiber::yield();
141 i = 8;
142 }
143
144 void fn4() {
145 boost::this_fiber::yield();
146 }
147
148 void fn5() {
149 boost::fibers::fiber f( boost::fibers::launch::dispatch, fn4);
150 BOOST_CHECK( f.joinable() );
151 f.join();
152 BOOST_CHECK( ! f.joinable() );
153 }
154
155 void test_scheduler_dtor() {
156 boost::fibers::context * ctx(
157 boost::fibers::context::active() );
158 (void)ctx;
159 }
160
161 void test_join_fn() {
162 {
163 value1 = 0;
164 boost::fibers::fiber f( boost::fibers::launch::dispatch, fn1);
165 f.join();
166 BOOST_CHECK_EQUAL( value1, 1);
167 }
168 {
169 value1 = 0;
170 value2 = "";
171 boost::fibers::fiber f( boost::fibers::launch::dispatch, fn2, 3, "abc");
172 f.join();
173 BOOST_CHECK_EQUAL( value1, 3);
174 BOOST_CHECK_EQUAL( value2, "abc");
175 }
176 }
177
178 void test_join_memfn() {
179 X x = {0};
180 BOOST_CHECK_EQUAL( x.value, 0);
181 boost::fibers::fiber( boost::fibers::launch::dispatch, & X::foo, & x, 3).join();
182 BOOST_CHECK_EQUAL( x.value, 3);
183 }
184
185 void test_join_copyable() {
186 value1 = 0;
187 copyable cp( 3);
188 BOOST_CHECK( cp.state);
189 BOOST_CHECK_EQUAL( value1, 0);
190 boost::fibers::fiber f( boost::fibers::launch::dispatch, cp);
191 f.join();
192 BOOST_CHECK( cp.state);
193 BOOST_CHECK_EQUAL( value1, 3);
194 }
195
196 void test_join_moveable() {
197 value1 = 0;
198 moveable mv( 7);
199 BOOST_CHECK( mv.state);
200 BOOST_CHECK_EQUAL( value1, 0);
201 boost::fibers::fiber f( boost::fibers::launch::dispatch, std::move( mv) );
202 f.join();
203 BOOST_CHECK( ! mv.state);
204 BOOST_CHECK_EQUAL( value1, 7);
205 }
206
207 void test_join_lambda() {
208 {
209 value1 = 0;
210 value2 = "";
211 int i = 3;
212 std::string abc("abc");
213 boost::fibers::fiber f(
214 boost::fibers::launch::dispatch, [i,abc]() {
215 value1 = i;
216 value2 = abc;
217 });
218 f.join();
219 BOOST_CHECK_EQUAL( value1, 3);
220 BOOST_CHECK_EQUAL( value2, "abc");
221 }
222 {
223 value1 = 0;
224 value2 = "";
225 int i = 3;
226 std::string abc("abc");
227 boost::fibers::fiber f(
228 boost::fibers::launch::dispatch, [](int i, std::string const& abc) {
229 value1 = i;
230 value2 = abc;
231 },
232 i, abc);
233 f.join();
234 BOOST_CHECK_EQUAL( value1, 3);
235 BOOST_CHECK_EQUAL( value2, "abc");
236 }
237 }
238
239 void test_join_bind() {
240 {
241 value1 = 0;
242 value2 = "";
243 int i = 3;
244 std::string abc("abc");
245 boost::fibers::fiber f(
246 boost::fibers::launch::dispatch, std::bind(
247 [i,abc]() {
248 value1 = i;
249 value2 = abc;
250 }
251 ));
252 f.join();
253 BOOST_CHECK_EQUAL( value1, 3);
254 BOOST_CHECK_EQUAL( value2, "abc");
255 }
256 {
257 value1 = 0;
258 value2 = "";
259 std::string abc("abc");
260 boost::fibers::fiber f(
261 boost::fibers::launch::dispatch, std::bind(
262 [](std::string & str) {
263 value1 = 3;
264 value2 = str;
265 },
266 abc
267 ));
268 f.join();
269 BOOST_CHECK_EQUAL( value1, 3);
270 BOOST_CHECK_EQUAL( value2, "abc");
271 }
272 {
273 value1 = 0;
274 value2 = "";
275 std::string abc("abc");
276 boost::fibers::fiber f(
277 boost::fibers::launch::dispatch, std::bind(
278 []( std::string & str) {
279 value1 = 3;
280 value2 = str;
281 },
282 std::placeholders::_1
283 ),
284 std::ref( abc) );
285 f.join();
286 BOOST_CHECK_EQUAL( value1, 3);
287 BOOST_CHECK_EQUAL( value2, "abc");
288 }
289 }
290
291 void test_join_in_fiber() {
292 // spawn fiber f
293 // f spawns an new fiber f' in its fiber-fn
294 // f' yields in its fiber-fn
295 // f joins s' and gets suspended (waiting on s')
296 boost::fibers::fiber f( boost::fibers::launch::dispatch, fn5);
297 BOOST_CHECK( f.joinable() );
298 // join() resumes f + f' which completes
299 f.join();
300 BOOST_CHECK( ! f.joinable() );
301 }
302
303 void test_move_fiber() {
304 boost::fibers::fiber f1;
305 BOOST_CHECK( ! f1.joinable() );
306 boost::fibers::fiber f2( boost::fibers::launch::dispatch, fn1);
307 BOOST_CHECK( f2.joinable() );
308 f1 = std::move( f2);
309 BOOST_CHECK( f1.joinable() );
310 BOOST_CHECK( ! f2.joinable() );
311 f1.join();
312 BOOST_CHECK( ! f1.joinable() );
313 BOOST_CHECK( ! f2.joinable() );
314 }
315
316 void test_id() {
317 boost::fibers::fiber f1;
318 boost::fibers::fiber f2( boost::fibers::launch::dispatch, fn1);
319 BOOST_CHECK( ! f1.joinable() );
320 BOOST_CHECK( f2.joinable() );
321
322 BOOST_CHECK_EQUAL( boost::fibers::fiber::id(), f1.get_id() );
323 BOOST_CHECK( boost::fibers::fiber::id() != f2.get_id() );
324
325 boost::fibers::fiber f3( boost::fibers::launch::dispatch, fn1);
326 BOOST_CHECK( f2.get_id() != f3.get_id() );
327
328 f1 = std::move( f2);
329 BOOST_CHECK( f1.joinable() );
330 BOOST_CHECK( ! f2.joinable() );
331
332 BOOST_CHECK( boost::fibers::fiber::id() != f1.get_id() );
333 BOOST_CHECK_EQUAL( boost::fibers::fiber::id(), f2.get_id() );
334
335 BOOST_CHECK( ! f2.joinable() );
336
337 f1.join();
338 f3.join();
339 }
340
341 void test_yield() {
342 int v1 = 0, v2 = 0;
343 BOOST_CHECK_EQUAL( 0, v1);
344 BOOST_CHECK_EQUAL( 0, v2);
345 boost::fibers::fiber f1( boost::fibers::launch::dispatch, fn3, std::ref( v1) );
346 boost::fibers::fiber f2( boost::fibers::launch::dispatch, fn3, std::ref( v2) );
347 f1.join();
348 f2.join();
349 BOOST_CHECK( ! f1.joinable() );
350 BOOST_CHECK( ! f2.joinable() );
351 BOOST_CHECK_EQUAL( 8, v1);
352 BOOST_CHECK_EQUAL( 8, v2);
353 }
354
355 void test_sleep_for() {
356 typedef std::chrono::system_clock Clock;
357 typedef Clock::time_point time_point;
358 std::chrono::milliseconds ms(500);
359 time_point t0 = Clock::now();
360 boost::this_fiber::sleep_for(ms);
361 time_point t1 = Clock::now();
362 std::chrono::nanoseconds ns = (t1 - t0) - ms;
363 std::chrono::nanoseconds err = ms / 10;
364 // This test is spurious as it depends on the time the fiber system switches the fiber
365 BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count());
366 }
367
368 void test_sleep_until() {
369 {
370 typedef std::chrono::steady_clock Clock;
371 typedef Clock::time_point time_point;
372 std::chrono::milliseconds ms(500);
373 time_point t0 = Clock::now();
374 boost::this_fiber::sleep_until(t0 + ms);
375 time_point t1 = Clock::now();
376 std::chrono::nanoseconds ns = (t1 - t0) - ms;
377 std::chrono::nanoseconds err = ms / 10;
378 // This test is spurious as it depends on the time the thread system switches the threads
379 BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count());
380 }
381 {
382 typedef std::chrono::system_clock Clock;
383 typedef Clock::time_point time_point;
384 std::chrono::milliseconds ms(500);
385 time_point t0 = Clock::now();
386 boost::this_fiber::sleep_until(t0 + ms);
387 time_point t1 = Clock::now();
388 std::chrono::nanoseconds ns = (t1 - t0) - ms;
389 std::chrono::nanoseconds err = ms / 10;
390 // This test is spurious as it depends on the time the thread system switches the threads
391 BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count());
392 }
393 }
394
395 void do_wait( boost::fibers::barrier* b) {
396 b->wait();
397 }
398
399 void test_detach() {
400 {
401 boost::fibers::fiber f( boost::fibers::launch::dispatch, (detachable()) );
402 BOOST_CHECK( f.joinable() );
403 f.detach();
404 BOOST_CHECK( ! f.joinable() );
405 boost::this_fiber::sleep_for( std::chrono::milliseconds(250) );
406 BOOST_CHECK( detachable::was_running);
407 BOOST_CHECK_EQUAL( 0, detachable::alive_count);
408 }
409 {
410 boost::fibers::fiber f( boost::fibers::launch::dispatch, (detachable()) );
411 BOOST_CHECK( f.joinable() );
412 boost::this_fiber::yield();
413 f.detach();
414 BOOST_CHECK( ! f.joinable() );
415 boost::this_fiber::sleep_for( std::chrono::milliseconds(250) );
416 BOOST_CHECK( detachable::was_running);
417 BOOST_CHECK_EQUAL( 0, detachable::alive_count);
418 }
419 }
420
421 boost::unit_test::test_suite * init_unit_test_suite( int, char* []) {
422 boost::unit_test::test_suite * test =
423 BOOST_TEST_SUITE("Boost.Fiber: fiber test suite");
424
425 test->add( BOOST_TEST_CASE( & test_scheduler_dtor) );
426 test->add( BOOST_TEST_CASE( & test_join_fn) );
427 test->add( BOOST_TEST_CASE( & test_join_memfn) );
428 test->add( BOOST_TEST_CASE( & test_join_copyable) );
429 test->add( BOOST_TEST_CASE( & test_join_moveable) );
430 test->add( BOOST_TEST_CASE( & test_join_lambda) );
431 test->add( BOOST_TEST_CASE( & test_join_bind) );
432 test->add( BOOST_TEST_CASE( & test_join_in_fiber) );
433 test->add( BOOST_TEST_CASE( & test_move_fiber) );
434 test->add( BOOST_TEST_CASE( & test_move_fiber) );
435 test->add( BOOST_TEST_CASE( & test_yield) );
436 test->add( BOOST_TEST_CASE( & test_sleep_for) );
437 test->add( BOOST_TEST_CASE( & test_sleep_until) );
438 test->add( BOOST_TEST_CASE( & test_detach) );
439
440 return test;
441 }