diff options
Diffstat (limited to 'src/boost/libs/fiber/test/test_fiber_dispatch.cpp')
-rw-r--r-- | src/boost/libs/fiber/test/test_fiber_dispatch.cpp | 440 |
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; +} |