]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/fiber/test/test_fiber_post.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / fiber / test / test_fiber_post.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::post, 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::post, 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::post, 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::post, & X::foo, std::ref( 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::post, 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::post, 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::post, [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::post, [](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::post, 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 int i = 3;
260 std::string abc("abc");
261 boost::fibers::fiber f(
262 boost::fibers::launch::post, std::bind(
263 []( int i, std::string & str) {
264 value1 = 3;
265 value2 = str;
266 },
267 i, abc
268 ));
269 f.join();
270 BOOST_CHECK_EQUAL( value1, 3);
271 BOOST_CHECK_EQUAL( value2, "abc");
272 }
273 #if 0
274 {
275 value1 = 0;
276 value2 = "";
277 int i = 3;
278 std::string abc("abc");
279 boost::fibers::fiber f(
280 boost::fibers::launch::post, std::bind(
281 []( int i, std::string & str) {
282 value1 = 3;
283 value2 = str;
284 },
285 std::placeholders::_1,
286 std::placeholders::_2
287 ),
288 i, abc);
289 f.join();
290 BOOST_CHECK_EQUAL( value1, 3);
291 BOOST_CHECK_EQUAL( value2, "abc");
292 }
293 #endif
294 }
295
296 void test_join_in_fiber() {
297 // spawn fiber f
298 // f spawns an new fiber f' in its fiber-fn
299 // f' yields in its fiber-fn
300 // f joins s' and gets suspended (waiting on s')
301 boost::fibers::fiber f( boost::fibers::launch::post, fn5);
302 BOOST_CHECK( f.joinable() );
303 // join() resumes f + f' which completes
304 f.join();
305 BOOST_CHECK( ! f.joinable() );
306 }
307
308 void test_move_fiber() {
309 boost::fibers::fiber f1;
310 BOOST_CHECK( ! f1.joinable() );
311 boost::fibers::fiber f2( boost::fibers::launch::post, fn1);
312 BOOST_CHECK( f2.joinable() );
313 f1 = std::move( f2);
314 BOOST_CHECK( f1.joinable() );
315 BOOST_CHECK( ! f2.joinable() );
316 f1.join();
317 BOOST_CHECK( ! f1.joinable() );
318 BOOST_CHECK( ! f2.joinable() );
319 }
320
321 void test_id() {
322 boost::fibers::fiber f1;
323 boost::fibers::fiber f2( boost::fibers::launch::post, fn1);
324 BOOST_CHECK( ! f1.joinable() );
325 BOOST_CHECK( f2.joinable() );
326
327 BOOST_CHECK_EQUAL( boost::fibers::fiber::id(), f1.get_id() );
328 BOOST_CHECK( boost::fibers::fiber::id() != f2.get_id() );
329
330 boost::fibers::fiber f3( boost::fibers::launch::post, fn1);
331 BOOST_CHECK( f2.get_id() != f3.get_id() );
332
333 f1 = std::move( f2);
334 BOOST_CHECK( f1.joinable() );
335 BOOST_CHECK( ! f2.joinable() );
336
337 BOOST_CHECK( boost::fibers::fiber::id() != f1.get_id() );
338 BOOST_CHECK_EQUAL( boost::fibers::fiber::id(), f2.get_id() );
339
340 BOOST_CHECK( ! f2.joinable() );
341
342 f1.join();
343 f3.join();
344 }
345
346 void test_yield() {
347 int v1 = 0, v2 = 0;
348 BOOST_CHECK_EQUAL( 0, v1);
349 BOOST_CHECK_EQUAL( 0, v2);
350 boost::fibers::fiber f1( boost::fibers::launch::post, fn3, std::ref( v1) );
351 boost::fibers::fiber f2( boost::fibers::launch::post, fn3, std::ref( v2) );
352 f1.join();
353 f2.join();
354 BOOST_CHECK( ! f1.joinable() );
355 BOOST_CHECK( ! f2.joinable() );
356 BOOST_CHECK_EQUAL( 8, v1);
357 BOOST_CHECK_EQUAL( 8, v2);
358 }
359
360 void test_sleep_for() {
361 typedef std::chrono::system_clock Clock;
362 typedef Clock::time_point time_point;
363 std::chrono::milliseconds ms(500);
364 time_point t0 = Clock::now();
365 boost::this_fiber::sleep_for(ms);
366 time_point t1 = Clock::now();
367 std::chrono::nanoseconds ns = (t1 - t0) - ms;
368 std::chrono::nanoseconds err = ms / 100;
369 // The time slept is within 1% of 500ms
370 // This test is spurious as it depends on the time the fiber system switches the fiber
371 BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count());
372 //BOOST_TEST(std::abs(static_cast<long>(ns.count())) < (err+std::chrono::milliseconds(1000)).count());
373 }
374
375 void test_sleep_until() {
376 {
377 typedef std::chrono::steady_clock Clock;
378 typedef Clock::time_point time_point;
379 std::chrono::milliseconds ms(500);
380 time_point t0 = Clock::now();
381 boost::this_fiber::sleep_until(t0 + ms);
382 time_point t1 = Clock::now();
383 std::chrono::nanoseconds ns = (t1 - t0) - ms;
384 std::chrono::nanoseconds err = ms / 100;
385 // The time slept is within 1% of 500ms
386 // This test is spurious as it depends on the time the thread system switches the threads
387 BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count());
388 //BOOST_TEST(std::abs(static_cast<long>(ns.count())) < (err+std::chrono::milliseconds(1000)).count());
389 }
390 {
391 typedef std::chrono::system_clock Clock;
392 typedef Clock::time_point time_point;
393 std::chrono::milliseconds ms(500);
394 time_point t0 = Clock::now();
395 boost::this_fiber::sleep_until(t0 + ms);
396 time_point t1 = Clock::now();
397 std::chrono::nanoseconds ns = (t1 - t0) - ms;
398 std::chrono::nanoseconds err = ms / 100;
399 // The time slept is within 1% of 500ms
400 // This test is spurious as it depends on the time the thread system switches the threads
401 BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count());
402 //BOOST_TEST(std::abs(static_cast<long>(ns.count())) < (err+std::chrono::milliseconds(1000)).count());
403 }
404 }
405
406 void do_wait( boost::fibers::barrier* b) {
407 b->wait();
408 }
409
410 void test_detach() {
411 {
412 boost::fibers::fiber f( boost::fibers::launch::post, (detachable()) );
413 BOOST_CHECK( f.joinable() );
414 f.detach();
415 BOOST_CHECK( ! f.joinable() );
416 boost::this_fiber::sleep_for( std::chrono::milliseconds(250) );
417 BOOST_CHECK( detachable::was_running);
418 BOOST_CHECK_EQUAL( 0, detachable::alive_count);
419 }
420 {
421 boost::fibers::fiber f( boost::fibers::launch::post, (detachable()) );
422 BOOST_CHECK( f.joinable() );
423 boost::this_fiber::yield();
424 f.detach();
425 BOOST_CHECK( ! f.joinable() );
426 boost::this_fiber::sleep_for( std::chrono::milliseconds(250) );
427 BOOST_CHECK( detachable::was_running);
428 BOOST_CHECK_EQUAL( 0, detachable::alive_count);
429 }
430 }
431
432 boost::unit_test::test_suite * init_unit_test_suite( int, char* []) {
433 boost::unit_test::test_suite * test =
434 BOOST_TEST_SUITE("Boost.Fiber: fiber test suite");
435
436 test->add( BOOST_TEST_CASE( & test_scheduler_dtor) );
437 test->add( BOOST_TEST_CASE( & test_join_fn) );
438 test->add( BOOST_TEST_CASE( & test_join_memfn) );
439 test->add( BOOST_TEST_CASE( & test_join_copyable) );
440 test->add( BOOST_TEST_CASE( & test_join_moveable) );
441 test->add( BOOST_TEST_CASE( & test_join_lambda) );
442 test->add( BOOST_TEST_CASE( & test_join_bind) );
443 test->add( BOOST_TEST_CASE( & test_join_in_fiber) );
444 test->add( BOOST_TEST_CASE( & test_move_fiber) );
445 test->add( BOOST_TEST_CASE( & test_move_fiber) );
446 test->add( BOOST_TEST_CASE( & test_yield) );
447 test->add( BOOST_TEST_CASE( & test_sleep_for) );
448 test->add( BOOST_TEST_CASE( & test_sleep_until) );
449 test->add( BOOST_TEST_CASE( & test_detach) );
450
451 return test;
452 }