summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/fiber/test/test_fiber_dispatch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/fiber/test/test_fiber_dispatch.cpp')
-rw-r--r--src/boost/libs/fiber/test/test_fiber_dispatch.cpp440
1 files changed, 440 insertions, 0 deletions
diff --git a/src/boost/libs/fiber/test/test_fiber_dispatch.cpp b/src/boost/libs/fiber/test/test_fiber_dispatch.cpp
new file mode 100644
index 00000000..1126b001
--- /dev/null
+++ b/src/boost/libs/fiber/test/test_fiber_dispatch.cpp
@@ -0,0 +1,440 @@
+
+// Copyright Oliver Kowalke 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// This test is based on the tests of Boost.Thread
+
+#include <chrono>
+#include <mutex>
+#include <sstream>
+#include <string>
+
+#include <boost/assert.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include <boost/fiber/all.hpp>
+
+int value1 = 0;
+std::string value2 = "";
+
+struct X {
+ int value;
+
+ void foo( int i) {
+ value = i;
+ }
+};
+
+class copyable {
+public:
+ bool state;
+ int value;
+
+ copyable() :
+ state( false),
+ value( -1) {
+ }
+
+ copyable( int v) :
+ state( true),
+ value( v) {
+ }
+
+ void operator()() {
+ value1 = value;
+ }
+};
+
+class moveable {
+public:
+ bool state;
+ int value;
+
+ moveable() :
+ state( false),
+ value( -1) {
+ }
+
+ moveable( int v) :
+ state( true),
+ value( v) {
+ }
+
+ moveable( moveable && other) :
+ state( other.state),
+ value( other.value) {
+ other.state = false;
+ other.value = -1;
+ }
+
+ moveable & operator=( moveable && other) {
+ if ( this == & other) return * this;
+ state = other.state;
+ value = other.value;
+ other.state = false;
+ other.value = -1;
+ return * this;
+ }
+
+ moveable( moveable const& other) = delete;
+ moveable & operator=( moveable const& other) = delete;
+
+ void operator()() {
+ value1 = value;
+ }
+};
+
+class detachable {
+private:
+ int alive_count_;
+
+public:
+ static int alive_count;
+ static bool was_running;
+
+ detachable() :
+ alive_count_( 1) {
+ ++alive_count;
+ }
+
+ detachable( detachable const& g) :
+ alive_count_( g.alive_count_) {
+ ++alive_count;
+ }
+
+ ~detachable() {
+ alive_count_ = 0;
+ --alive_count;
+ }
+
+ void operator()() {
+ BOOST_CHECK_EQUAL(1, alive_count_);
+ was_running = true;
+ }
+};
+
+int detachable::alive_count = 0;
+bool detachable::was_running = false;
+
+void fn1() {
+ value1 = 1;
+}
+
+void fn2( int i, std::string const& s) {
+ value1 = i;
+ value2 = s;
+}
+
+void fn3( int & i) {
+ i = 1;
+ boost::this_fiber::yield();
+ i = 1;
+ boost::this_fiber::yield();
+ i = 2;
+ boost::this_fiber::yield();
+ i = 3;
+ boost::this_fiber::yield();
+ i = 5;
+ boost::this_fiber::yield();
+ i = 8;
+}
+
+void fn4() {
+ boost::this_fiber::yield();
+}
+
+void fn5() {
+ boost::fibers::fiber f( boost::fibers::launch::dispatch, fn4);
+ BOOST_CHECK( f.joinable() );
+ f.join();
+ BOOST_CHECK( ! f.joinable() );
+}
+
+void test_scheduler_dtor() {
+ boost::fibers::context * ctx(
+ boost::fibers::context::active() );
+ (void)ctx;
+}
+
+void test_join_fn() {
+ {
+ value1 = 0;
+ boost::fibers::fiber f( boost::fibers::launch::dispatch, fn1);
+ f.join();
+ BOOST_CHECK_EQUAL( value1, 1);
+ }
+ {
+ value1 = 0;
+ value2 = "";
+ boost::fibers::fiber f( boost::fibers::launch::dispatch, fn2, 3, "abc");
+ f.join();
+ BOOST_CHECK_EQUAL( value1, 3);
+ BOOST_CHECK_EQUAL( value2, "abc");
+ }
+}
+
+void test_join_memfn() {
+ X x = {0};
+ BOOST_CHECK_EQUAL( x.value, 0);
+ boost::fibers::fiber( boost::fibers::launch::dispatch, & X::foo, & x, 3).join();
+ BOOST_CHECK_EQUAL( x.value, 3);
+}
+
+void test_join_copyable() {
+ value1 = 0;
+ copyable cp( 3);
+ BOOST_CHECK( cp.state);
+ BOOST_CHECK_EQUAL( value1, 0);
+ boost::fibers::fiber f( boost::fibers::launch::dispatch, cp);
+ f.join();
+ BOOST_CHECK( cp.state);
+ BOOST_CHECK_EQUAL( value1, 3);
+}
+
+void test_join_moveable() {
+ value1 = 0;
+ moveable mv( 7);
+ BOOST_CHECK( mv.state);
+ BOOST_CHECK_EQUAL( value1, 0);
+ boost::fibers::fiber f( boost::fibers::launch::dispatch, std::move( mv) );
+ f.join();
+ BOOST_CHECK( ! mv.state);
+ BOOST_CHECK_EQUAL( value1, 7);
+}
+
+void test_join_lambda() {
+ {
+ value1 = 0;
+ value2 = "";
+ int i = 3;
+ std::string abc("abc");
+ boost::fibers::fiber f(
+ boost::fibers::launch::dispatch, [i,abc]() {
+ value1 = i;
+ value2 = abc;
+ });
+ f.join();
+ BOOST_CHECK_EQUAL( value1, 3);
+ BOOST_CHECK_EQUAL( value2, "abc");
+ }
+ {
+ value1 = 0;
+ value2 = "";
+ int i = 3;
+ std::string abc("abc");
+ boost::fibers::fiber f(
+ boost::fibers::launch::dispatch, [](int i, std::string const& abc) {
+ value1 = i;
+ value2 = abc;
+ },
+ i, abc);
+ f.join();
+ BOOST_CHECK_EQUAL( value1, 3);
+ BOOST_CHECK_EQUAL( value2, "abc");
+ }
+}
+
+void test_join_bind() {
+ {
+ value1 = 0;
+ value2 = "";
+ int i = 3;
+ std::string abc("abc");
+ boost::fibers::fiber f(
+ boost::fibers::launch::dispatch, std::bind(
+ [i,abc]() {
+ value1 = i;
+ value2 = abc;
+ }
+ ));
+ f.join();
+ BOOST_CHECK_EQUAL( value1, 3);
+ BOOST_CHECK_EQUAL( value2, "abc");
+ }
+ {
+ value1 = 0;
+ value2 = "";
+ std::string abc("abc");
+ boost::fibers::fiber f(
+ boost::fibers::launch::dispatch, std::bind(
+ [](std::string & str) {
+ value1 = 3;
+ value2 = str;
+ },
+ abc
+ ));
+ f.join();
+ BOOST_CHECK_EQUAL( value1, 3);
+ BOOST_CHECK_EQUAL( value2, "abc");
+ }
+ {
+ value1 = 0;
+ value2 = "";
+ std::string abc("abc");
+ boost::fibers::fiber f(
+ boost::fibers::launch::dispatch, std::bind(
+ []( std::string & str) {
+ value1 = 3;
+ value2 = str;
+ },
+ std::placeholders::_1
+ ),
+ std::ref( abc) );
+ f.join();
+ BOOST_CHECK_EQUAL( value1, 3);
+ BOOST_CHECK_EQUAL( value2, "abc");
+ }
+}
+
+void test_join_in_fiber() {
+ // spawn fiber f
+ // f spawns an new fiber f' in its fiber-fn
+ // f' yields in its fiber-fn
+ // f joins s' and gets suspended (waiting on s')
+ boost::fibers::fiber f( boost::fibers::launch::dispatch, fn5);
+ BOOST_CHECK( f.joinable() );
+ // join() resumes f + f' which completes
+ f.join();
+ BOOST_CHECK( ! f.joinable() );
+}
+
+void test_move_fiber() {
+ boost::fibers::fiber f1;
+ BOOST_CHECK( ! f1.joinable() );
+ boost::fibers::fiber f2( boost::fibers::launch::dispatch, fn1);
+ BOOST_CHECK( f2.joinable() );
+ f1 = std::move( f2);
+ BOOST_CHECK( f1.joinable() );
+ BOOST_CHECK( ! f2.joinable() );
+ f1.join();
+ BOOST_CHECK( ! f1.joinable() );
+ BOOST_CHECK( ! f2.joinable() );
+}
+
+void test_id() {
+ boost::fibers::fiber f1;
+ boost::fibers::fiber f2( boost::fibers::launch::dispatch, fn1);
+ BOOST_CHECK( ! f1.joinable() );
+ BOOST_CHECK( f2.joinable() );
+
+ BOOST_CHECK_EQUAL( boost::fibers::fiber::id(), f1.get_id() );
+ BOOST_CHECK( boost::fibers::fiber::id() != f2.get_id() );
+
+ boost::fibers::fiber f3( boost::fibers::launch::dispatch, fn1);
+ BOOST_CHECK( f2.get_id() != f3.get_id() );
+
+ f1 = std::move( f2);
+ BOOST_CHECK( f1.joinable() );
+ BOOST_CHECK( ! f2.joinable() );
+
+ BOOST_CHECK( boost::fibers::fiber::id() != f1.get_id() );
+ BOOST_CHECK_EQUAL( boost::fibers::fiber::id(), f2.get_id() );
+
+ BOOST_CHECK( ! f2.joinable() );
+
+ f1.join();
+ f3.join();
+}
+
+void test_yield() {
+ int v1 = 0, v2 = 0;
+ BOOST_CHECK_EQUAL( 0, v1);
+ BOOST_CHECK_EQUAL( 0, v2);
+ boost::fibers::fiber f1( boost::fibers::launch::dispatch, fn3, std::ref( v1) );
+ boost::fibers::fiber f2( boost::fibers::launch::dispatch, fn3, std::ref( v2) );
+ f1.join();
+ f2.join();
+ BOOST_CHECK( ! f1.joinable() );
+ BOOST_CHECK( ! f2.joinable() );
+ BOOST_CHECK_EQUAL( 8, v1);
+ BOOST_CHECK_EQUAL( 8, v2);
+}
+
+void test_sleep_for() {
+ typedef std::chrono::system_clock Clock;
+ typedef Clock::time_point time_point;
+ std::chrono::milliseconds ms(500);
+ time_point t0 = Clock::now();
+ boost::this_fiber::sleep_for(ms);
+ time_point t1 = Clock::now();
+ std::chrono::nanoseconds ns = (t1 - t0) - ms;
+ std::chrono::nanoseconds err = ms / 10;
+ // This test is spurious as it depends on the time the fiber system switches the fiber
+ BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count());
+}
+
+void test_sleep_until() {
+ {
+ typedef std::chrono::steady_clock Clock;
+ typedef Clock::time_point time_point;
+ std::chrono::milliseconds ms(500);
+ time_point t0 = Clock::now();
+ boost::this_fiber::sleep_until(t0 + ms);
+ time_point t1 = Clock::now();
+ std::chrono::nanoseconds ns = (t1 - t0) - ms;
+ std::chrono::nanoseconds err = ms / 10;
+ // This test is spurious as it depends on the time the thread system switches the threads
+ BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count());
+ }
+ {
+ typedef std::chrono::system_clock Clock;
+ typedef Clock::time_point time_point;
+ std::chrono::milliseconds ms(500);
+ time_point t0 = Clock::now();
+ boost::this_fiber::sleep_until(t0 + ms);
+ time_point t1 = Clock::now();
+ std::chrono::nanoseconds ns = (t1 - t0) - ms;
+ std::chrono::nanoseconds err = ms / 10;
+ // This test is spurious as it depends on the time the thread system switches the threads
+ BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count());
+ }
+}
+
+void do_wait( boost::fibers::barrier* b) {
+ b->wait();
+}
+
+void test_detach() {
+ {
+ boost::fibers::fiber f( boost::fibers::launch::dispatch, (detachable()) );
+ BOOST_CHECK( f.joinable() );
+ f.detach();
+ BOOST_CHECK( ! f.joinable() );
+ boost::this_fiber::sleep_for( std::chrono::milliseconds(250) );
+ BOOST_CHECK( detachable::was_running);
+ BOOST_CHECK_EQUAL( 0, detachable::alive_count);
+ }
+ {
+ boost::fibers::fiber f( boost::fibers::launch::dispatch, (detachable()) );
+ BOOST_CHECK( f.joinable() );
+ boost::this_fiber::yield();
+ f.detach();
+ BOOST_CHECK( ! f.joinable() );
+ boost::this_fiber::sleep_for( std::chrono::milliseconds(250) );
+ BOOST_CHECK( detachable::was_running);
+ BOOST_CHECK_EQUAL( 0, detachable::alive_count);
+ }
+}
+
+boost::unit_test::test_suite * init_unit_test_suite( int, char* []) {
+ boost::unit_test::test_suite * test =
+ BOOST_TEST_SUITE("Boost.Fiber: fiber test suite");
+
+ test->add( BOOST_TEST_CASE( & test_scheduler_dtor) );
+ test->add( BOOST_TEST_CASE( & test_join_fn) );
+ test->add( BOOST_TEST_CASE( & test_join_memfn) );
+ test->add( BOOST_TEST_CASE( & test_join_copyable) );
+ test->add( BOOST_TEST_CASE( & test_join_moveable) );
+ test->add( BOOST_TEST_CASE( & test_join_lambda) );
+ test->add( BOOST_TEST_CASE( & test_join_bind) );
+ test->add( BOOST_TEST_CASE( & test_join_in_fiber) );
+ test->add( BOOST_TEST_CASE( & test_move_fiber) );
+ test->add( BOOST_TEST_CASE( & test_yield) );
+ test->add( BOOST_TEST_CASE( & test_sleep_for) );
+ test->add( BOOST_TEST_CASE( & test_sleep_until) );
+ test->add( BOOST_TEST_CASE( & test_detach) );
+
+ return test;
+}