diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp index 59bbcb0e..56e9bb3f 100644 --- a/include/boost/fiber/all.hpp +++ b/include/boost/fiber/all.hpp @@ -7,9 +7,13 @@ #ifndef BOOST_FIBERS_H #define BOOST_FIBERS_H +#include +#include #include #include +#include #include +#include #include #endif // BOOST_FIBERS_H diff --git a/include/boost/fiber/context.hpp b/include/boost/fiber/context.hpp index 1fffb56d..0b79be36 100644 --- a/include/boost/fiber/context.hpp +++ b/include/boost/fiber/context.hpp @@ -236,6 +236,8 @@ public: void join() noexcept; + void yield() noexcept; + bool is_main_context() const noexcept { return 0 != ( flags_ & flag_main_context); } diff --git a/include/boost/fiber/operations.hpp b/include/boost/fiber/operations.hpp new file mode 100644 index 00000000..8e625677 --- /dev/null +++ b/include/boost/fiber/operations.hpp @@ -0,0 +1,37 @@ +// 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_THIS_FIBER_OPERATIONS_H +#define BOOST_THIS_FIBER_OPERATIONS_H + +#include + +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace this_fiber { + +inline +fibers::fiber::id get_id() noexcept { + return fibers::context::active()->get_id(); +} + +inline +void yield() noexcept { + fibers::context::active()->yield(); +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_THIS_FIBER_OPERATIONS_H diff --git a/include/boost/fiber/scheduler.hpp b/include/boost/fiber/scheduler.hpp index 07b3a553..fd8cc849 100644 --- a/include/boost/fiber/scheduler.hpp +++ b/include/boost/fiber/scheduler.hpp @@ -65,6 +65,8 @@ public: void set_terminated( context *) noexcept; + void yield( context *) noexcept; + void re_schedule( context *) noexcept; }; diff --git a/src/context.cpp b/src/context.cpp index 08318ef6..82be3f48 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -143,6 +143,14 @@ context::join() noexcept { } } +void +context::yield() noexcept { + // get active context + context * active_ctx = context::active(); + // yield active context + scheduler_->yield( active_ctx); +} + bool context::wait_is_linked() { return wait_hook_.is_linked(); diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 84384425..e9f0d80f 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -107,8 +107,8 @@ scheduler::dispatch() { context * ctx( nullptr); // loop till we get next ready context while ( nullptr == ( ctx = get_next_() ) ) { - // FIXME: move context' from remote ready-queue to local ready-queue - // move ready context' from sleep-queue to ready-queue + // TODO: move context' from remote ready-queue to local ready-queue + // move ready context' from sleep-queue to ready-queue // no ready context, wait till signaled ready_queue_ev_.reset( (std::chrono::steady_clock::time_point::max)()); @@ -118,9 +118,9 @@ scheduler::dispatch() { auto active_ctx = context::active(); ready_queue_.push_back( * active_ctx); resume_( active_ctx, ctx); - // FIXME: pump external event-loop like boost::asio::io_service - // react on external interrupt signals - // react on requestsin work sahring scenario + // TODO: pump external event-loop like boost::asio::io_service + // react on external interrupt signals + // react on requestsin work sahring scenario // no ready context, wait till signaled } // interrupt all context' in ready- and sleep-queue @@ -134,9 +134,9 @@ scheduler::set_ready( context * ctx) noexcept { BOOST_ASSERT( ! ctx->ready_is_linked() ); BOOST_ASSERT( ! ctx->is_terminated() ); BOOST_ASSERT( ! ctx->wait_is_linked() ); - // set the scheduler for new fiber context + // set the scheduler for new context ctx->set_scheduler( this); - // push new fiber context to redy-queue + // push new context to ready-queue ready_queue_.push_back( * ctx); } @@ -149,6 +149,17 @@ scheduler::set_terminated( context * ctx) noexcept { terminated_queue_.push_back( * ctx); } +void +scheduler::yield( context * active_ctx) noexcept { + BOOST_ASSERT( nullptr != active_ctx); + BOOST_ASSERT( ! active_ctx->is_terminated() ); + BOOST_ASSERT( ! active_ctx->ready_is_linked() ); + BOOST_ASSERT( ! active_ctx->wait_is_linked() ); + // push active context to ready-queue + ready_queue_.push_back( * active_ctx); + resume_( active_ctx, get_next_() ); +} + void scheduler::re_schedule( context * active_ctx) noexcept { BOOST_ASSERT( nullptr != active_ctx); diff --git a/test/test_fiber.cpp b/test/test_fiber.cpp index 46ddf424..272a9f67 100644 --- a/test/test_fiber.cpp +++ b/test/test_fiber.cpp @@ -24,6 +24,20 @@ void fn2( int i, std::string const& s) { value2 = s; } +void fn3( int & i) { + i = 1; + boost::this_fiber::yield(); + i = 1; + boost::this_fiber::yield(); + i = 2; + boost::this_fiber::yield(); + i = 3; + boost::this_fiber::yield(); + i = 5; + boost::this_fiber::yield(); + i = 8; +} + struct X { int value; @@ -179,6 +193,20 @@ void test_id() { f3.join(); } +void test_yield() { + int v1 = 0, v2 = 0; + BOOST_CHECK_EQUAL( 0, v1); + BOOST_CHECK_EQUAL( 0, v2); + boost::fibers::fiber f1( fn3, std::ref( v1) ); + boost::fibers::fiber f2( fn3, std::ref( v2) ); + f1.join(); + f2.join(); + BOOST_CHECK( ! f1); + BOOST_CHECK( ! f2); + BOOST_CHECK_EQUAL( 8, v1); + BOOST_CHECK_EQUAL( 8, v2); +} + boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { boost::unit_test::test_suite * test = BOOST_TEST_SUITE("Boost.Fiber: fiber test suite"); @@ -189,7 +217,8 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { test->add( BOOST_TEST_CASE( & test_join_copyable) ); test->add( BOOST_TEST_CASE( & test_join_moveable) ); test->add( BOOST_TEST_CASE( & test_move_fiber) ); - test->add( BOOST_TEST_CASE( & test_id) ); + test->add( BOOST_TEST_CASE( & test_move_fiber) ); + test->add( BOOST_TEST_CASE( & test_yield) ); return test; }