From 90403fd89f8baf1d5caa9554ea44ee34a3db41da Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Sat, 3 Jun 2017 22:19:15 +0200 Subject: [PATCH 01/15] adjust timeouts in unit-test --- test/test_condition_variable_any_dispatch.cpp | 8 +++--- test/test_condition_variable_any_post.cpp | 8 +++--- test/test_condition_variable_dispatch.cpp | 8 +++--- test/test_condition_variable_post.cpp | 8 +++--- test/test_fiber_dispatch.cpp | 22 ++++----------- test/test_fiber_post.cpp | 22 ++++----------- test/test_future_dispatch.cpp | 14 +++++----- test/test_future_post.cpp | 14 +++++----- test/test_mutex_dispatch.cpp | 28 +++++++++---------- test/test_mutex_post.cpp | 28 +++++++++---------- 10 files changed, 70 insertions(+), 90 deletions(-) diff --git a/test/test_condition_variable_any_dispatch.cpp b/test/test_condition_variable_any_dispatch.cpp index f0331edd..e227fd45 100644 --- a/test/test_condition_variable_any_dispatch.cpp +++ b/test/test_condition_variable_any_dispatch.cpp @@ -225,7 +225,7 @@ void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) BOOST_CHECK(t1 - t0 < ms(250)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+5+1000)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); BOOST_CHECK(test2 == 0); } ++runs; @@ -258,7 +258,7 @@ void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) BOOST_CHECK(test2 != 0); BOOST_CHECK(r); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(250+2)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100)); BOOST_CHECK(test2 == 0); BOOST_CHECK(!r); } @@ -280,7 +280,7 @@ void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) BOOST_CHECK(t1 - t0 < ms(250)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+5+1000)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); BOOST_CHECK(test2 == 0); } ++runs; @@ -301,7 +301,7 @@ void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) BOOST_CHECK(t1 - t0 < ms(250+1000)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+2)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100)); BOOST_CHECK(test2 == 0); } ++runs; diff --git a/test/test_condition_variable_any_post.cpp b/test/test_condition_variable_any_post.cpp index eb41abe8..da6d882a 100644 --- a/test/test_condition_variable_any_post.cpp +++ b/test/test_condition_variable_any_post.cpp @@ -225,7 +225,7 @@ void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) BOOST_CHECK(t1 - t0 < ms(250)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+5+1000)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); BOOST_CHECK(test2 == 0); } ++runs; @@ -258,7 +258,7 @@ void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) BOOST_CHECK(test2 != 0); BOOST_CHECK(r); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(250+2)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100)); BOOST_CHECK(test2 == 0); BOOST_CHECK(!r); } @@ -280,7 +280,7 @@ void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) BOOST_CHECK(t1 - t0 < ms(250)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+5+1000)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); BOOST_CHECK(test2 == 0); } ++runs; @@ -301,7 +301,7 @@ void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) BOOST_CHECK(t1 - t0 < ms(250+1000)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+2)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100)); BOOST_CHECK(test2 == 0); } ++runs; diff --git a/test/test_condition_variable_dispatch.cpp b/test/test_condition_variable_dispatch.cpp index ddb5eaf4..dc5e00fe 100644 --- a/test/test_condition_variable_dispatch.cpp +++ b/test/test_condition_variable_dispatch.cpp @@ -222,7 +222,7 @@ void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { BOOST_CHECK(t1 - t0 < ms(250)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+5+1000)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); BOOST_CHECK(test2 == 0); } ++runs; @@ -254,7 +254,7 @@ void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { BOOST_CHECK(test2 != 0); BOOST_CHECK(r); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(250+2)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100)); BOOST_CHECK(test2 == 0); BOOST_CHECK(!r); } @@ -275,7 +275,7 @@ void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { BOOST_CHECK(t1 - t0 < ms(250)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+5+1000)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); BOOST_CHECK(test2 == 0); } ++runs; @@ -295,7 +295,7 @@ void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { BOOST_CHECK(t1 - t0 < ms(250+1000)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+2)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100)); BOOST_CHECK(test2 == 0); } ++runs; diff --git a/test/test_condition_variable_post.cpp b/test/test_condition_variable_post.cpp index 7c11d618..3f043a7b 100644 --- a/test/test_condition_variable_post.cpp +++ b/test/test_condition_variable_post.cpp @@ -222,7 +222,7 @@ void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { BOOST_CHECK(t1 - t0 < ms(250)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+5+1000)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); BOOST_CHECK(test2 == 0); } ++runs; @@ -254,7 +254,7 @@ void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { BOOST_CHECK(test2 != 0); BOOST_CHECK(r); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(250+2)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100)); BOOST_CHECK(test2 == 0); BOOST_CHECK(!r); } @@ -275,7 +275,7 @@ void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { BOOST_CHECK(t1 - t0 < ms(250)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+5+1000)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); BOOST_CHECK(test2 == 0); } ++runs; @@ -295,7 +295,7 @@ void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { BOOST_CHECK(t1 - t0 < ms(250+1000)); BOOST_CHECK(test2 != 0); } else { - BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+2)); + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100)); BOOST_CHECK(test2 == 0); } ++runs; diff --git a/test/test_fiber_dispatch.cpp b/test/test_fiber_dispatch.cpp index 47992a54..d7fce6c9 100644 --- a/test/test_fiber_dispatch.cpp +++ b/test/test_fiber_dispatch.cpp @@ -269,27 +269,23 @@ void test_join_bind() { BOOST_CHECK_EQUAL( value1, 3); BOOST_CHECK_EQUAL( value2, "abc"); } -#if 0 { value1 = 0; value2 = ""; - int i = 3; std::string abc("abc"); boost::fibers::fiber f( boost::fibers::launch::dispatch, std::bind( - []( int i, std::string & str) { + []( std::string & str) { value1 = 3; value2 = str; }, - std::placeholders::_1, - std::placeholders::_2 + std::placeholders::_1 ), - i, abc); + std::ref( abc) ); f.join(); BOOST_CHECK_EQUAL( value1, 3); BOOST_CHECK_EQUAL( value2, "abc"); } -#endif } void test_join_in_fiber() { @@ -364,11 +360,9 @@ void test_sleep_for() { boost::this_fiber::sleep_for(ms); time_point t1 = Clock::now(); std::chrono::nanoseconds ns = (t1 - t0) - ms; - std::chrono::nanoseconds err = ms / 100; - // The time slept is within 1% of 500ms + 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()); - //BOOST_TEST(std::abs(static_cast(ns.count())) < (err+std::chrono::milliseconds(1000)).count()); } void test_sleep_until() { @@ -380,11 +374,9 @@ void test_sleep_until() { boost::this_fiber::sleep_until(t0 + ms); time_point t1 = Clock::now(); std::chrono::nanoseconds ns = (t1 - t0) - ms; - std::chrono::nanoseconds err = ms / 100; - // The time slept is within 1% of 500ms + 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()); - //BOOST_TEST(std::abs(static_cast(ns.count())) < (err+std::chrono::milliseconds(1000)).count()); } { typedef std::chrono::system_clock Clock; @@ -394,11 +386,9 @@ void test_sleep_until() { boost::this_fiber::sleep_until(t0 + ms); time_point t1 = Clock::now(); std::chrono::nanoseconds ns = (t1 - t0) - ms; - std::chrono::nanoseconds err = ms / 100; - // The time slept is within 1% of 500ms + 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()); - //BOOST_TEST(std::abs(static_cast(ns.count())) < (err+std::chrono::milliseconds(1000)).count()); } } diff --git a/test/test_fiber_post.cpp b/test/test_fiber_post.cpp index fc7aa23a..d880b6d8 100644 --- a/test/test_fiber_post.cpp +++ b/test/test_fiber_post.cpp @@ -269,27 +269,23 @@ void test_join_bind() { BOOST_CHECK_EQUAL( value1, 3); BOOST_CHECK_EQUAL( value2, "abc"); } -#if 0 { value1 = 0; value2 = ""; - int i = 3; std::string abc("abc"); boost::fibers::fiber f( boost::fibers::launch::post, std::bind( - []( int i, std::string & str) { + []( std::string & str) { value1 = 3; value2 = str; }, - std::placeholders::_1, - std::placeholders::_2 + std::placeholders::_1 ), - i, abc); + std::ref( abc) ); f.join(); BOOST_CHECK_EQUAL( value1, 3); BOOST_CHECK_EQUAL( value2, "abc"); } -#endif } void test_join_in_fiber() { @@ -364,11 +360,9 @@ void test_sleep_for() { boost::this_fiber::sleep_for(ms); time_point t1 = Clock::now(); std::chrono::nanoseconds ns = (t1 - t0) - ms; - std::chrono::nanoseconds err = ms / 100; - // The time slept is within 1% of 500ms + 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()); - //BOOST_TEST(std::abs(static_cast(ns.count())) < (err+std::chrono::milliseconds(1000)).count()); } void test_sleep_until() { @@ -380,11 +374,9 @@ void test_sleep_until() { boost::this_fiber::sleep_until(t0 + ms); time_point t1 = Clock::now(); std::chrono::nanoseconds ns = (t1 - t0) - ms; - std::chrono::nanoseconds err = ms / 100; - // The time slept is within 1% of 500ms + 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()); - //BOOST_TEST(std::abs(static_cast(ns.count())) < (err+std::chrono::milliseconds(1000)).count()); } { typedef std::chrono::system_clock Clock; @@ -394,11 +386,9 @@ void test_sleep_until() { boost::this_fiber::sleep_until(t0 + ms); time_point t1 = Clock::now(); std::chrono::nanoseconds ns = (t1 - t0) - ms; - std::chrono::nanoseconds err = ms / 100; - // The time slept is within 1% of 500ms + 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()); - //BOOST_TEST(std::abs(static_cast(ns.count())) < (err+std::chrono::milliseconds(1000)).count()); } } diff --git a/test/test_future_dispatch.cpp b/test/test_future_dispatch.cpp index 49cda20d..2990ec41 100644 --- a/test/test_future_dispatch.cpp +++ b/test/test_future_dispatch.cpp @@ -99,7 +99,7 @@ void fn12( boost::fibers::promise< int& > p) { } void fn13( boost::fibers::promise< void > p) { - boost::this_fiber::sleep_for( ms(500) ); + boost::this_fiber::sleep_for( ms(400) ); p.set_value(); } @@ -414,7 +414,7 @@ void test_future_wait_for() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_for( ms(300) ); + status = f1.wait_for( ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); @@ -434,7 +434,7 @@ void test_future_wait_for_ref() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_for( ms(300) ); + status = f1.wait_for( ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); @@ -454,7 +454,7 @@ void test_future_wait_for_void() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_for( ms(300) ); + status = f1.wait_for( ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); @@ -474,7 +474,7 @@ void test_future_wait_until() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_until( Clock::now() + ms(300) ); + status = f1.wait_until( Clock::now() + ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); @@ -494,7 +494,7 @@ void test_future_wait_until_ref() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_until( Clock::now() + ms(300) ); + status = f1.wait_until( Clock::now() + ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); @@ -514,7 +514,7 @@ void test_future_wait_until_void() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_until( Clock::now() + ms(300) ); + status = f1.wait_until( Clock::now() + ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); diff --git a/test/test_future_post.cpp b/test/test_future_post.cpp index b6c847a0..01deb26f 100644 --- a/test/test_future_post.cpp +++ b/test/test_future_post.cpp @@ -99,7 +99,7 @@ void fn12( boost::fibers::promise< int& > p) { } void fn13( boost::fibers::promise< void > p) { - boost::this_fiber::sleep_for( ms(500) ); + boost::this_fiber::sleep_for( ms(400) ); p.set_value(); } @@ -414,7 +414,7 @@ void test_future_wait_for() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_for( ms(300) ); + status = f1.wait_for( ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); @@ -434,7 +434,7 @@ void test_future_wait_for_ref() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_for( ms(300) ); + status = f1.wait_for( ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); @@ -454,7 +454,7 @@ void test_future_wait_for_void() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_for( ms(300) ); + status = f1.wait_for( ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); @@ -474,7 +474,7 @@ void test_future_wait_until() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_until( Clock::now() + ms(300) ); + status = f1.wait_until( Clock::now() + ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); @@ -494,7 +494,7 @@ void test_future_wait_until_ref() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_until( Clock::now() + ms(300) ); + status = f1.wait_until( Clock::now() + ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); @@ -514,7 +514,7 @@ void test_future_wait_until_void() { BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); - status = f1.wait_until( Clock::now() + ms(300) ); + status = f1.wait_until( Clock::now() + ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); diff --git a/test/test_mutex_dispatch.cpp b/test/test_mutex_dispatch.cpp index 9c189838..dec8ed4d 100644 --- a/test/test_mutex_dispatch.cpp +++ b/test/test_mutex_dispatch.cpp @@ -47,7 +47,7 @@ void fn3( boost::fibers::timed_mutex & m) { std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms + BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms } void fn4( boost::fibers::timed_mutex & m) { @@ -73,7 +73,7 @@ void fn6( boost::fibers::timed_mutex & m) { BOOST_CHECK(m.try_lock_for(ms(250)) == false); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms } void fn7( boost::fibers::timed_mutex & m) { @@ -82,7 +82,7 @@ void fn7( boost::fibers::timed_mutex & m) { std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5ms + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5ms } void fn8( boost::fibers::timed_mutex & m) { @@ -90,7 +90,7 @@ void fn8( boost::fibers::timed_mutex & m) { BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); ns d = t1 - t0 - ms(250); - ns r = ns(5000000)+ms(1000); // within 6ms + ns r = ns(5000000)+ms(2000); // within 6ms BOOST_CHECK(d < r); // within 6ms } @@ -102,7 +102,7 @@ void fn9( boost::fibers::recursive_timed_mutex & m) { m.unlock(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms + BOOST_CHECK(d < ms(2500)+ms(2000)); // within 2.5 ms } void fn10( boost::fibers::recursive_timed_mutex & m) { @@ -113,7 +113,7 @@ void fn10( boost::fibers::recursive_timed_mutex & m) { m.unlock(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(50000000)+ms(1000)); // within 50 ms + BOOST_CHECK(d < ms(50000)+ms(2000)); // within 50 ms } void fn11( boost::fibers::recursive_timed_mutex & m) { @@ -124,7 +124,7 @@ void fn11( boost::fibers::recursive_timed_mutex & m) { m.unlock(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms } void fn12( boost::fibers::recursive_timed_mutex & m) { @@ -132,7 +132,7 @@ void fn12( boost::fibers::recursive_timed_mutex & m) { BOOST_CHECK(m.try_lock_for(ms(250)) == false); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms + BOOST_CHECK(d < ms(5000)+ms(2000)); // within 5 ms } void fn13( boost::fibers::recursive_timed_mutex & m) { @@ -141,7 +141,7 @@ void fn13( boost::fibers::recursive_timed_mutex & m) { std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms } void fn14( boost::fibers::recursive_timed_mutex & m) { @@ -149,7 +149,7 @@ void fn14( boost::fibers::recursive_timed_mutex & m) { BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms } void fn15( boost::fibers::recursive_mutex & m) { @@ -160,7 +160,7 @@ void fn15( boost::fibers::recursive_mutex & m) { m.unlock(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms + BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms } void fn16( boost::fibers::recursive_mutex & m) { @@ -171,7 +171,7 @@ void fn16( boost::fibers::recursive_mutex & m) { m.unlock(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(50000000)+ms(1000)); // within 50 ms + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms } void fn17( boost::fibers::mutex & m) { @@ -180,7 +180,7 @@ void fn17( boost::fibers::mutex & m) { std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms + BOOST_CHECK(d < ms(2500)+ms(2000)); // within 2.5 ms } void fn18( boost::fibers::mutex & m) { @@ -189,7 +189,7 @@ void fn18( boost::fibers::mutex & m) { std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(50000000)+ms(1000)); // within 50 ms + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms } template< typename M > diff --git a/test/test_mutex_post.cpp b/test/test_mutex_post.cpp index f14a57f3..f88a571f 100644 --- a/test/test_mutex_post.cpp +++ b/test/test_mutex_post.cpp @@ -47,7 +47,7 @@ void fn3( boost::fibers::timed_mutex & m) { std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms + BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms } void fn4( boost::fibers::timed_mutex & m) { @@ -73,7 +73,7 @@ void fn6( boost::fibers::timed_mutex & m) { BOOST_CHECK(m.try_lock_for(ms(250)) == false); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms } void fn7( boost::fibers::timed_mutex & m) { @@ -82,7 +82,7 @@ void fn7( boost::fibers::timed_mutex & m) { std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5ms + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5ms } void fn8( boost::fibers::timed_mutex & m) { @@ -90,7 +90,7 @@ void fn8( boost::fibers::timed_mutex & m) { BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); ns d = t1 - t0 - ms(250); - ns r = ns(5000000)+ms(1000); // within 6ms + ns r = ns(5000000)+ms(2000); // within 6ms BOOST_CHECK(d < r); // within 6ms } @@ -102,7 +102,7 @@ void fn9( boost::fibers::recursive_timed_mutex & m) { m.unlock(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms + BOOST_CHECK(d < ms(2500)+ms(2000)); // within 2.5 ms } void fn10( boost::fibers::recursive_timed_mutex & m) { @@ -113,7 +113,7 @@ void fn10( boost::fibers::recursive_timed_mutex & m) { m.unlock(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(50000000)+ms(1000)); // within 50 ms + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms } void fn11( boost::fibers::recursive_timed_mutex & m) { @@ -124,7 +124,7 @@ void fn11( boost::fibers::recursive_timed_mutex & m) { m.unlock(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms } void fn12( boost::fibers::recursive_timed_mutex & m) { @@ -132,7 +132,7 @@ void fn12( boost::fibers::recursive_timed_mutex & m) { BOOST_CHECK(m.try_lock_for(ms(250)) == false); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms + BOOST_CHECK(d < ms(5000)+ms(2000)); // within 5 ms } void fn13( boost::fibers::recursive_timed_mutex & m) { @@ -141,7 +141,7 @@ void fn13( boost::fibers::recursive_timed_mutex & m) { std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms } void fn14( boost::fibers::recursive_timed_mutex & m) { @@ -149,7 +149,7 @@ void fn14( boost::fibers::recursive_timed_mutex & m) { BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms } void fn15( boost::fibers::recursive_mutex & m) { @@ -160,7 +160,7 @@ void fn15( boost::fibers::recursive_mutex & m) { m.unlock(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms + BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms } void fn16( boost::fibers::recursive_mutex & m) { @@ -171,7 +171,7 @@ void fn16( boost::fibers::recursive_mutex & m) { m.unlock(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(50000000)+ms(1000)); // within 50 ms + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms } void fn17( boost::fibers::mutex & m) { @@ -180,7 +180,7 @@ void fn17( boost::fibers::mutex & m) { std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms + BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms } void fn18( boost::fibers::mutex & m) { @@ -189,7 +189,7 @@ void fn18( boost::fibers::mutex & m) { std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); m.unlock(); ns d = t1 - t0 - ms(250); - BOOST_CHECK(d < ns(50000000)+ms(1000)); // within 50 ms + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms } template< typename M > From 1ddea95cccb3b6c94632a1777df7faf57aeed93f Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Sat, 3 Jun 2017 22:41:29 +0200 Subject: [PATCH 02/15] fiber unit-tests pass pointer instead of reference (MSVC-14.0 issue) --- test/test_fiber_dispatch.cpp | 2 +- test/test_fiber_post.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_fiber_dispatch.cpp b/test/test_fiber_dispatch.cpp index d7fce6c9..458fe4ea 100644 --- a/test/test_fiber_dispatch.cpp +++ b/test/test_fiber_dispatch.cpp @@ -178,7 +178,7 @@ void test_join_fn() { void test_join_memfn() { X x = {0}; BOOST_CHECK_EQUAL( x.value, 0); - boost::fibers::fiber( boost::fibers::launch::dispatch, & X::foo, std::ref( x), 3).join(); + boost::fibers::fiber( boost::fibers::launch::dispatch, & X::foo, & x, 3).join(); BOOST_CHECK_EQUAL( x.value, 3); } diff --git a/test/test_fiber_post.cpp b/test/test_fiber_post.cpp index d880b6d8..f57f6cc2 100644 --- a/test/test_fiber_post.cpp +++ b/test/test_fiber_post.cpp @@ -178,7 +178,7 @@ void test_join_fn() { void test_join_memfn() { X x = {0}; BOOST_CHECK_EQUAL( x.value, 0); - boost::fibers::fiber( boost::fibers::launch::post, & X::foo, std::ref( x), 3).join(); + boost::fibers::fiber( boost::fibers::launch::post, & X::foo, & x, 3).join(); BOOST_CHECK_EQUAL( x.value, 3); } From 18c0a64dfd71b50eeeb1eec559b2d3aa0339326e Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Sun, 4 Jun 2017 13:07:38 +0200 Subject: [PATCH 03/15] correct CPU model used for perforance tests in documentation --- doc/performance.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/performance.qbk b/doc/performance.qbk index de73e2ae..0e585d75 100644 --- a/doc/performance.qbk +++ b/doc/performance.qbk @@ -11,7 +11,7 @@ Performance measurements were taken using `std::chrono::highresolution_clock`, with overhead corrections. The code was compiled with gcc-6.3.1, using build options: variant = release, optimization = speed. -Tests were executed on dual Intel XEON E5 2620 2.2GHz, 16C/32T, 64GB RAM, +Tests were executed on dual Intel XEON E5 2620v4 2.2GHz, 16C/32T, 64GB RAM, running Linux (x86_64). Measurements headed 1C/1T were run in a single-threaded process. From a5b22fb6d6b698a1bbfd8b9ba82e26800013f2b1 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Sun, 4 Jun 2017 13:08:43 +0200 Subject: [PATCH 04/15] prefetching of context in algo-implementations --- .../boost/fiber/algo/numa/work_stealing.hpp | 4 +-- include/boost/fiber/detail/config.hpp | 7 ---- src/algo/numa/work_stealing.cpp | 34 +++++++++++-------- src/algo/round_robin.cpp | 2 ++ src/algo/work_stealing.cpp | 23 +++++++------ 5 files changed, 36 insertions(+), 34 deletions(-) diff --git a/include/boost/fiber/algo/numa/work_stealing.hpp b/include/boost/fiber/algo/numa/work_stealing.hpp index cacf4470..40e34b35 100644 --- a/include/boost/fiber/algo/numa/work_stealing.hpp +++ b/include/boost/fiber/algo/numa/work_stealing.hpp @@ -47,9 +47,9 @@ private: std::uniform_int_distribution< std::uint32_t > local_distribution_; std::uniform_int_distribution< std::uint32_t > remote_distribution_; #ifdef BOOST_FIBERS_USE_SPMC_QUEUE - detail::context_spmc_queue rqueue_{}; + detail::context_spmc_queue rqueue_{}; #else - detail::context_spinlock_queue rqueue_{}; + detail::context_spinlock_queue rqueue_{}; #endif std::mutex mtx_{}; std::condition_variable cnd_{}; diff --git a/include/boost/fiber/detail/config.hpp b/include/boost/fiber/detail/config.hpp index cb190591..21dea693 100644 --- a/include/boost/fiber/detail/config.hpp +++ b/include/boost/fiber/detail/config.hpp @@ -63,11 +63,4 @@ # define BOOST_FIBERS_SPIN_BEFORE_YIELD 64 #endif -// modern architectures have cachelines with 64byte length -// ARM Cortex-A15 32/64byte, Cortex-A9 16/32/64bytes -// MIPS 74K: 32byte, 4KEc: 16byte -// ist shoudl be safe to use 64byte for all -static constexpr std::size_t cache_alignment{ 64 }; -static constexpr std::size_t cacheline_length{ 64 }; - #endif // BOOST_FIBERS_DETAIL_CONFIG_H diff --git a/src/algo/numa/work_stealing.cpp b/src/algo/numa/work_stealing.cpp index e52c2a80..9022cc97 100644 --- a/src/algo/numa/work_stealing.cpp +++ b/src/algo/numa/work_stealing.cpp @@ -11,6 +11,7 @@ #include #include +#include #include "boost/fiber/type.hpp" @@ -91,10 +92,11 @@ work_stealing::awakened( context * ctx) noexcept { context * work_stealing::pick_next() noexcept { - context * ctx = rqueue_.pop(); - if ( nullptr != ctx) { - if ( ! ctx->is_context( type::pinned_context) ) { - context::active()->attach( ctx); + context * victim = rqueue_.pop(); + if ( nullptr != victim) { + boost::context::detail::prefetch_range( victim, sizeof( victim) ); + if ( ! victim->is_context( type::pinned_context) ) { + context::active()->attach( victim); } } else { std::uint32_t cpu_id = 0; @@ -110,11 +112,12 @@ work_stealing::pick_next() noexcept { // steal context from other scheduler // schedulers_[cpu_id] should never contain a nullptr BOOST_ASSERT( nullptr != schedulers_[cpu_id]); - ctx = schedulers_[cpu_id]->steal(); - } while ( nullptr == ctx && count < size); - if ( nullptr != ctx) { - BOOST_ASSERT( ! ctx->is_context( type::pinned_context) ); - context::active()->attach( ctx); + victim = schedulers_[cpu_id]->steal(); + } while ( nullptr == victim && count < size); + if ( nullptr != victim) { + boost::context::detail::prefetch_range( victim, sizeof( victim) ); + BOOST_ASSERT( ! victim->is_context( type::pinned_context) ); + context::active()->attach( victim); } else if ( ! remote_cpus_.empty() ) { cpu_id = 0; count = 0; @@ -129,17 +132,18 @@ work_stealing::pick_next() noexcept { // schedulers_[cpu_id] should never contain a nullptr BOOST_ASSERT( nullptr != schedulers_[cpu_id]); // steal context from other scheduler - ctx = schedulers_[cpu_id]->steal(); - } while ( nullptr == ctx && count < size); - if ( nullptr != ctx) { - BOOST_ASSERT( ! ctx->is_context( type::pinned_context) ); + victim = schedulers_[cpu_id]->steal(); + } while ( nullptr == victim && count < size); + if ( nullptr != victim) { + boost::context::detail::prefetch_range( victim, sizeof( victim) ); + BOOST_ASSERT( ! victim->is_context( type::pinned_context) ); // move memory from remote NUMA-node to // memory of local NUMA-node - context::active()->attach( ctx); + context::active()->attach( victim); } } } - return ctx; + return victim; } void diff --git a/src/algo/round_robin.cpp b/src/algo/round_robin.cpp index 37866a7a..2b90b5a8 100644 --- a/src/algo/round_robin.cpp +++ b/src/algo/round_robin.cpp @@ -7,6 +7,7 @@ #include "boost/fiber/algo/round_robin.hpp" #include +#include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -30,6 +31,7 @@ round_robin::pick_next() noexcept { if ( ! rqueue_.empty() ) { victim = & rqueue_.front(); rqueue_.pop_front(); + boost::context::detail::prefetch_range( victim, sizeof( victim) ); BOOST_ASSERT( nullptr != victim); BOOST_ASSERT( ! victim->ready_is_linked() ); BOOST_ASSERT( victim->is_resumable() ); diff --git a/src/algo/work_stealing.cpp b/src/algo/work_stealing.cpp index 36fe67bb..53434ca2 100644 --- a/src/algo/work_stealing.cpp +++ b/src/algo/work_stealing.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "boost/fiber/type.hpp" @@ -52,10 +53,11 @@ work_stealing::awakened( context * ctx) noexcept { context * work_stealing::pick_next() noexcept { - context * ctx = rqueue_.pop(); - if ( nullptr != ctx) { - if ( ! ctx->is_context( type::pinned_context) ) { - context::active()->attach( ctx); + context * victim = rqueue_.pop(); + if ( nullptr != victim) { + boost::context::detail::prefetch_range( victim, sizeof( victim) ); + if ( ! victim->is_context( type::pinned_context) ) { + context::active()->attach( victim); } } else { std::uint32_t id = 0; @@ -69,14 +71,15 @@ work_stealing::pick_next() noexcept { // prevent stealing from own scheduler } while ( id == id_); // steal context from other scheduler - ctx = schedulers_[id]->steal(); - } while ( nullptr == ctx && count < size); - if ( nullptr != ctx) { - BOOST_ASSERT( ! ctx->is_context( type::pinned_context) ); - context::active()->attach( ctx); + victim = schedulers_[id]->steal(); + } while ( nullptr == victim && count < size); + if ( nullptr != victim) { + boost::context::detail::prefetch_range( victim, sizeof( victim) ); + BOOST_ASSERT( ! victim->is_context( type::pinned_context) ); + context::active()->attach( victim); } } - return ctx; + return victim; } void From c8f6ddc49704660df654e88aed56f79d98a1b3d7 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Sun, 4 Jun 2017 21:31:05 +0200 Subject: [PATCH 05/15] use conditional expression likely/unlikely --- include/boost/fiber/algo/algorithm.hpp | 2 +- include/boost/fiber/buffered_channel.hpp | 25 +++++----- include/boost/fiber/fiber.hpp | 2 +- include/boost/fiber/fss.hpp | 6 +-- .../fiber/future/detail/shared_state.hpp | 10 ++-- include/boost/fiber/future/future.hpp | 48 +++++++++---------- include/boost/fiber/future/packaged_task.hpp | 8 ++-- include/boost/fiber/future/promise.hpp | 16 +++---- include/boost/fiber/operations.hpp | 2 +- include/boost/fiber/unbuffered_channel.hpp | 22 ++++----- src/barrier.cpp | 2 +- src/fiber.cpp | 6 +-- src/mutex.cpp | 6 +-- src/numa/aix/pin_thread.cpp | 2 +- src/numa/aix/topology.cpp | 2 +- src/numa/freebsd/pin_thread.cpp | 2 +- src/numa/freebsd/topology.cpp | 2 +- src/numa/hpux/pin_thread.cpp | 2 +- src/numa/hpux/topology.cpp | 2 +- src/numa/linux/pin_thread.cpp | 2 +- src/numa/solaris/pin_thread.cpp | 4 +- src/numa/solaris/topology.cpp | 2 +- src/numa/windows/pin_thread.cpp | 2 +- src/numa/windows/topology.cpp | 8 ++-- src/recursive_mutex.cpp | 2 +- src/recursive_timed_mutex.cpp | 2 +- src/timed_mutex.cpp | 6 +-- 27 files changed, 98 insertions(+), 97 deletions(-) diff --git a/include/boost/fiber/algo/algorithm.hpp b/include/boost/fiber/algo/algorithm.hpp index 3bc8eca2..b22a5923 100644 --- a/include/boost/fiber/algo/algorithm.hpp +++ b/include/boost/fiber/algo/algorithm.hpp @@ -81,7 +81,7 @@ struct algorithm_with_properties : public algorithm_with_properties_base { // with: algorithm_with_properties::awakened(fb); virtual void awakened( context * ctx) noexcept override final { fiber_properties * props = super::get_properties( ctx); - if ( nullptr == props) { + if ( BOOST_LIKELY( nullptr == props) ) { // TODO: would be great if PROPS could be allocated on the new // fiber's stack somehow props = new_properties( ctx); diff --git a/include/boost/fiber/buffered_channel.hpp b/include/boost/fiber/buffered_channel.hpp index 7f9f6ab0..474ac260 100644 --- a/include/boost/fiber/buffered_channel.hpp +++ b/include/boost/fiber/buffered_channel.hpp @@ -64,7 +64,7 @@ private: public: explicit buffered_channel( std::size_t capacity) : capacity_{ capacity } { - if ( 2 > capacity_ || 0 != ( capacity_ & (capacity_ - 1) ) ) { + if ( BOOST_UNLIKELY( 2 > capacity_ || 0 != ( capacity_ & (capacity_ - 1) ) ) ) { throw fiber_error{ std::make_error_code( std::errc::invalid_argument), "boost fiber: buffer capacity is invalid" }; } @@ -105,7 +105,7 @@ public: channel_op_status try_push( value_type const& value) { context * active_ctx = context::active(); detail::spinlock_lock lk{ splk_ }; - if ( is_closed_() ) { + if ( BOOST_UNLIKELY( is_closed_() ) ) { return channel_op_status::closed; } else if ( is_full_() ) { return channel_op_status::full; @@ -126,7 +126,7 @@ public: channel_op_status try_push( value_type && value) { context * active_ctx = context::active(); detail::spinlock_lock lk{ splk_ }; - if ( is_closed_() ) { + if ( BOOST_UNLIKELY( is_closed_() ) ) { return channel_op_status::closed; } else if ( is_full_() ) { return channel_op_status::full; @@ -148,7 +148,7 @@ public: context * active_ctx = context::active(); for (;;) { detail::spinlock_lock lk{ splk_ }; - if ( is_closed_() ) { + if ( BOOST_UNLIKELY( is_closed_() ) ) { return channel_op_status::closed; } else if ( is_full_() ) { active_ctx->wait_link( waiting_producers_); @@ -173,7 +173,7 @@ public: context * active_ctx = context::active(); for (;;) { detail::spinlock_lock lk{ splk_ }; - if ( is_closed_() ) { + if ( BOOST_UNLIKELY( is_closed_() ) ) { return channel_op_status::closed; } else if ( is_full_() ) { active_ctx->wait_link( waiting_producers_); @@ -215,7 +215,7 @@ public: std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); for (;;) { detail::spinlock_lock lk{ splk_ }; - if ( is_closed_() ) { + if ( BOOST_UNLIKELY( is_closed_() ) ) { return channel_op_status::closed; } else if ( is_full_() ) { active_ctx->wait_link( waiting_producers_); @@ -249,7 +249,7 @@ public: std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); for (;;) { detail::spinlock_lock lk{ splk_ }; - if ( is_closed_() ) { + if ( BOOST_UNLIKELY( is_closed_() ) ) { return channel_op_status::closed; } else if ( is_full_() ) { active_ctx->wait_link( waiting_producers_); @@ -302,7 +302,7 @@ public: for (;;) { detail::spinlock_lock lk{ splk_ }; if ( is_empty_() ) { - if ( is_closed_() ) { + if ( BOOST_UNLIKELY( is_closed_() ) ) { return channel_op_status::closed; } else { active_ctx->wait_link( waiting_consumers_); @@ -329,7 +329,7 @@ public: for (;;) { detail::spinlock_lock lk{ splk_ }; if ( is_empty_() ) { - if ( is_closed_() ) { + if ( BOOST_UNLIKELY( is_closed_() ) ) { throw fiber_error{ std::make_error_code( std::errc::operation_not_permitted), "boost fiber: channel is closed" }; @@ -368,7 +368,7 @@ public: for (;;) { detail::spinlock_lock lk{ splk_ }; if ( is_empty_() ) { - if ( is_closed_() ) { + if ( BOOST_UNLIKELY( is_closed_() ) ) { return channel_op_status::closed; } else { active_ctx->wait_link( waiting_consumers_); @@ -428,8 +428,9 @@ public: } iterator & operator=( iterator const& other) noexcept { - if ( this == & other) return * this; - chan_ = other.chan_; + if ( BOOST_LIKELY( this != & other) ) { + chan_ = other.chan_; + } return * this; } diff --git a/include/boost/fiber/fiber.hpp b/include/boost/fiber/fiber.hpp index 5dfe5f4f..afee7171 100644 --- a/include/boost/fiber/fiber.hpp +++ b/include/boost/fiber/fiber.hpp @@ -108,7 +108,7 @@ public: if ( joinable() ) { std::terminate(); } - if ( this == & other) { + if ( BOOST_UNLIKELY( this == & other) ) { return * this; } impl_.swap( other.impl_); diff --git a/include/boost/fiber/fss.hpp b/include/boost/fiber/fss.hpp index f65d7353..0a321bb6 100644 --- a/include/boost/fiber/fss.hpp +++ b/include/boost/fiber/fss.hpp @@ -37,8 +37,8 @@ private: fn{ fn_ } { } - void operator()( void* data) { - if ( fn) { + void operator()( void * data) { + if ( BOOST_LIKELY( nullptr != fn) ) { fn( static_cast< T * >( data) ); } } @@ -91,7 +91,7 @@ public: void reset( T * t) { T * c = get(); - if ( c != t) { + if ( BOOST_LIKELY( c != t) ) { context::active()->set_fss_data( this, cleanup_fn_, t, true); } diff --git a/include/boost/fiber/future/detail/shared_state.hpp b/include/boost/fiber/future/detail/shared_state.hpp index d8eb1098..28e0e3cf 100644 --- a/include/boost/fiber/future/detail/shared_state.hpp +++ b/include/boost/fiber/future/detail/shared_state.hpp @@ -62,7 +62,7 @@ protected: void set_exception_( std::exception_ptr except, std::unique_lock< mutex > & lk) { BOOST_ASSERT( lk.owns_lock() ); - if ( ready_) { + if ( BOOST_UNLIKELY( ready_) ) { throw promise_already_satisfied(); } except_ = except; @@ -161,7 +161,7 @@ private: void set_value_( R const& value, std::unique_lock< mutex > & lk) { BOOST_ASSERT( lk.owns_lock() ); - if ( ready_) { + if ( BOOST_UNLIKELY( ready_) ) { throw promise_already_satisfied{}; } ::new ( static_cast< void * >( std::addressof( storage_) ) ) R( value ); @@ -170,7 +170,7 @@ private: void set_value_( R && value, std::unique_lock< mutex > & lk) { BOOST_ASSERT( lk.owns_lock() ); - if ( ready_) { + if ( BOOST_UNLIKELY( ready_) ) { throw promise_already_satisfied{}; } ::new ( static_cast< void * >( std::addressof( storage_) ) ) R( std::move( value) ); @@ -223,7 +223,7 @@ private: void set_value_( R & value, std::unique_lock< mutex > & lk) { BOOST_ASSERT( lk.owns_lock() ); - if ( ready_) { + if ( BOOST_UNLIKELY( ready_) ) { throw promise_already_satisfied(); } value_ = std::addressof( value); @@ -266,7 +266,7 @@ private: inline void set_value_( std::unique_lock< mutex > & lk) { BOOST_ASSERT( lk.owns_lock() ); - if ( ready_) { + if ( BOOST_UNLIKELY( ready_) ) { throw promise_already_satisfied(); } mark_ready_and_notify_( lk); diff --git a/include/boost/fiber/future/future.hpp b/include/boost/fiber/future/future.hpp index 5d4ad78a..2191080d 100644 --- a/include/boost/fiber/future/future.hpp +++ b/include/boost/fiber/future/future.hpp @@ -46,14 +46,14 @@ struct future_base { } future_base & operator=( future_base const& other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { state_ = other.state_; } return * this; } future_base & operator=( future_base && other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { state_ = other.state_; other.state_.reset(); } @@ -65,14 +65,14 @@ struct future_base { } std::exception_ptr get_exception_ptr() { - if ( ! valid() ) { + if ( BOOST_UNLIKELY( ! valid() ) ) { throw future_uninitialized{}; } return state_->get_exception_ptr(); } void wait() const { - if ( ! valid() ) { + if ( BOOST_UNLIKELY( ! valid() ) ) { throw future_uninitialized{}; } state_->wait(); @@ -80,7 +80,7 @@ struct future_base { template< typename Rep, typename Period > future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - if ( ! valid() ) { + if ( BOOST_UNLIKELY( ! valid() ) ) { throw future_uninitialized{}; } return state_->wait_for( timeout_duration); @@ -88,7 +88,7 @@ struct future_base { template< typename Clock, typename Duration > future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - if ( ! valid() ) { + if ( BOOST_UNLIKELY( ! valid() ) ) { throw future_uninitialized{}; } return state_->wait_until( timeout_time); @@ -131,7 +131,7 @@ public: } future & operator=( future && other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { base_type::operator=( std::move( other) ); } return * this; @@ -140,7 +140,7 @@ public: shared_future< R > share(); R get() { - if ( ! base_type::valid() ) { + if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { throw future_uninitialized{}; } typename base_type::ptr_type tmp{}; @@ -180,7 +180,7 @@ public: } future & operator=( future && other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { base_type::operator=( std::move( other) ); } return * this; @@ -189,7 +189,7 @@ public: shared_future< R & > share(); R & get() { - if ( ! base_type::valid() ) { + if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { throw future_uninitialized{}; } typename base_type::ptr_type tmp{}; @@ -231,7 +231,7 @@ public: inline future & operator=( future && other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { base_type::operator=( std::move( other) ); } return * this; @@ -241,7 +241,7 @@ public: inline void get() { - if ( ! base_type::valid() ) { + if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { throw future_uninitialized{}; } base_type::ptr_type tmp{}; @@ -284,14 +284,14 @@ public: } shared_future & operator=( shared_future const& other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { base_type::operator=( other); } return * this; } shared_future & operator=( shared_future && other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { base_type::operator=( std::move( other) ); } return * this; @@ -303,7 +303,7 @@ public: } R const& get() const { - if ( ! valid() ) { + if ( BOOST_UNLIKELY( ! valid() ) ) { throw future_uninitialized{}; } return base_type::state_->get(); @@ -343,14 +343,14 @@ public: } shared_future & operator=( shared_future const& other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { base_type::operator=( other); } return * this; } shared_future & operator=( shared_future && other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { base_type::operator=( std::move( other) ); } return * this; @@ -362,7 +362,7 @@ public: } R & get() const { - if ( ! valid() ) { + if ( BOOST_UNLIKELY( ! valid() ) ) { throw future_uninitialized{}; } return base_type::state_->get(); @@ -406,7 +406,7 @@ public: inline shared_future & operator=( shared_future const& other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { base_type::operator=( other); } return * this; @@ -414,7 +414,7 @@ public: inline shared_future & operator=( shared_future && other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { base_type::operator=( std::move( other) ); } return * this; @@ -428,7 +428,7 @@ public: inline void get() const { - if ( ! valid() ) { + if ( BOOST_UNLIKELY( ! valid() ) ) { throw future_uninitialized{}; } base_type::state_->get(); @@ -445,7 +445,7 @@ public: template< typename R > shared_future< R > future< R >::share() { - if ( ! base_type::valid() ) { + if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { throw future_uninitialized{}; } return shared_future< R >{ std::move( * this) }; @@ -454,7 +454,7 @@ future< R >::share() { template< typename R > shared_future< R & > future< R & >::share() { - if ( ! base_type::valid() ) { + if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { throw future_uninitialized{}; } return shared_future< R & >{ std::move( * this) }; @@ -463,7 +463,7 @@ future< R & >::share() { inline shared_future< void > future< void >::share() { - if ( ! base_type::valid() ) { + if ( BOOST_UNLIKELY( ! base_type::valid() ) ) { throw future_uninitialized{}; } return shared_future< void >{ std::move( * this) }; diff --git a/include/boost/fiber/future/packaged_task.hpp b/include/boost/fiber/future/packaged_task.hpp index e53bfea3..c8b10d43 100644 --- a/include/boost/fiber/future/packaged_task.hpp +++ b/include/boost/fiber/future/packaged_task.hpp @@ -86,7 +86,7 @@ public: } packaged_task & operator=( packaged_task && other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { packaged_task tmp{ std::move( other) }; swap( tmp); } @@ -106,7 +106,7 @@ public: if ( obtained_) { throw future_already_retrieved{}; } - if ( ! valid() ) { + if ( BOOST_UNLIKELY( ! valid() ) ) { throw packaged_task_uninitialized{}; } obtained_ = true; @@ -115,14 +115,14 @@ public: } void operator()( Args ... args) { - if ( ! valid() ) { + if ( BOOST_UNLIKELY( ! valid() ) ) { throw packaged_task_uninitialized{}; } task_->run( std::forward< Args >( args) ... ); } void reset() { - if ( ! valid() ) { + if ( BOOST_UNLIKELY( ! valid() ) ) { throw packaged_task_uninitialized{}; } packaged_task tmp; diff --git a/include/boost/fiber/future/promise.hpp b/include/boost/fiber/future/promise.hpp index 1815771b..661c8b04 100644 --- a/include/boost/fiber/future/promise.hpp +++ b/include/boost/fiber/future/promise.hpp @@ -68,7 +68,7 @@ struct promise_base { } promise_base & operator=( promise_base && other) noexcept { - if ( this != & other) { + if ( BOOST_LIKELY( this != & other) ) { promise_base tmp{ std::move( other) }; swap( tmp); } @@ -76,10 +76,10 @@ struct promise_base { } future< R > get_future() { - if ( obtained_) { + if ( BOOST_UNLIKELY( obtained_) ) { throw future_already_retrieved{}; } - if ( ! future_) { + if ( BOOST_UNLIKELY( ! future_) ) { throw promise_uninitialized{}; } obtained_ = true; @@ -92,7 +92,7 @@ struct promise_base { } void set_exception( std::exception_ptr p) { - if ( ! future_) { + if ( BOOST_UNLIKELY( ! future_) ) { throw promise_uninitialized{}; } future_->set_exception( p); @@ -121,14 +121,14 @@ public: promise & operator=( promise && other) = default; void set_value( R const& value) { - if ( ! base_type::future_) { + if ( BOOST_UNLIKELY( ! base_type::future_) ) { throw promise_uninitialized{}; } base_type::future_->set_value( value); } void set_value( R && value) { - if ( ! base_type::future_) { + if ( BOOST_UNLIKELY( ! base_type::future_) ) { throw promise_uninitialized{}; } base_type::future_->set_value( std::move( value) ); @@ -162,7 +162,7 @@ public: promise & operator=( promise && other) noexcept = default; void set_value( R & value) { - if ( ! base_type::future_) { + if ( BOOST_UNLIKELY( ! base_type::future_) ) { throw promise_uninitialized{}; } base_type::future_->set_value( value); @@ -197,7 +197,7 @@ public: inline void set_value() { - if ( ! base_type::future_) { + if ( BOOST_UNLIKELY( ! base_type::future_) ) { throw promise_uninitialized{}; } base_type::future_->set_value(); diff --git a/include/boost/fiber/operations.hpp b/include/boost/fiber/operations.hpp index ce7087f8..2e6dd112 100644 --- a/include/boost/fiber/operations.hpp +++ b/include/boost/fiber/operations.hpp @@ -49,7 +49,7 @@ void sleep_for( std::chrono::duration< Rep, Period > const& timeout_duration) { template< typename PROPS > PROPS & properties() { fibers::fiber_properties * props = fibers::context::active()->get_properties(); - if ( ! props) { + if ( BOOST_LIKELY( nullptr != props) ) { // props could be nullptr if the thread's main fiber has not yet // yielded (not yet passed through algorithm_with_properties:: // awakened()). Address that by yielding right now. diff --git a/include/boost/fiber/unbuffered_channel.hpp b/include/boost/fiber/unbuffered_channel.hpp index 53ae00bc..f0df4029 100644 --- a/include/boost/fiber/unbuffered_channel.hpp +++ b/include/boost/fiber/unbuffered_channel.hpp @@ -137,7 +137,7 @@ public: context * active_ctx = context::active(); slot s{ value, active_ctx }; for (;;) { - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { return channel_op_status::closed; } if ( try_push_( & s) ) { @@ -154,7 +154,7 @@ public: return channel_op_status::success; } else { detail::spinlock_lock lk{ splk_producers_ }; - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { return channel_op_status::closed; } if ( is_empty_() ) { @@ -172,7 +172,7 @@ public: context * active_ctx = context::active(); slot s{ std::move( value), active_ctx }; for (;;) { - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { return channel_op_status::closed; } if ( try_push_( & s) ) { @@ -189,7 +189,7 @@ public: return channel_op_status::success; } else { detail::spinlock_lock lk{ splk_producers_ }; - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { return channel_op_status::closed; } if ( is_empty_() ) { @@ -224,7 +224,7 @@ public: slot s{ value, active_ctx }; std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); for (;;) { - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { return channel_op_status::closed; } if ( try_push_( & s) ) { @@ -247,7 +247,7 @@ public: return channel_op_status::success; } else { detail::spinlock_lock lk{ splk_producers_ }; - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { return channel_op_status::closed; } if ( is_empty_() ) { @@ -274,7 +274,7 @@ public: slot s{ std::move( value), active_ctx }; std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); for (;;) { - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { return channel_op_status::closed; } if ( try_push_( & s) ) { @@ -297,7 +297,7 @@ public: return channel_op_status::success; } else { detail::spinlock_lock lk{ splk_producers_ }; - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { return channel_op_status::closed; } if ( is_empty_() ) { @@ -339,7 +339,7 @@ public: return channel_op_status::success; } else { detail::spinlock_lock lk{ splk_consumers_ }; - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { return channel_op_status::closed; } if ( ! is_empty_() ) { @@ -375,7 +375,7 @@ public: return std::move( value); } else { detail::spinlock_lock lk{ splk_consumers_ }; - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { throw fiber_error{ std::make_error_code( std::errc::operation_not_permitted), "boost fiber: channel is closed" }; @@ -423,7 +423,7 @@ public: return channel_op_status::success; } else { detail::spinlock_lock lk{ splk_consumers_ }; - if ( is_closed() ) { + if ( BOOST_UNLIKELY( is_closed() ) ) { return channel_op_status::closed; } if ( ! is_empty_() ) { diff --git a/src/barrier.cpp b/src/barrier.cpp index 87d9be4e..a8aaf36c 100644 --- a/src/barrier.cpp +++ b/src/barrier.cpp @@ -21,7 +21,7 @@ namespace fibers { barrier::barrier( std::size_t initial) : initial_{ initial }, current_{ initial_ } { - if ( 0 == initial) { + if ( BOOST_UNLIKELY( 0 == initial) ) { throw fiber_error{ std::make_error_code( std::errc::invalid_argument), "boost fiber: zero initial barrier count" }; } diff --git a/src/fiber.cpp b/src/fiber.cpp index d337699f..d360812f 100644 --- a/src/fiber.cpp +++ b/src/fiber.cpp @@ -43,11 +43,11 @@ fiber::start_() noexcept { void fiber::join() { // FIXME: must fiber::join() be synchronized? - if ( context::active()->get_id() == get_id() ) { + if ( BOOST_UNLIKELY( context::active()->get_id() == get_id() ) ) { throw fiber_error{ std::make_error_code( std::errc::resource_deadlock_would_occur), "boost fiber: trying to join itself" }; } - if ( ! joinable() ) { + if ( BOOST_UNLIKELY( ! joinable() ) ) { throw fiber_error{ std::make_error_code( std::errc::invalid_argument), "boost fiber: fiber not joinable" }; } @@ -57,7 +57,7 @@ fiber::join() { void fiber::detach() { - if ( ! joinable() ) { + if ( BOOST_UNLIKELY( ! joinable() ) ) { throw fiber_error{ std::make_error_code( std::errc::invalid_argument), "boost fiber: fiber not joinable" }; } diff --git a/src/mutex.cpp b/src/mutex.cpp index cf358326..213bb15f 100644 --- a/src/mutex.cpp +++ b/src/mutex.cpp @@ -26,7 +26,7 @@ mutex::lock() { context * active_ctx = context::active(); // store this fiber in order to be notified later detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( active_ctx == owner_) { + if ( BOOST_UNLIKELY( active_ctx == owner_) ) { throw lock_error{ std::make_error_code( std::errc::resource_deadlock_would_occur), "boost fiber: a deadlock is detected" }; @@ -46,7 +46,7 @@ bool mutex::try_lock() { context * active_ctx = context::active(); detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( active_ctx == owner_) { + if ( BOOST_UNLIKELY( active_ctx == owner_) ) { throw lock_error{ std::make_error_code( std::errc::resource_deadlock_would_occur), "boost fiber: a deadlock is detected" }; @@ -63,7 +63,7 @@ void mutex::unlock() { context * active_ctx = context::active(); detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( active_ctx != owner_) { + if ( BOOST_UNLIKELY( active_ctx != owner_) ) { throw lock_error{ std::make_error_code( std::errc::operation_not_permitted), "boost fiber: no privilege to perform the operation" }; diff --git a/src/numa/aix/pin_thread.cpp b/src/numa/aix/pin_thread.cpp index f3a8d040..437b0de6 100644 --- a/src/numa/aix/pin_thread.cpp +++ b/src/numa/aix/pin_thread.cpp @@ -24,7 +24,7 @@ namespace numa { BOOST_FIBERS_DECL void pin_thread( std::uint32_t cpuid) { - if ( -1 == ::bindprocessor( BINDTHREAD, ::thread_self(), static_cast< cpu_t >( cpuid) ) ) { + if ( BOOST_UNLIKELY( -1 == ::bindprocessor( BINDTHREAD, ::thread_self(), static_cast< cpu_t >( cpuid) ) ) ) { throw std::system_error( std::error_code( errno, std::system_category() ), "bindprocessor() failed"); diff --git a/src/numa/aix/topology.cpp b/src/numa/aix/topology.cpp index d9e9f4d6..107f070f 100644 --- a/src/numa/aix/topology.cpp +++ b/src/numa/aix/topology.cpp @@ -24,7 +24,7 @@ void explore( int sdl, std::vector< boost::fibers::numa::node > & topo) { rsethandle_t rset = ::rs_alloc( RS_PARTITION); rsethandle_t rad = ::rs_alloc( RS_EMPTY); int maxnodes = ::rs_numrads( rset, sdl, 0); - if ( -1 == maxnodes) { + if ( BOOST_UNLIKELY( -1 == maxnodes) ) { throw std::system_error{ std::error_code{ errno, std::system_category() }, "rs_numrads() failed" }; diff --git a/src/numa/freebsd/pin_thread.cpp b/src/numa/freebsd/pin_thread.cpp index ec60668a..83ec95ac 100644 --- a/src/numa/freebsd/pin_thread.cpp +++ b/src/numa/freebsd/pin_thread.cpp @@ -27,7 +27,7 @@ void pin_thread( std::uint32_t cpu_id) { cpuset_t mask; CPU_ZERO( & mask); CPU_SET( cpu_id, & mask); - if ( 0 != ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof( mask), & mask) ) { + if ( BOOST_UNLIKELY( 0 != ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof( mask), & mask) ) ) { throw std::system_error( std::error_code( errno, std::system_category() ), "::cpuset_setaffinity() failed"); diff --git a/src/numa/freebsd/topology.cpp b/src/numa/freebsd/topology.cpp index 4171a1c5..848aea3f 100644 --- a/src/numa/freebsd/topology.cpp +++ b/src/numa/freebsd/topology.cpp @@ -27,7 +27,7 @@ std::vector< node > topology() { std::vector< node > topo; cpuset_t mask; CPU_ZERO( & mask); - if ( 0 != ::cpuset_getaffinity( CPU_LEVEL_WHICH, CPU_WHICH_CPUSET, -1, sizeof( mask), & mask) ) { + if ( BOOST_UNLIKELY( 0 != ::cpuset_getaffinity( CPU_LEVEL_WHICH, CPU_WHICH_CPUSET, -1, sizeof( mask), & mask) ) ) { throw std::system_error{ std::error_code{ errno, std::system_category() }, "::cpuset_getaffinity() failed" }; diff --git a/src/numa/hpux/pin_thread.cpp b/src/numa/hpux/pin_thread.cpp index 1fd606fc..23a75835 100644 --- a/src/numa/hpux/pin_thread.cpp +++ b/src/numa/hpux/pin_thread.cpp @@ -27,7 +27,7 @@ void pin_thread( std::uint32_t cpuid) { & spu, static_cast< pthread_spu_t >( cpuid), PTHREAD_SELFTID_NP); - if ( err != 0) + if ( BOOST_UNLIKELY( 0 != err) ) throw std::system_error( std::error_code( err, std::system_category() ), "pthread_processor_bind_np() failed"); diff --git a/src/numa/hpux/topology.cpp b/src/numa/hpux/topology.cpp index b3318e83..63a40275 100644 --- a/src/numa/hpux/topology.cpp +++ b/src/numa/hpux/topology.cpp @@ -34,7 +34,7 @@ std::vector< node > topology() { int cpu_id = ::mpctl( MPC_GETFIRSTSPU_SYS, 0, 0); while ( -1 != cpu_id) { int node_id = ::mpctl( MPC_SPUTOLDOM, cpu_id, 0); - if ( -1 == node_id) { + if ( BOOST_UNLIKELY( -1 == node_id) ) { throw std::system_errors{ std::error_codes{ errno, std::system_category() }, "mpctl() failed" }; diff --git a/src/numa/linux/pin_thread.cpp b/src/numa/linux/pin_thread.cpp index 3e674fc5..ae696be3 100644 --- a/src/numa/linux/pin_thread.cpp +++ b/src/numa/linux/pin_thread.cpp @@ -27,7 +27,7 @@ void pin_thread( std::uint32_t cpuid) { CPU_ZERO( & set); CPU_SET( cpuid, & set); int err = 0; - if ( 0 != ( err = ::pthread_setaffinity_np( ::pthread_self(), sizeof( set), & set) ) ) { + if ( BOOST_UNLIKELY( 0 != ( err = ::pthread_setaffinity_np( ::pthread_self(), sizeof( set), & set) ) ) ) { throw std::system_error( std::error_code( err, std::system_category() ), "pthread_setaffinity_np() failed"); diff --git a/src/numa/solaris/pin_thread.cpp b/src/numa/solaris/pin_thread.cpp index 2621f3e6..40312e38 100644 --- a/src/numa/solaris/pin_thread.cpp +++ b/src/numa/solaris/pin_thread.cpp @@ -25,10 +25,10 @@ namespace numa { BOOST_FIBERS_DECL void pin_thread( std::uint32_t cpuid) { - if ( -1 == ::processor_bind( P_LWPID, + if ( BOOST_UNLIKELY( -1 == ::processor_bind( P_LWPID, P_MYID, static_cast< processorid_t >( cpuid), - 0) ) { + 0) ) ) { throw std::system_error( std::error_code( errno, std::system_category() ), "processor_bind() failed"); diff --git a/src/numa/solaris/topology.cpp b/src/numa/solaris/topology.cpp index 221a4369..51a12eee 100644 --- a/src/numa/solaris/topology.cpp +++ b/src/numa/solaris/topology.cpp @@ -55,7 +55,7 @@ BOOST_FIBERS_DECL std::vector< node > topology() { std::vector< node > topo; lgrp_cookie_t cookie = ::lgrp_init( LGRP_VIEW_OS); - if ( LGRP_COOKIE_NONE == cookie) { + if ( BOOST_UNLIKELY( LGRP_COOKIE_NONE == cookie) ) { throw std::system_error{ std::error_code{ errno, std::system_category() }, "lprp_init() failed" }; diff --git a/src/numa/windows/pin_thread.cpp b/src/numa/windows/pin_thread.cpp index 96d301a7..34900951 100644 --- a/src/numa/windows/pin_thread.cpp +++ b/src/numa/windows/pin_thread.cpp @@ -32,7 +32,7 @@ void pin_thread( std::uint32_t cpuid) { uint32_t id = cpuid % 64; // set the bit mask of the logical CPU affinity.Mask = static_cast< KAFFINITY >( 1) << id; - if ( 0 == ::SetThreadGroupAffinity( ::GetCurrentThread(), & affinity, nullptr) ) { + if ( BOOST_UNLIKELY( 0 == ::SetThreadGroupAffinity( ::GetCurrentThread(), & affinity, nullptr) ) ) { throw std::system_error( std::error_code( ::GetLastError(), std::system_category() ), "::SetThreadiGroupAffinity() failed"); diff --git a/src/numa/windows/topology.cpp b/src/numa/windows/topology.cpp index d51b60d6..618ddf62 100644 --- a/src/numa/windows/topology.cpp +++ b/src/numa/windows/topology.cpp @@ -35,19 +35,19 @@ public: procinfo_iterator() = default; procinfo_iterator( LOGICAL_PROCESSOR_RELATIONSHIP relship) { - if ( ::GetLogicalProcessorInformationEx( relship, nullptr, & length_) ) { + if ( ::GetLogicalProcessorInformationEx( relship, nullptr, & length_) ) { return; } - if ( ERROR_INSUFFICIENT_BUFFER != ::GetLastError() ) { + if ( BOOST_UNLIKELY( ERROR_INSUFFICIENT_BUFFER != ::GetLastError() ) ) { throw std::system_error{ std::error_code{ static_cast< int >( ::GetLastError() ), std::system_category() }, "::GetLogicalProcessorInformation() failed" }; } buffer_ = reinterpret_cast< SLPI * >( LocalAlloc( LMEM_FIXED, length_) ); - if ( nullptr == buffer_) { + if ( BOOST_UNLIKELY( nullptr == buffer_) ) { throw std::bad_alloc(); } - if ( ! ::GetLogicalProcessorInformationEx( relship, buffer_, & length_) ) { + if ( BOOST_UNLIKELY( ! ::GetLogicalProcessorInformationEx( relship, buffer_, & length_) ) ) { throw std::system_error{ std::error_code{ static_cast< int >( ::GetLastError() ), std::system_category() }, "::GetLogicalProcessorInformation() failed" }; diff --git a/src/recursive_mutex.cpp b/src/recursive_mutex.cpp index a1c25657..67f2334a 100644 --- a/src/recursive_mutex.cpp +++ b/src/recursive_mutex.cpp @@ -61,7 +61,7 @@ void recursive_mutex::unlock() { context * active_ctx = context::active(); detail::spinlock_lock lk( wait_queue_splk_); - if ( active_ctx != owner_) { + if ( BOOST_UNLIKELY( active_ctx != owner_) ) { throw lock_error( std::make_error_code( std::errc::operation_not_permitted), "boost fiber: no privilege to perform the operation"); diff --git a/src/recursive_timed_mutex.cpp b/src/recursive_timed_mutex.cpp index e47d64cf..aa52f15d 100644 --- a/src/recursive_timed_mutex.cpp +++ b/src/recursive_timed_mutex.cpp @@ -91,7 +91,7 @@ void recursive_timed_mutex::unlock() { context * active_ctx = context::active(); detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( active_ctx != owner_) { + if ( BOOST_UNLIKELY( active_ctx != owner_) ) { throw lock_error{ std::make_error_code( std::errc::operation_not_permitted), "boost fiber: no privilege to perform the operation" }; diff --git a/src/timed_mutex.cpp b/src/timed_mutex.cpp index 140f493c..2af68b90 100644 --- a/src/timed_mutex.cpp +++ b/src/timed_mutex.cpp @@ -51,7 +51,7 @@ timed_mutex::lock() { context * active_ctx = context::active(); // store this fiber in order to be notified later detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( active_ctx == owner_) { + if ( BOOST_UNLIKELY( active_ctx == owner_) ) { throw lock_error{ std::make_error_code( std::errc::resource_deadlock_would_occur), "boost fiber: a deadlock is detected" }; @@ -71,7 +71,7 @@ bool timed_mutex::try_lock() { context * active_ctx = context::active(); detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( active_ctx == owner_) { + if ( BOOST_UNLIKELY( active_ctx == owner_) ) { throw lock_error{ std::make_error_code( std::errc::resource_deadlock_would_occur), "boost fiber: a deadlock is detected" }; @@ -88,7 +88,7 @@ void timed_mutex::unlock() { context * active_ctx = context::active(); detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( active_ctx != owner_) { + if ( BOOST_UNLIKELY( active_ctx != owner_) ) { throw lock_error{ std::make_error_code( std::errc::operation_not_permitted), "boost fiber: no privilege to perform the operation" }; From 9b2f84a77a0316e3ed0850f8c73996dd3eaf4b00 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Mon, 5 Jun 2017 20:21:12 +0200 Subject: [PATCH 06/15] fix overloads of fiber ctor for gcc --- include/boost/fiber/fiber.hpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/include/boost/fiber/fiber.hpp b/include/boost/fiber/fiber.hpp index afee7171..eb10487c 100644 --- a/include/boost/fiber/fiber.hpp +++ b/include/boost/fiber/fiber.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -53,9 +54,15 @@ public: template< typename Fn, typename ... Arg, - typename = detail::disable_overload< fiber, Fn > + typename = detail::disable_overload< fiber, Fn >, + typename = detail::disable_overload< launch, Fn >, + typename = detail::disable_overload< std::allocator_arg_t, Fn > > +#if BOOST_COMP_GNUC < 50000000 + fiber( Fn && fn, Arg && ... arg) : +#else fiber( Fn && fn, Arg ... arg) : +#endif fiber{ launch::post, std::allocator_arg, default_stack(), std::forward< Fn >( fn), std::forward< Arg >( arg) ... } { @@ -65,7 +72,11 @@ public: typename ... Arg, typename = detail::disable_overload< fiber, Fn > > +#if BOOST_COMP_GNUC < 50000000 + fiber( launch policy, Fn && fn, Arg && ... arg) : +#else fiber( launch policy, Fn && fn, Arg ... arg) : +#endif fiber{ policy, std::allocator_arg, default_stack(), std::forward< Fn >( fn), std::forward< Arg >( arg) ... } { @@ -75,7 +86,11 @@ public: typename Fn, typename ... Arg > +#if BOOST_COMP_GNUC < 50000000 + fiber( std::allocator_arg_t, StackAllocator salloc, Fn && fn, Arg && ... arg) : +#else fiber( std::allocator_arg_t, StackAllocator salloc, Fn && fn, Arg ... arg) : +#endif fiber{ launch::post, std::allocator_arg, salloc, std::forward< Fn >( fn), std::forward< Arg >( arg) ... } { @@ -85,7 +100,11 @@ public: typename Fn, typename ... Arg > +#if BOOST_COMP_GNUC < 50000000 + fiber( launch policy, std::allocator_arg_t, StackAllocator salloc, Fn && fn, Arg && ... arg) : +#else fiber( launch policy, std::allocator_arg_t, StackAllocator salloc, Fn && fn, Arg ... arg) : +#endif impl_{ make_worker_context( policy, salloc, std::forward< Fn >( fn), std::forward< Arg >( arg) ... ) } { start_(); } From 7400595d852c403e7753ccce66ca03891ac2688e Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Tue, 6 Jun 2017 18:54:28 +0200 Subject: [PATCH 07/15] function and args not moved into context::run_() --- include/boost/fiber/context.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/boost/fiber/context.hpp b/include/boost/fiber/context.hpp index 4054d0b8..64b2e1dc 100644 --- a/include/boost/fiber/context.hpp +++ b/include/boost/fiber/context.hpp @@ -418,10 +418,9 @@ private: boost::context::continuation run_( boost::context::continuation && c) noexcept { + // `noexcept` will call std::terminate() + // if an exception escapes `fn` { - // fn and tpl must be destroyed before calling terminate() - auto fn = std::move( fn_); - auto arg = std::move( arg_); c = c.resume(); context * active_ctx = active(); BOOST_ASSERT( nullptr != active_ctx); @@ -437,9 +436,9 @@ private: active_ctx->ready_ctx_ = nullptr; } #if defined(BOOST_NO_CXX17_STD_APPLY) - boost::context::detail::apply( std::move( fn), std::move( arg) ); + boost::context::detail::apply( std::move( fn_), std::move( arg_) ); #else - std::apply( std::move( fn), std::move( arg) ); + std::apply( std::move( fn_), std::move( arg_) ); #endif } // terminate context From 027d7f3519fe9455f29869136e00a1544548e290 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Tue, 6 Jun 2017 18:55:05 +0200 Subject: [PATCH 08/15] if dequeued from remote-ready-queue test for ready - if a context was signaled from remote, test if it is already in the ready-queue (might be possible by a timedout wait for instance) --- src/scheduler.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 89c76224..8fba44b8 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -58,8 +58,14 @@ scheduler::remote_ready2ready_() noexcept { while ( ! tmp.empty() ) { context * ctx = & tmp.front(); tmp.pop_front(); - // store context in local queues - schedule( ctx); + // ctx was signaled from remote (other thread) + // ctx might have been already resumed because of + // its wait-op. has been already timed out and + // thus it was already pushed to the ready-queue + if ( ! ctx->ready_is_linked() ) { + // store context in local queues + schedule( ctx); + } } } #endif @@ -391,6 +397,7 @@ scheduler::attach_worker_context( context * ctx) noexcept { BOOST_ASSERT( ! ctx->worker_is_linked() ); ctx->worker_link( worker_queue_); ctx->scheduler_ = this; + // an attached context must belong at least to worker-queue } void @@ -406,7 +413,9 @@ scheduler::detach_worker_context( context * ctx) noexcept { BOOST_ASSERT( ctx->worker_is_linked() ); BOOST_ASSERT( ! ctx->is_context( type::pinned_context) ); ctx->worker_unlink(); + BOOST_ASSERT( ! ctx->worker_is_linked() ); ctx->scheduler_ = nullptr; + // a detached context must not belong to any queue } }} From cd6950c0dd85679c15eb0836815818cf1f4970c8 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Thu, 8 Jun 2017 20:40:32 +0200 Subject: [PATCH 09/15] reset stack-size to 4kB/8kB for skynet-tests --- performance/fiber/numa/skynet_stealing_detach.cpp | 8 ++++++++ performance/fiber/skynet_detach.cpp | 8 ++++++++ performance/fiber/skynet_join.cpp | 8 ++++++++ performance/fiber/skynet_shared_detach.cpp | 8 ++++++++ performance/fiber/skynet_shared_join.cpp | 8 ++++++++ performance/fiber/skynet_stealing_async.cpp | 8 ++++++++ performance/fiber/skynet_stealing_detach.cpp | 8 ++++++++ performance/fiber/skynet_stealing_join.cpp | 8 ++++++++ 8 files changed, 64 insertions(+) diff --git a/performance/fiber/numa/skynet_stealing_detach.cpp b/performance/fiber/numa/skynet_stealing_detach.cpp index 6d64064c..ae06b597 100644 --- a/performance/fiber/numa/skynet_stealing_detach.cpp +++ b/performance/fiber/numa/skynet_stealing_detach.cpp @@ -25,6 +25,7 @@ #include #include +#include #include "../barrier.hpp" @@ -85,7 +86,14 @@ int main() { barrier b{ hardware_concurrency( topo) }; std::size_t size{ 1000000 }; std::size_t div{ 10 }; + // Windows 10 and FreeBSD require a fiber stack of 8kb + // otherwise the stack gets exhausted + // stack requirements must be checked for other OS too +#if BOOST_OS_WINDOWS || BOOST_OS_BSD allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; +#else + allocator_type salloc{ allocator_type::traits_type::page_size() }; +#endif std::uint64_t result{ 0 }; channel_type rc{ 2 }; std::vector< std::thread > threads; diff --git a/performance/fiber/skynet_detach.cpp b/performance/fiber/skynet_detach.cpp index d15fd184..5e6d4052 100644 --- a/performance/fiber/skynet_detach.cpp +++ b/performance/fiber/skynet_detach.cpp @@ -19,6 +19,7 @@ #include #include +#include using allocator_type = boost::fibers::fixedsize_stack; using channel_type = boost::fibers::buffered_channel< std::uint64_t >; @@ -51,7 +52,14 @@ int main() { try { std::size_t size{ 1000000 }; std::size_t div{ 10 }; + // Windows 10 and FreeBSD require a fiber stack of 8kb + // otherwise the stack gets exhausted + // stack requirements must be checked for other OS too +#if BOOST_OS_WINDOWS || BOOST_OS_BSD allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; +#else + allocator_type salloc{ allocator_type::traits_type::page_size() }; +#endif std::uint64_t result{ 0 }; channel_type rc{ 2 }; time_point_type start{ clock_type::now() }; diff --git a/performance/fiber/skynet_join.cpp b/performance/fiber/skynet_join.cpp index 1b345374..543ee03f 100644 --- a/performance/fiber/skynet_join.cpp +++ b/performance/fiber/skynet_join.cpp @@ -19,6 +19,7 @@ #include #include +#include using allocator_type = boost::fibers::fixedsize_stack; using channel_type = boost::fibers::buffered_channel< std::uint64_t >; @@ -55,7 +56,14 @@ int main() { try { std::size_t size{ 1000000 }; std::size_t div{ 10 }; + // Windows 10 and FreeBSD require a fiber stack of 8kb + // otherwise the stack gets exhausted + // stack requirements must be checked for other OS too +#if BOOST_OS_WINDOWS || BOOST_OS_BSD allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; +#else + allocator_type salloc{ allocator_type::traits_type::page_size() }; +#endif std::uint64_t result{ 0 }; channel_type rc{ 2 }; time_point_type start{ clock_type::now() }; diff --git a/performance/fiber/skynet_shared_detach.cpp b/performance/fiber/skynet_shared_detach.cpp index d9c71c8c..013de62a 100644 --- a/performance/fiber/skynet_shared_detach.cpp +++ b/performance/fiber/skynet_shared_detach.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "barrier.hpp" @@ -78,7 +79,14 @@ int main() { for ( unsigned int i = 1; i < n; ++i) { threads.emplace_back( thread, i - 1, & b); }; + // Windows 10 and FreeBSD require a fiber stack of 8kb + // otherwise the stack gets exhausted + // stack requirements must be checked for other OS too +#if BOOST_OS_WINDOWS || BOOST_OS_BSD allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; +#else + allocator_type salloc{ allocator_type::traits_type::page_size() }; +#endif std::uint64_t result{ 0 }; channel_type rc{ 2 }; b.wait(); diff --git a/performance/fiber/skynet_shared_join.cpp b/performance/fiber/skynet_shared_join.cpp index f2bf8edc..086e8d41 100644 --- a/performance/fiber/skynet_shared_join.cpp +++ b/performance/fiber/skynet_shared_join.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "barrier.hpp" @@ -82,7 +83,14 @@ int main() { for ( unsigned int i = 1; i < n; ++i) { threads.emplace_back( thread, i - 1, & b); }; + // Windows 10 and FreeBSD require a fiber stack of 8kb + // otherwise the stack gets exhausted + // stack requirements must be checked for other OS too +#if BOOST_OS_WINDOWS || BOOST_OS_BSD allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; +#else + allocator_type salloc{ allocator_type::traits_type::page_size() }; +#endif std::uint64_t result{ 0 }; channel_type rc{ 2 }; b.wait(); diff --git a/performance/fiber/skynet_stealing_async.cpp b/performance/fiber/skynet_stealing_async.cpp index aec1f185..6dd0c7a1 100644 --- a/performance/fiber/skynet_stealing_async.cpp +++ b/performance/fiber/skynet_stealing_async.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "barrier.hpp" @@ -83,7 +84,14 @@ int main() { barrier b{ thread_count }; std::size_t size{ 1000000 }; std::size_t div{ 10 }; + // Windows 10 and FreeBSD require a fiber stack of 8kb + // otherwise the stack gets exhausted + // stack requirements must be checked for other OS too +#if BOOST_OS_WINDOWS || BOOST_OS_BSD allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; +#else + allocator_type salloc{ allocator_type::traits_type::page_size() }; +#endif std::uint64_t result{ 0 }; channel_type rc{ 2 }; std::vector< std::thread > threads; diff --git a/performance/fiber/skynet_stealing_detach.cpp b/performance/fiber/skynet_stealing_detach.cpp index f00c1f31..a0783a1e 100644 --- a/performance/fiber/skynet_stealing_detach.cpp +++ b/performance/fiber/skynet_stealing_detach.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "barrier.hpp" @@ -77,7 +78,14 @@ int main() { barrier b{ thread_count }; std::size_t size{ 1000000 }; std::size_t div{ 10 }; + // Windows 10 and FreeBSD require a fiber stack of 8kb + // otherwise the stack gets exhausted + // stack requirements must be checked for other OS too +#if BOOST_OS_WINDOWS || BOOST_OS_BSD allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; +#else + allocator_type salloc{ allocator_type::traits_type::page_size() }; +#endif std::uint64_t result{ 0 }; channel_type rc{ 2 }; std::vector< std::thread > threads; diff --git a/performance/fiber/skynet_stealing_join.cpp b/performance/fiber/skynet_stealing_join.cpp index 81b61554..b8c4028e 100644 --- a/performance/fiber/skynet_stealing_join.cpp +++ b/performance/fiber/skynet_stealing_join.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "barrier.hpp" @@ -81,7 +82,14 @@ int main() { barrier b{ thread_count }; std::size_t size{ 1000000 }; std::size_t div{ 10 }; + // Windows 10 and FreeBSD require a fiber stack of 8kb + // otherwise the stack gets exhausted + // stack requirements must be checked for other OS too +#if BOOST_OS_WINDOWS || BOOST_OS_BSD allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; +#else + allocator_type salloc{ allocator_type::traits_type::page_size() }; +#endif std::uint64_t result{ 0 }; channel_type rc{ 2 }; std::vector< std::thread > threads; From 47d80ff617cb1ea3a1471bd02ff5a49067c5b94d Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Fri, 9 Jun 2017 16:34:34 +0200 Subject: [PATCH 10/15] refactor creation of context --- include/boost/fiber/context.hpp | 4 +--- src/context.cpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/include/boost/fiber/context.hpp b/include/boost/fiber/context.hpp index 64b2e1dc..4d645ca5 100644 --- a/include/boost/fiber/context.hpp +++ b/include/boost/fiber/context.hpp @@ -467,11 +467,9 @@ static intrusive_ptr< context > make_worker_context( launch policy, typedef worker_context< Fn, Arg ... > context_t; auto sctx = salloc.allocate(); - BOOST_ASSERT( ( sizeof( context_t) + 2048) < sctx.size); // stack at least of 2kB - const std::size_t offset = sizeof( context_t) + 63; // reserve space for control structure void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( offset) ) + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( context_t) ) ) & ~ static_cast< uintptr_t >( 0xff) ); void * stack_bottom = reinterpret_cast< void * >( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); diff --git a/src/context.cpp b/src/context.cpp index 507005cf..3769144b 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -61,11 +61,9 @@ public: static intrusive_ptr< context > make_dispatcher_context() { default_stack salloc; // use default satck-size auto sctx = salloc.allocate(); - BOOST_ASSERT( ( sizeof( dispatcher_context) + 2048) < sctx.size); // stack at least of 2kB - const std::size_t offset = sizeof( dispatcher_context) + 63; // reserve space for control structure void * storage = reinterpret_cast< void * >( - ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( offset) ) + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( dispatcher_context) ) ) & ~ static_cast< uintptr_t >( 0xff) ); void * stack_bottom = reinterpret_cast< void * >( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); From 18bba329e8b9b2b8987f967627f230197c21ff5b Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Fri, 9 Jun 2017 16:34:58 +0200 Subject: [PATCH 11/15] make std::minstd_rand non local in spinlocks --- include/boost/fiber/detail/spinlock_rtm.hpp | 8 ++++---- include/boost/fiber/detail/spinlock_ttas.hpp | 6 +++--- include/boost/fiber/detail/spinlock_ttas_adaptive.hpp | 6 +++--- .../boost/fiber/detail/spinlock_ttas_adaptive_futex.hpp | 6 +++--- include/boost/fiber/detail/spinlock_ttas_futex.hpp | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/boost/fiber/detail/spinlock_rtm.hpp b/include/boost/fiber/detail/spinlock_rtm.hpp index 62d2e1b5..14660fab 100644 --- a/include/boost/fiber/detail/spinlock_rtm.hpp +++ b/include/boost/fiber/detail/spinlock_rtm.hpp @@ -25,17 +25,17 @@ namespace detail { template< typename FBSplk > class spinlock_rtm { private: - FBSplk splk_; + FBSplk splk_{}; + std::minstd_rand generator_{}; public: - spinlock_rtm() noexcept = default; + spinlock_rtm() = default; spinlock_rtm( spinlock_rtm const&) = delete; spinlock_rtm & operator=( spinlock_rtm const&) = delete; void lock() noexcept { std::size_t collisions = 0 ; - std::minstd_rand generator; for ( std::size_t retries = 0; retries < BOOST_FIBERS_RETRY_THRESHOLD; ++retries) { std::uint32_t status; if ( rtm_status::success == ( status = rtm_begin() ) ) { @@ -56,7 +56,7 @@ public: if ( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD > collisions) { std::uniform_int_distribution< std::size_t > distribution{ 0, static_cast< std::size_t >( 1) << (std::min)(collisions, static_cast< std::size_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) }; - const std::size_t z = distribution( generator); + const std::size_t z = distribution( generator_); ++collisions; for ( std::size_t i = 0; i < z; ++i) { cpu_relax(); diff --git a/include/boost/fiber/detail/spinlock_ttas.hpp b/include/boost/fiber/detail/spinlock_ttas.hpp index e5fea603..146a4a72 100644 --- a/include/boost/fiber/detail/spinlock_ttas.hpp +++ b/include/boost/fiber/detail/spinlock_ttas.hpp @@ -31,16 +31,16 @@ private: friend class spinlock_rtm; std::atomic< spinlock_status > state_{ spinlock_status::unlocked }; + std::minstd_rand generator_{}; public: - spinlock_ttas() noexcept = default; + spinlock_ttas() = default; spinlock_ttas( spinlock_ttas const&) = delete; spinlock_ttas & operator=( spinlock_ttas const&) = delete; void lock() noexcept { std::size_t collisions = 0 ; - std::minstd_rand generator; for (;;) { // avoid using multiple pause instructions for a delay of a specific cycle count // the delay of cpu_relax() (pause on Intel) depends on the processor family @@ -88,7 +88,7 @@ public: // linear_congruential_engine is a random number engine based on Linear congruential generator (LCG) std::uniform_int_distribution< std::size_t > distribution{ 0, static_cast< std::size_t >( 1) << (std::min)(collisions, static_cast< std::size_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) }; - const std::size_t z = distribution( generator); + const std::size_t z = distribution( generator_); ++collisions; for ( std::size_t i = 0; i < z; ++i) { // -> reduces the power consumed by the CPU diff --git a/include/boost/fiber/detail/spinlock_ttas_adaptive.hpp b/include/boost/fiber/detail/spinlock_ttas_adaptive.hpp index c2762057..b7bb65b9 100644 --- a/include/boost/fiber/detail/spinlock_ttas_adaptive.hpp +++ b/include/boost/fiber/detail/spinlock_ttas_adaptive.hpp @@ -32,16 +32,16 @@ private: std::atomic< spinlock_status > state_{ spinlock_status::unlocked }; std::atomic< std::size_t > retries_{ 0 }; + std::minstd_rand generator_{}; public: - spinlock_ttas_adaptive() noexcept = default; + spinlock_ttas_adaptive() = default; spinlock_ttas_adaptive( spinlock_ttas_adaptive const&) = delete; spinlock_ttas_adaptive & operator=( spinlock_ttas_adaptive const&) = delete; void lock() noexcept { std::size_t collisions = 0 ; - std::minstd_rand generator; for (;;) { std::size_t retries = 0; const std::size_t prev_retries = retries_.load( std::memory_order_relaxed); @@ -95,7 +95,7 @@ public: // linear_congruential_engine is a random number engine based on Linear congruential generator (LCG) std::uniform_int_distribution< std::size_t > distribution{ 0, static_cast< std::size_t >( 1) << (std::min)(collisions, static_cast< std::size_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) }; - const std::size_t z = distribution( generator); + const std::size_t z = distribution( generator_); ++collisions; for ( std::size_t i = 0; i < z; ++i) { // -> reduces the power consumed by the CPU diff --git a/include/boost/fiber/detail/spinlock_ttas_adaptive_futex.hpp b/include/boost/fiber/detail/spinlock_ttas_adaptive_futex.hpp index cce65604..f1be6bb0 100644 --- a/include/boost/fiber/detail/spinlock_ttas_adaptive_futex.hpp +++ b/include/boost/fiber/detail/spinlock_ttas_adaptive_futex.hpp @@ -31,9 +31,10 @@ private: std::atomic< std::int32_t > value_{ 0 }; std::atomic< std::int32_t > retries_{ 0 }; + std::minstd_rand generator_{}; public: - spinlock_ttas_adaptive_futex() noexcept = default; + spinlock_ttas_adaptive_futex() = default; spinlock_ttas_adaptive_futex( spinlock_ttas_adaptive_futex const&) = delete; spinlock_ttas_adaptive_futex & operator=( spinlock_ttas_adaptive_futex const&) = delete; @@ -45,7 +46,6 @@ public: static_cast< std::int32_t >( BOOST_FIBERS_SPIN_BEFORE_SLEEP0), 2 * prev_retries + 10); const std::int32_t max_sleep_retries = (std::min)( static_cast< std::int32_t >( BOOST_FIBERS_SPIN_BEFORE_YIELD), 2 * prev_retries + 10); - std::minstd_rand generator; // after max. spins or collisions suspend via futex while ( retries++ < BOOST_FIBERS_RETRY_THRESHOLD) { // avoid using multiple pause instructions for a delay of a specific cycle count @@ -92,7 +92,7 @@ public: // linear_congruential_engine is a random number engine based on Linear congruential generator (LCG) std::uniform_int_distribution< std::int32_t > distribution{ 0, static_cast< std::int32_t >( 1) << (std::min)(collisions, static_cast< std::int32_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) }; - const std::int32_t z = distribution( generator); + const std::int32_t z = distribution( generator_); ++collisions; for ( std::int32_t i = 0; i < z; ++i) { // -> reduces the power consumed by the CPU diff --git a/include/boost/fiber/detail/spinlock_ttas_futex.hpp b/include/boost/fiber/detail/spinlock_ttas_futex.hpp index f668c682..3c70b6a3 100644 --- a/include/boost/fiber/detail/spinlock_ttas_futex.hpp +++ b/include/boost/fiber/detail/spinlock_ttas_futex.hpp @@ -30,16 +30,16 @@ private: friend class spinlock_rtm; std::atomic< std::int32_t > value_{ 0 }; + std::minstd_rand generator_{}; public: - spinlock_ttas_futex() noexcept = default; + spinlock_ttas_futex() = default; spinlock_ttas_futex( spinlock_ttas_futex const&) = delete; spinlock_ttas_futex & operator=( spinlock_ttas_futex const&) = delete; void lock() noexcept { std::int32_t collisions = 0, retries = 0, expected = 0; - std::minstd_rand generator; // after max. spins or collisions suspend via futex while ( retries++ < BOOST_FIBERS_RETRY_THRESHOLD) { // avoid using multiple pause instructions for a delay of a specific cycle count @@ -86,7 +86,7 @@ public: // linear_congruential_engine is a random number engine based on Linear congruential generator (LCG) std::uniform_int_distribution< std::int32_t > distribution{ 0, static_cast< std::int32_t >( 1) << (std::min)(collisions, static_cast< std::int32_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) }; - const std::int32_t z = distribution( generator); + const std::int32_t z = distribution( generator_); ++collisions; for ( std::int32_t i = 0; i < z; ++i) { // -> reduces the power consumed by the CPU From e03405f2beadbe5d9f86dfe1183c05ef569a8f08 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Fri, 9 Jun 2017 16:38:36 +0200 Subject: [PATCH 12/15] force inlining futex functions --- include/boost/fiber/detail/futex.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/fiber/detail/futex.hpp b/include/boost/fiber/detail/futex.hpp index d383dc40..713ff3d2 100644 --- a/include/boost/fiber/detail/futex.hpp +++ b/include/boost/fiber/detail/futex.hpp @@ -26,28 +26,28 @@ namespace fibers { namespace detail { #if BOOST_OS_LINUX -inline +BOOST_FORCEINLINE int sys_futex( void * addr, std::int32_t op, std::int32_t x) { return ::syscall( SYS_futex, addr, op, x, nullptr, nullptr, 0); } -inline +BOOST_FORCEINLINE int futex_wake( std::atomic< std::int32_t > * addr) { return 0 <= sys_futex( static_cast< void * >( addr), FUTEX_WAKE_PRIVATE, 1) ? 0 : -1; } -inline +BOOST_FORCEINLINE int futex_wait( std::atomic< std::int32_t > * addr, std::int32_t x) { return 0 <= sys_futex( static_cast< void * >( addr), FUTEX_WAIT_PRIVATE, x) ? 0 : -1; } #elif BOOST_OS_WINDOWS -inline +BOOST_FORCEINLINE int futex_wake( std::atomic< std::int32_t > * addr) { ::WakeByAddressSingle( static_cast< void * >( addr) ); return 0; } -inline +BOOST_FORCEINLINE int futex_wait( std::atomic< std::int32_t > * addr, std::int32_t x) { ::WaitOnAddress( static_cast< volatile void * >( addr), & x, sizeof( x), INFINITE); return 0; From 73bf0b5d5cbd662a856744c6f7956ca02d6c53af Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Fri, 9 Jun 2017 17:16:27 +0200 Subject: [PATCH 13/15] Revert "function and args not moved into context::run_()" lets skynet_stealing_async fail (access to null pointer of context) This reverts commit 7400595d852c403e7753ccce66ca03891ac2688e. --- include/boost/fiber/context.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/boost/fiber/context.hpp b/include/boost/fiber/context.hpp index 4d645ca5..2d7be90d 100644 --- a/include/boost/fiber/context.hpp +++ b/include/boost/fiber/context.hpp @@ -418,9 +418,10 @@ private: boost::context::continuation run_( boost::context::continuation && c) noexcept { - // `noexcept` will call std::terminate() - // if an exception escapes `fn` { + // fn and tpl must be destroyed before calling terminate() + auto fn = std::move( fn_); + auto arg = std::move( arg_); c = c.resume(); context * active_ctx = active(); BOOST_ASSERT( nullptr != active_ctx); @@ -436,9 +437,9 @@ private: active_ctx->ready_ctx_ = nullptr; } #if defined(BOOST_NO_CXX17_STD_APPLY) - boost::context::detail::apply( std::move( fn_), std::move( arg_) ); + boost::context::detail::apply( std::move( fn), std::move( arg) ); #else - std::apply( std::move( fn_), std::move( arg_) ); + std::apply( std::move( fn), std::move( arg) ); #endif } // terminate context From 732e91b6342ff251e0d7ab8d6260f9ccc6eca0dd Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Sat, 10 Jun 2017 12:13:30 +0200 Subject: [PATCH 14/15] Revert "no data transferred via continuation::resume()" This reverts commit 953bcb423e0c5f776d3af9b4582b6ae83ef008f0. --- examples/asio/detail/yield.hpp | 2 +- include/boost/fiber/buffered_channel.hpp | 14 ++-- include/boost/fiber/condition_variable.hpp | 4 +- include/boost/fiber/context.hpp | 31 +++----- include/boost/fiber/detail/data.hpp | 54 +++++++++++++ include/boost/fiber/scheduler.hpp | 7 +- include/boost/fiber/type.hpp | 1 + include/boost/fiber/unbuffered_channel.hpp | 22 +++--- src/context.cpp | 89 +++++++++++----------- src/mutex.cpp | 2 +- src/recursive_mutex.cpp | 2 +- src/recursive_timed_mutex.cpp | 4 +- src/scheduler.cpp | 8 +- src/timed_mutex.cpp | 4 +- 14 files changed, 145 insertions(+), 99 deletions(-) create mode 100644 include/boost/fiber/detail/data.hpp diff --git a/examples/asio/detail/yield.hpp b/examples/asio/detail/yield.hpp index 75ad397c..8970e95b 100644 --- a/examples/asio/detail/yield.hpp +++ b/examples/asio/detail/yield.hpp @@ -49,7 +49,7 @@ struct yield_completion { if ( ! completed_) { // suspend(unique_lock) unlocks the lock in the act of // resuming another fiber - fibers::context::active()->suspend( & lk); + fibers::context::active()->suspend( lk); } } diff --git a/include/boost/fiber/buffered_channel.hpp b/include/boost/fiber/buffered_channel.hpp index 474ac260..055815f5 100644 --- a/include/boost/fiber/buffered_channel.hpp +++ b/include/boost/fiber/buffered_channel.hpp @@ -153,7 +153,7 @@ public: } else if ( is_full_() ) { active_ctx->wait_link( waiting_producers_); // suspend this producer - active_ctx->suspend( & lk); + active_ctx->suspend( lk); } else { slots_[pidx_] = value; pidx_ = (pidx_ + 1) % capacity_; @@ -178,7 +178,7 @@ public: } else if ( is_full_() ) { active_ctx->wait_link( waiting_producers_); // suspend this producer - active_ctx->suspend( & lk); + active_ctx->suspend( lk); } else { slots_[pidx_] = std::move( value); pidx_ = (pidx_ + 1) % capacity_; @@ -220,7 +220,7 @@ public: } else if ( is_full_() ) { active_ctx->wait_link( waiting_producers_); // suspend this producer - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { // relock local lk lk.lock(); // remove from waiting-queue @@ -254,7 +254,7 @@ public: } else if ( is_full_() ) { active_ctx->wait_link( waiting_producers_); // suspend this producer - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { // relock local lk lk.lock(); // remove from waiting-queue @@ -307,7 +307,7 @@ public: } else { active_ctx->wait_link( waiting_consumers_); // suspend this consumer - active_ctx->suspend( & lk); + active_ctx->suspend( lk); } } else { value = std::move( slots_[cidx_]); @@ -336,7 +336,7 @@ public: } else { active_ctx->wait_link( waiting_consumers_); // suspend this consumer - active_ctx->suspend( & lk); + active_ctx->suspend( lk); } } else { value_type value = std::move( slots_[cidx_]); @@ -373,7 +373,7 @@ public: } else { active_ctx->wait_link( waiting_consumers_); // suspend this consumer - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { // relock local lk lk.lock(); // remove from waiting-queue diff --git a/include/boost/fiber/condition_variable.hpp b/include/boost/fiber/condition_variable.hpp index 3bcc6e8d..cd0e7cb0 100644 --- a/include/boost/fiber/condition_variable.hpp +++ b/include/boost/fiber/condition_variable.hpp @@ -73,7 +73,7 @@ public: // unlock external lt lt.unlock(); // suspend this fiber - active_ctx->suspend( & lk); + active_ctx->suspend( lk); // relock external again before returning try { lt.lock(); @@ -104,7 +104,7 @@ public: // unlock external lt lt.unlock(); // suspend this fiber - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { status = cv_status::timeout; // relock local lk lk.lock(); diff --git a/include/boost/fiber/context.hpp b/include/boost/fiber/context.hpp index 2d7be90d..c9dc0e76 100644 --- a/include/boost/fiber/context.hpp +++ b/include/boost/fiber/context.hpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -185,9 +186,6 @@ private: fiber_properties * properties_{ nullptr }; std::chrono::steady_clock::time_point tp_{ (std::chrono::steady_clock::time_point::max)() }; boost::context::continuation c_{}; - context * from_ctx_{ nullptr }; - context * ready_ctx_{ nullptr }; - detail::spinlock_lock * lk_{ nullptr }; type type_; launch policy_; @@ -197,7 +195,7 @@ private: policy_{ policy } { } - void resume_() noexcept; + void resume_( detail::data_t &) noexcept; public: class id { @@ -280,11 +278,11 @@ public: } void resume() noexcept; - void resume( detail::spinlock_lock *) noexcept; + void resume( detail::spinlock_lock &) noexcept; void resume( context *) noexcept; void suspend() noexcept; - void suspend( detail::spinlock_lock *) noexcept; + void suspend( detail::spinlock_lock &) noexcept; boost::context::continuation suspend_with_cc() noexcept; boost::context::continuation terminate() noexcept; @@ -295,7 +293,7 @@ public: bool wait_until( std::chrono::steady_clock::time_point const&) noexcept; bool wait_until( std::chrono::steady_clock::time_point const&, - detail::spinlock_lock *) noexcept; + detail::spinlock_lock &) noexcept; void schedule( context *) noexcept; @@ -423,18 +421,13 @@ private: auto fn = std::move( fn_); auto arg = std::move( arg_); c = c.resume(); - context * active_ctx = active(); - BOOST_ASSERT( nullptr != active_ctx); - BOOST_ASSERT( nullptr != active_ctx->from_ctx_); - active_ctx->from_ctx_->c_ = std::move( c); - active_ctx->from_ctx_ = nullptr; - if ( nullptr != active_ctx->lk_) { - active_ctx->lk_->unlock(); - active_ctx->lk_ = nullptr; - } - if ( nullptr != active_ctx->ready_ctx_) { - active_ctx->schedule( active_ctx->ready_ctx_); - active_ctx->ready_ctx_ = nullptr; + detail::data_t * dp = c.get_data< detail::data_t * >(); + // update contiunation of calling fiber + dp->from->c_ = std::move( c); + if ( nullptr != dp->lk) { + dp->lk->unlock(); + } else if ( nullptr != dp->ctx) { + active()->schedule( dp->ctx); } #if defined(BOOST_NO_CXX17_STD_APPLY) boost::context::detail::apply( std::move( fn), std::move( arg) ); diff --git a/include/boost/fiber/detail/data.hpp b/include/boost/fiber/detail/data.hpp new file mode 100644 index 00000000..c363817a --- /dev/null +++ b/include/boost/fiber/detail/data.hpp @@ -0,0 +1,54 @@ + +// 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) + +#ifndef BOOST_FIBERS_DETAIL_DATA_H +#define BOOST_FIBERS_DETAIL_DATA_H + +#include + +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace fibers { + +class context; + +namespace detail { + +struct data_t { + spinlock_lock * lk{ nullptr }; + context * ctx{ nullptr }; + context * from; + + explicit data_t( context * from_) noexcept : + from{ from_ } { + } + + explicit data_t( spinlock_lock * lk_, + context * from_) noexcept : + lk{ lk_ }, + from{ from_ } { + } + + explicit data_t( context * ctx_, + context * from_) noexcept : + ctx{ ctx_ }, + from{ from_ } { + } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_FIBERS_DETAIL_DATA_H diff --git a/include/boost/fiber/scheduler.hpp b/include/boost/fiber/scheduler.hpp index 3fec784f..accedf03 100644 --- a/include/boost/fiber/scheduler.hpp +++ b/include/boost/fiber/scheduler.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #ifdef BOOST_HAS_ABI_HEADERS @@ -123,7 +124,7 @@ public: boost::context::continuation dispatch() noexcept; - boost::context::continuation terminate( detail::spinlock_lock *, context *) noexcept; + boost::context::continuation terminate( detail::spinlock_lock &, context *) noexcept; void yield( context *) noexcept; @@ -131,10 +132,10 @@ public: std::chrono::steady_clock::time_point const&) noexcept; bool wait_until( context *, std::chrono::steady_clock::time_point const&, - detail::spinlock_lock *) noexcept; + detail::spinlock_lock &) noexcept; void suspend() noexcept; - void suspend( detail::spinlock_lock *) noexcept; + void suspend( detail::spinlock_lock &) noexcept; bool has_ready_fibers() const noexcept; diff --git a/include/boost/fiber/type.hpp b/include/boost/fiber/type.hpp index 4d6403e7..d9ab0a94 100644 --- a/include/boost/fiber/type.hpp +++ b/include/boost/fiber/type.hpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/include/boost/fiber/unbuffered_channel.hpp b/include/boost/fiber/unbuffered_channel.hpp index f0df4029..47b7dc98 100644 --- a/include/boost/fiber/unbuffered_channel.hpp +++ b/include/boost/fiber/unbuffered_channel.hpp @@ -149,7 +149,7 @@ public: active_ctx->schedule( consumer_ctx); } // suspend till value has been consumed - active_ctx->suspend( & lk); + active_ctx->suspend( lk); // resumed, value has been consumed return channel_op_status::success; } else { @@ -162,7 +162,7 @@ public: } active_ctx->wait_link( waiting_producers_); // suspend this producer - active_ctx->suspend( & lk); + active_ctx->suspend( lk); // resumed, slot mabye free } } @@ -184,7 +184,7 @@ public: active_ctx->schedule( consumer_ctx); } // suspend till value has been consumed - active_ctx->suspend( & lk); + active_ctx->suspend( lk); // resumed, value has been consumed return channel_op_status::success; } else { @@ -197,7 +197,7 @@ public: } active_ctx->wait_link( waiting_producers_); // suspend this producer - active_ctx->suspend( & lk); + active_ctx->suspend( lk); // resumed, slot mabye free } } @@ -236,7 +236,7 @@ public: active_ctx->schedule( consumer_ctx); } // suspend this producer - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { // clear slot slot * nil_slot = nullptr, * own_slot = & s; slot_.compare_exchange_strong( own_slot, nil_slot, std::memory_order_acq_rel); @@ -255,7 +255,7 @@ public: } active_ctx->wait_link( waiting_producers_); // suspend this producer - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { // relock local lk lk.lock(); // remove from waiting-queue @@ -286,7 +286,7 @@ public: active_ctx->schedule( consumer_ctx); } // suspend this producer - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { // clear slot slot * nil_slot = nullptr, * own_slot = & s; slot_.compare_exchange_strong( own_slot, nil_slot, std::memory_order_acq_rel); @@ -305,7 +305,7 @@ public: } active_ctx->wait_link( waiting_producers_); // suspend this producer - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { // relock local lk lk.lock(); // remove from waiting-queue @@ -347,7 +347,7 @@ public: } active_ctx->wait_link( waiting_consumers_); // suspend this consumer - active_ctx->suspend( & lk); + active_ctx->suspend( lk); // resumed, slot mabye set } } @@ -385,7 +385,7 @@ public: } active_ctx->wait_link( waiting_consumers_); // suspend this consumer - active_ctx->suspend( & lk); + active_ctx->suspend( lk); // resumed, slot mabye set } } @@ -431,7 +431,7 @@ public: } active_ctx->wait_link( waiting_consumers_); // suspend this consumer - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { // relock local lk lk.lock(); // remove from waiting-queue diff --git a/src/context.cpp b/src/context.cpp index 3769144b..0c8e111a 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -32,19 +32,14 @@ private: boost::context::continuation run_( boost::context::continuation && c) noexcept { c = c.resume(); - context * active_ctx = active(); - BOOST_ASSERT( nullptr != active_ctx); - BOOST_ASSERT( nullptr != active_ctx->from_ctx_); - active_ctx->from_ctx_->c_ = std::move( c); - active_ctx->from_ctx_ = nullptr; - if ( nullptr != active_ctx->lk_) { - active_ctx->lk_->unlock(); - active_ctx->lk_ = nullptr; - } - if ( nullptr != active_ctx->ready_ctx_) { - active_ctx->schedule( active_ctx->ready_ctx_); - active_ctx->ready_ctx_ = nullptr; - } + detail::data_t * dp = c.get_data< detail::data_t * >(); + // update contiunation of calling fiber + dp->from->c_ = std::move( c); + if ( nullptr != dp->lk) { + dp->lk->unlock(); + } else if ( nullptr != dp->ctx) { + active()->schedule( dp->ctx); + } // execute scheduler::dispatch() return get_scheduler()->dispatch(); } @@ -122,24 +117,16 @@ context::reset_active() noexcept { } void -context::resume_() noexcept { - context * prev = this; - // context_initializer::active_ will point to `this` - // prev will point to previous active context - std::swap( context_initializer::active_, prev); - boost::context::continuation c = c_.resume(); - context * active_ctx = active(); - BOOST_ASSERT( nullptr != active_ctx); - BOOST_ASSERT( nullptr != active_ctx->from_ctx_); - active_ctx->from_ctx_->c_ = std::move( c); - active_ctx->from_ctx_ = nullptr; - if ( nullptr != active_ctx->lk_) { - active_ctx->lk_->unlock(); - active_ctx->lk_ = nullptr; - } - if ( nullptr != active_ctx->ready_ctx_) { - active_ctx->schedule( active_ctx->ready_ctx_); - active_ctx->ready_ctx_ = nullptr; +context::resume_( detail::data_t & d) noexcept { + boost::context::continuation c = c_.resume( & d); + detail::data_t * dp = c.get_data< detail::data_t * >(); + if ( nullptr != dp) { + dp->from->c_ = std::move( c); + if ( nullptr != dp->lk) { + dp->lk->unlock(); + } else if ( nullptr != dp->ctx) { + active()->schedule( dp->ctx); + } } } @@ -173,22 +160,32 @@ context::get_id() const noexcept { void context::resume() noexcept { - from_ctx_ = active(); - resume_(); + context * prev = this; + // context_initializer::active_ will point to `this` + // prev will point to previous active context + std::swap( context_initializer::active_, prev); + detail::data_t d{ prev }; + resume_( d); } void -context::resume( detail::spinlock_lock * lk) noexcept { - from_ctx_ = active(); - lk_ = lk; - resume_(); +context::resume( detail::spinlock_lock & lk) noexcept { + context * prev = this; + // context_initializer::active_ will point to `this` + // prev will point to previous active context + std::swap( context_initializer::active_, prev); + detail::data_t d{ & lk, prev }; + resume_( d); } void context::resume( context * ready_ctx) noexcept { - from_ctx_ = active(); - ready_ctx_ = ready_ctx; - resume_(); + context * prev = this; + // context_initializer::active_ will point to `this` + // prev will point to previous active context + std::swap( context_initializer::active_, prev); + detail::data_t d{ ready_ctx, prev }; + resume_( d); } void @@ -197,7 +194,7 @@ context::suspend() noexcept { } void -context::suspend( detail::spinlock_lock * lk) noexcept { +context::suspend( detail::spinlock_lock & lk) noexcept { get_scheduler()->suspend( lk); } @@ -214,7 +211,7 @@ context::join() { // the active context active_ctx->wait_link( wait_queue_); // suspend active context - active_ctx->get_scheduler()->suspend( & lk); + active_ctx->get_scheduler()->suspend( lk); // active context resumed BOOST_ASSERT( context::active() == active_ctx); } @@ -228,13 +225,13 @@ context::yield() noexcept { boost::context::continuation context::suspend_with_cc() noexcept { - from_ctx_ = active(); context * prev = this; // context_initializer::active_ will point to `this` // prev will point to previous active context std::swap( context_initializer::active_, prev); + detail::data_t d{ prev }; // context switch - return c_.resume(); + return c_.resume( & d); } boost::context::continuation @@ -258,7 +255,7 @@ context::terminate() noexcept { } fss_data_.clear(); // switch to another context - return get_scheduler()->terminate( & lk, this); + return get_scheduler()->terminate( lk, this); } bool @@ -270,7 +267,7 @@ context::wait_until( std::chrono::steady_clock::time_point const& tp) noexcept { bool context::wait_until( std::chrono::steady_clock::time_point const& tp, - detail::spinlock_lock * lk) noexcept { + detail::spinlock_lock & lk) noexcept { BOOST_ASSERT( nullptr != get_scheduler() ); BOOST_ASSERT( this == active() ); return get_scheduler()->wait_until( this, tp, lk); diff --git a/src/mutex.cpp b/src/mutex.cpp index 213bb15f..ad67cbd1 100644 --- a/src/mutex.cpp +++ b/src/mutex.cpp @@ -37,7 +37,7 @@ mutex::lock() { BOOST_ASSERT( ! active_ctx->wait_is_linked() ); active_ctx->wait_link( wait_queue_); // suspend this fiber - active_ctx->suspend( & lk); + active_ctx->suspend( lk); BOOST_ASSERT( ! active_ctx->wait_is_linked() ); } } diff --git a/src/recursive_mutex.cpp b/src/recursive_mutex.cpp index 67f2334a..081559d3 100644 --- a/src/recursive_mutex.cpp +++ b/src/recursive_mutex.cpp @@ -36,7 +36,7 @@ recursive_mutex::lock() { BOOST_ASSERT( ! active_ctx->wait_is_linked() ); active_ctx->wait_link( wait_queue_); // suspend this fiber - active_ctx->suspend( & lk); + active_ctx->suspend( lk); BOOST_ASSERT( ! active_ctx->wait_is_linked() ); } } diff --git a/src/recursive_timed_mutex.cpp b/src/recursive_timed_mutex.cpp index aa52f15d..cb95690a 100644 --- a/src/recursive_timed_mutex.cpp +++ b/src/recursive_timed_mutex.cpp @@ -39,7 +39,7 @@ recursive_timed_mutex::try_lock_until_( std::chrono::steady_clock::time_point co BOOST_ASSERT( ! active_ctx->wait_is_linked() ); active_ctx->wait_link( wait_queue_); // suspend this fiber until notified or timed-out - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { // remove fiber from wait-queue lk.lock(); wait_queue_.remove( * active_ctx); @@ -66,7 +66,7 @@ recursive_timed_mutex::lock() { BOOST_ASSERT( ! active_ctx->wait_is_linked() ); active_ctx->wait_link( wait_queue_); // suspend this fiber - active_ctx->suspend( & lk); + active_ctx->suspend( lk); BOOST_ASSERT( ! active_ctx->wait_is_linked() ); } } diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 8fba44b8..e6999029 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -239,7 +239,7 @@ scheduler::schedule_from_remote( context * ctx) noexcept { #endif boost::context::continuation -scheduler::terminate( detail::spinlock_lock * lk, context * ctx) noexcept { +scheduler::terminate( detail::spinlock_lock & lk, context * ctx) noexcept { BOOST_ASSERT( nullptr != ctx); BOOST_ASSERT( context::active() == ctx); BOOST_ASSERT( this == ctx->get_scheduler() ); @@ -260,7 +260,7 @@ scheduler::terminate( detail::spinlock_lock * lk, context * ctx) noexcept { // remove from the worker-queue ctx->worker_unlink(); // release lock - lk->unlock(); + lk.unlock(); // resume another fiber return algo_->pick_next()->suspend_with_cc(); } @@ -306,7 +306,7 @@ scheduler::wait_until( context * ctx, bool scheduler::wait_until( context * ctx, std::chrono::steady_clock::time_point const& sleep_tp, - detail::spinlock_lock * lk) noexcept { + detail::spinlock_lock & lk) noexcept { BOOST_ASSERT( nullptr != ctx); BOOST_ASSERT( context::active() == ctx); BOOST_ASSERT( ctx->is_context( type::worker_context) || ctx->is_context( type::main_context) ); @@ -335,7 +335,7 @@ scheduler::suspend() noexcept { } void -scheduler::suspend( detail::spinlock_lock * lk) noexcept { +scheduler::suspend( detail::spinlock_lock & lk) noexcept { // resume another context algo_->pick_next()->resume( lk); } diff --git a/src/timed_mutex.cpp b/src/timed_mutex.cpp index 2af68b90..bdb9c6a1 100644 --- a/src/timed_mutex.cpp +++ b/src/timed_mutex.cpp @@ -35,7 +35,7 @@ timed_mutex::try_lock_until_( std::chrono::steady_clock::time_point const& timeo BOOST_ASSERT( ! active_ctx->wait_is_linked() ); active_ctx->wait_link( wait_queue_); // suspend this fiber until notified or timed-out - if ( ! active_ctx->wait_until( timeout_time, & lk) ) { + if ( ! active_ctx->wait_until( timeout_time, lk) ) { // remove fiber from wait-queue lk.lock(); wait_queue_.remove( * active_ctx); @@ -62,7 +62,7 @@ timed_mutex::lock() { BOOST_ASSERT( ! active_ctx->wait_is_linked() ); active_ctx->wait_link( wait_queue_); // suspend this fiber - active_ctx->suspend( & lk); + active_ctx->suspend( lk); BOOST_ASSERT( ! active_ctx->wait_is_linked() ); } } From 0986f9d1e6e900f4936a9f56ee2f58b35047002a Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Sat, 10 Jun 2017 15:01:23 +0200 Subject: [PATCH 15/15] fix compiler warnings in unit-tests --- test/test_condition_mt_dispatch.cpp | 16 ++++++++-------- test/test_condition_mt_post.cpp | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/test/test_condition_mt_dispatch.cpp b/test/test_condition_mt_dispatch.cpp index 3862eaeb..e57fd087 100644 --- a/test/test_condition_mt_dispatch.cpp +++ b/test/test_condition_mt_dispatch.cpp @@ -28,7 +28,7 @@ typedef boost::chrono::milliseconds ms; -boost::atomic< int > value; +boost::atomic< int > value1; void wait_fn( boost::barrier & b, boost::fibers::mutex & mtx, @@ -37,7 +37,7 @@ void wait_fn( boost::barrier & b, b.wait(); std::unique_lock< boost::fibers::mutex > lk( mtx); cond.wait( lk, [&flag](){ return flag; }); - ++value; + ++value1; } void notify_one_fn( boost::barrier & b, @@ -106,11 +106,11 @@ void test_one_waiter_notify_one() { boost::barrier b( 2); bool flag = false; - value = 0; + value1 = 0; boost::fibers::mutex mtx; boost::fibers::condition_variable cond; - BOOST_CHECK( 0 == value); + BOOST_CHECK( 0 == value1); boost::thread t1(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); boost::thread t2(std::bind( fn2, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); @@ -118,7 +118,7 @@ void test_one_waiter_notify_one() { t1.join(); t2.join(); - BOOST_CHECK( 1 == value); + BOOST_CHECK( 1 == value1); } } @@ -127,11 +127,11 @@ void test_two_waiter_notify_all() { boost::barrier b( 3); bool flag = false; - value = 0; + value1 = 0; boost::fibers::mutex mtx; boost::fibers::condition_variable cond; - BOOST_CHECK( 0 == value); + BOOST_CHECK( 0 == value1); boost::thread t1(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); boost::thread t2(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); @@ -141,7 +141,7 @@ void test_two_waiter_notify_all() { t2.join(); t3.join(); - BOOST_CHECK( 2 == value); + BOOST_CHECK( 2 == value1); } } diff --git a/test/test_condition_mt_post.cpp b/test/test_condition_mt_post.cpp index b2387d13..b85647eb 100644 --- a/test/test_condition_mt_post.cpp +++ b/test/test_condition_mt_post.cpp @@ -28,7 +28,7 @@ typedef boost::chrono::milliseconds ms; -boost::atomic< int > value; +boost::atomic< int > value1; void wait_fn( boost::barrier & b, boost::fibers::mutex & mtx, @@ -37,7 +37,7 @@ void wait_fn( boost::barrier & b, b.wait(); std::unique_lock< boost::fibers::mutex > lk( mtx); cond.wait( lk, [&flag](){ return flag; }); - ++value; + ++value1; } void notify_one_fn( boost::barrier & b, @@ -106,11 +106,11 @@ void test_one_waiter_notify_one() { boost::barrier b( 2); bool flag = false; - value = 0; + value1 = 0; boost::fibers::mutex mtx; boost::fibers::condition_variable cond; - BOOST_CHECK( 0 == value); + BOOST_CHECK( 0 == value1); boost::thread t1(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); boost::thread t2(std::bind( fn2, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); @@ -118,7 +118,7 @@ void test_one_waiter_notify_one() { t1.join(); t2.join(); - BOOST_CHECK( 1 == value); + BOOST_CHECK( 1 == value1); } } @@ -127,11 +127,11 @@ void test_two_waiter_notify_all() { boost::barrier b( 3); bool flag = false; - value = 0; + value1 = 0; boost::fibers::mutex mtx; boost::fibers::condition_variable cond; - BOOST_CHECK( 0 == value); + BOOST_CHECK( 0 == value1); boost::thread t1(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); boost::thread t2(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); @@ -141,7 +141,7 @@ void test_two_waiter_notify_all() { t2.join(); t3.join(); - BOOST_CHECK( 2 == value); + BOOST_CHECK( 2 == value1); } }