• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
fooX25     void foo( int i) {
26         value = i;
27     }
28 };
29 
30 class copyable {
31 public:
32     bool    state;
33     int     value;
34 
copyable()35     copyable() :
36         state( false),
37         value( -1) {
38     }
39 
copyable(int v)40     copyable( int v) :
41         state( true),
42         value( v) {
43     }
44 
operator ()()45     void operator()() {
46         value1 = value;
47     }
48 };
49 
50 class moveable {
51 public:
52     bool    state;
53     int     value;
54 
moveable()55     moveable() :
56         state( false),
57         value( -1) {
58     }
59 
moveable(int v)60     moveable( int v) :
61         state( true),
62         value( v) {
63     }
64 
moveable(moveable && other)65     moveable( moveable && other) :
66         state( other.state),
67         value( other.value) {
68         other.state = false;
69         other.value = -1;
70     }
71 
operator =(moveable && other)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 
operator ()()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 
detachable()97     detachable() :
98         alive_count_( 1) {
99         ++alive_count;
100     }
101 
detachable(detachable const & g)102     detachable( detachable const& g) :
103         alive_count_( g.alive_count_) {
104         ++alive_count;
105     }
106 
~detachable()107     ~detachable() {
108         alive_count_ = 0;
109         --alive_count;
110     }
111 
operator ()()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 
fn1()121 void fn1() {
122     value1 = 1;
123 }
124 
fn2(int i,std::string const & s)125 void fn2( int i, std::string const& s) {
126     value1 = i;
127     value2 = s;
128 }
129 
fn3(int & i)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 
fn4()144 void fn4() {
145     boost::this_fiber::yield();
146 }
147 
fn5()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 
test_scheduler_dtor()155 void test_scheduler_dtor() {
156     boost::fibers::context * ctx(
157         boost::fibers::context::active() );
158     (void)ctx;
159 }
160 
test_join_fn()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 
test_join_memfn()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, & x, 3).join();
182     BOOST_CHECK_EQUAL( x.value, 3);
183 }
184 
test_join_copyable()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 
test_join_moveable()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 
test_join_lambda()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 
test_join_bind()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         std::string abc("abc");
260         boost::fibers::fiber f(
261             boost::fibers::launch::post, 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::post, 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 
test_join_in_fiber()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::post, fn5);
297     BOOST_CHECK( f.joinable() );
298     // join() resumes f + f' which completes
299     f.join();
300     BOOST_CHECK( ! f.joinable() );
301 }
302 
test_move_fiber()303 void test_move_fiber() {
304     boost::fibers::fiber f1;
305     BOOST_CHECK( ! f1.joinable() );
306     boost::fibers::fiber f2( boost::fibers::launch::post, 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 
test_id()316 void test_id() {
317     boost::fibers::fiber f1;
318     boost::fibers::fiber f2( boost::fibers::launch::post, 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::post, 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 
test_yield()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::post, fn3, std::ref( v1) );
346     boost::fibers::fiber f2( boost::fibers::launch::post, 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 
test_sleep_for()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 
test_sleep_until()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 
do_wait(boost::fibers::barrier * b)395 void do_wait( boost::fibers::barrier* b) {
396     b->wait();
397 }
398 
test_detach()399 void test_detach() {
400     {
401         boost::fibers::fiber f( boost::fibers::launch::post, (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::post, (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 
init_unit_test_suite(int,char * [])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_yield) );
435     test->add( BOOST_TEST_CASE( & test_sleep_for) );
436     test->add( BOOST_TEST_CASE( & test_sleep_until) );
437     test->add( BOOST_TEST_CASE( & test_detach) );
438 
439     return test;
440 }
441