Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r57673 - in sandbox/fiber: boost/fiber boost/fiber/detail libs/fiber/examples libs/fiber/src libs/fiber/test
From: oliver.kowalke_at_[hidden]
Date: 2009-11-15 03:18:21


Author: olli
Date: 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
New Revision: 57673
URL: http://svn.boost.org/trac/boost/changeset/57673

Log:
- join() op. + unut test and example added

Added:
   sandbox/fiber/libs/fiber/examples/join.cpp (contents, props changed)
   sandbox/fiber/libs/fiber/test/test_join.cpp (contents, props changed)
Text files modified:
   sandbox/fiber/boost/fiber/bounded_fifo.hpp | 116 +++++++++++++++++++-------------------
   sandbox/fiber/boost/fiber/detail/scheduler_impl.hpp | 30 +++++++--
   sandbox/fiber/boost/fiber/fiber.hpp | 2
   sandbox/fiber/boost/fiber/scheduler.hpp | 2
   sandbox/fiber/boost/fiber/unbounded_fifo.hpp | 50 ++++++++--------
   sandbox/fiber/libs/fiber/examples/Jamfile.v2 | 1
   sandbox/fiber/libs/fiber/src/fiber.cpp | 4 +
   sandbox/fiber/libs/fiber/src/scheduler.cpp | 7 ++
   sandbox/fiber/libs/fiber/src/scheduler_impl.cpp | 119 +++++++++++++++++++++++++++------------
   sandbox/fiber/libs/fiber/test/Jamfile.v2 | 1
   10 files changed, 204 insertions(+), 128 deletions(-)

Modified: sandbox/fiber/boost/fiber/bounded_fifo.hpp
==============================================================================
--- sandbox/fiber/boost/fiber/bounded_fifo.hpp (original)
+++ sandbox/fiber/boost/fiber/bounded_fifo.hpp 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -187,30 +187,30 @@
                 not_empty_cond_.notify_one();
         }
 
- void put(
- T const& t,
- posix_time::time_duration const& rel_time)
- {
- typename node::sptr_t new_node( new node);
- {
- mutex::scoped_lock lk( tail_mtx_);
-
- if ( full_() )
- {
- while ( active_() && full_() )
- if ( ! not_full_cond_.timed_wait( lk, rel_time) )
- throw std::runtime_error("timed out");
- }
- if ( ! active_() )
- throw std::runtime_error("queue is not active");
-
- tail_->va = t;
- tail_->next = new_node;
- tail_ = new_node;
- detail::atomic_fetch_add( & count_, 1);
- }
- not_empty_cond_.notify_one();
- }
+// void put(
+// T const& t,
+// posix_time::time_duration const& rel_time)
+// {
+// typename node::sptr_t new_node( new node);
+// {
+// mutex::scoped_lock lk( tail_mtx_);
+//
+// if ( full_() )
+// {
+// while ( active_() && full_() )
+// if ( ! not_full_cond_.timed_wait( lk, rel_time) )
+// throw std::runtime_error("timed out");
+// }
+// if ( ! active_() )
+// throw std::runtime_error("queue is not active");
+//
+// tail_->va = t;
+// tail_->next = new_node;
+// tail_ = new_node;
+// detail::atomic_fetch_add( & count_, 1);
+// }
+// not_empty_cond_.notify_one();
+// }
 
         bool take( value_type & va)
         {
@@ -244,40 +244,40 @@
                 return va;
         }
 
- bool take(
- value_type & va,
- posix_time::time_duration const& rel_time)
- {
- mutex::scoped_lock lk( head_mtx_);
- bool empty = empty_();
- if ( ! active_() && empty)
- return false;
- if ( empty)
- {
- try
- {
- while ( active_() && empty_() )
- if ( ! not_empty_cond_.timed_wait( lk, rel_time) )
- return false;
- }
- catch ( fiber_interrupted const&)
- { return false; }
- }
- if ( ! active_() && empty_() )
- return false;
- swap( va, head_->va);
- pop_head_();
- if ( size_() <= lwm_)
- {
- if ( lwm_ == hwm_)
- not_full_cond_.notify_one();
- else
- // more than one producer could be waiting
- // for submiting an action object
- not_full_cond_.notify_all();
- }
- return va;
- }
+// bool take(
+// value_type & va,
+// posix_time::time_duration const& rel_time)
+// {
+// mutex::scoped_lock lk( head_mtx_);
+// bool empty = empty_();
+// if ( ! active_() && empty)
+// return false;
+// if ( empty)
+// {
+// try
+// {
+// while ( active_() && empty_() )
+// if ( ! not_empty_cond_.timed_wait( lk, rel_time) )
+// return false;
+// }
+// catch ( fiber_interrupted const&)
+// { return false; }
+// }
+// if ( ! active_() && empty_() )
+// return false;
+// swap( va, head_->va);
+// pop_head_();
+// if ( size_() <= lwm_)
+// {
+// if ( lwm_ == hwm_)
+// not_full_cond_.notify_one();
+// else
+// // more than one producer could be waiting
+// // for submiting an action object
+// not_full_cond_.notify_all();
+// }
+// return va;
+// }
 
         bool try_take( value_type & va)
         {

Modified: sandbox/fiber/boost/fiber/detail/scheduler_impl.hpp
==============================================================================
--- sandbox/fiber/boost/fiber/detail/scheduler_impl.hpp (original)
+++ sandbox/fiber/boost/fiber/detail/scheduler_impl.hpp 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -26,13 +26,27 @@
 class BOOST_FIBER_DECL scheduler_impl : private noncopyable
 {
 private:
- typedef std::map< fiber::id, fiber > container;
- typedef std::list< fiber::id > runnable_queue;
- typedef std::queue< fiber::id > terminated_queue;
-
- fiber master_;
- fiber::id f_id_;
- container fibers_;
+ struct schedulable
+ {
+ fiber f;
+ std::list< fiber::id > waiting;
+
+ schedulable() :
+ f(), waiting()
+ {}
+
+ schedulable( fiber f_) :
+ f( f_), waiting()
+ {}
+ };
+
+ typedef std::map< fiber::id, schedulable > container;
+ typedef std::list< fiber::id > runnable_queue;
+ typedef std::queue< fiber::id > terminated_queue;
+
+ fiber master_;
+ fiber::id f_id_;
+ container fibers_;
         runnable_queue runnable_fibers_;
         terminated_queue terminated_fibers_;
 
@@ -61,6 +75,8 @@
 
         void re_schedule( fiber::id const&);
 
+ void join( fiber::id const&);
+
         bool run();
 
         bool empty();

Modified: sandbox/fiber/boost/fiber/fiber.hpp
==============================================================================
--- sandbox/fiber/boost/fiber/fiber.hpp (original)
+++ sandbox/fiber/boost/fiber/fiber.hpp 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -197,6 +197,8 @@
         void suspend();
 
         void resume();
+
+ void join();
 };
 
 class fiber::id

Modified: sandbox/fiber/boost/fiber/scheduler.hpp
==============================================================================
--- sandbox/fiber/boost/fiber/scheduler.hpp (original)
+++ sandbox/fiber/boost/fiber/scheduler.hpp 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -75,6 +75,8 @@
 
         static void re_schedule( fiber::id const&);
 
+ static void join( fiber::id const&);
+
         detail::scheduler_impl * access_();
 
 public:

Modified: sandbox/fiber/boost/fiber/unbounded_fifo.hpp
==============================================================================
--- sandbox/fiber/boost/fiber/unbounded_fifo.hpp (original)
+++ sandbox/fiber/boost/fiber/unbounded_fifo.hpp 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -143,31 +143,31 @@
                 return va;
         }
 
- bool take(
- value_type & va,
- posix_time::time_duration const& rel_time)
- {
- mutex::scoped_lock lk( head_mtx_);
- bool empty = empty_();
- if ( ! active_() && empty)
- return false;
- if ( empty)
- {
- try
- {
- while ( active_() && empty_() )
- if ( ! not_empty_cond_.timed_wait( lk, rel_time) )
- return false;
- }
- catch ( fiber_interrupted const&)
- { return false; }
- }
- if ( ! active_() && empty_() )
- return false;
- swap( va, head_->va);
- pop_head_();
- return va;
- }
+// bool take(
+// value_type & va,
+// posix_time::time_duration const& rel_time)
+// {
+// mutex::scoped_lock lk( head_mtx_);
+// bool empty = empty_();
+// if ( ! active_() && empty)
+// return false;
+// if ( empty)
+// {
+// try
+// {
+// while ( active_() && empty_() )
+// if ( ! not_empty_cond_.timed_wait( lk, rel_time) )
+// return false;
+// }
+// catch ( fiber_interrupted const&)
+// { return false; }
+// }
+// if ( ! active_() && empty_() )
+// return false;
+// swap( va, head_->va);
+// pop_head_();
+// return va;
+// }
 
         bool try_take( value_type & va)
         {

Modified: sandbox/fiber/libs/fiber/examples/Jamfile.v2
==============================================================================
--- sandbox/fiber/libs/fiber/examples/Jamfile.v2 (original)
+++ sandbox/fiber/libs/fiber/examples/Jamfile.v2 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -24,6 +24,7 @@
     ;
 
 exe suspend : suspend.cpp ;
+exe join : join.cpp ;
 exe cancel : cancel.cpp ;
 exe simple : simple.cpp ;
 exe simple_mt : simple_mt.cpp ;

Added: sandbox/fiber/libs/fiber/examples/join.cpp
==============================================================================
--- (empty file)
+++ sandbox/fiber/libs/fiber/examples/join.cpp 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -0,0 +1,71 @@
+#include <cstdlib>
+#include <iostream>
+#include <string>
+
+#include <boost/bind.hpp>
+#include <boost/system/system_error.hpp>
+
+#include <boost/fiber.hpp>
+
+int value1 = 0;
+int value2 = 0;
+
+void fn_1()
+{
+ for ( int i = 0; i < 5; ++i)
+ {
+ ++value1;
+ std::cout << "fn_1() increment value1 " << value1 << std::endl;
+ boost::this_fiber::yield();
+ }
+}
+
+void fn_2( boost::fiber f)
+{
+ for ( int i = 0; i < 5; ++i)
+ {
+ ++value2;
+ std::cout << "fn_2() increment value2 " << value2 << std::endl;
+ if ( i == 1)
+ {
+ std::cout << "fn_2() join fiber " << f.get_id() << std::endl;
+ f.join();
+ std::cout << "fn_2() fiber " << f.get_id() << " joined" << std::endl;
+ }
+ boost::this_fiber::yield();
+ }
+}
+
+int main()
+{
+ try
+ {
+ boost::fibers::scheduler sched;
+
+ boost::fiber f( fn_1);
+ sched.submit_fiber( f);
+ sched.make_fiber( fn_2, f);
+
+ std::cout << "start" << std::endl;
+ std::cout << "fiber to be joined " << f.get_id() << std::endl;
+
+ for (;;)
+ {
+ while ( sched.run() );
+ if ( sched.empty() ) break;
+ }
+
+ std::cout << "finish: value1 == " << value1 << ", value2 == " << value2 << std::endl;
+
+ return EXIT_SUCCESS;
+ }
+ catch ( boost::system::system_error const& e)
+ { std::cerr << "system_error: " << e.code().value() << std::endl; }
+ catch ( boost::fibers::scheduler_error const& e)
+ { std::cerr << "scheduler_error: " << e.what() << std::endl; }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}

Modified: sandbox/fiber/libs/fiber/src/fiber.cpp
==============================================================================
--- sandbox/fiber/libs/fiber/src/fiber.cpp (original)
+++ sandbox/fiber/libs/fiber/src/fiber.cpp 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -135,6 +135,10 @@
 fiber::resume()
 { scheduler::resume_fiber( get_id() ); }
 
+void
+fiber::join()
+{ scheduler::join( get_id() ); }
+
 }}
 
 #include <boost/config/abi_suffix.hpp>

Modified: sandbox/fiber/libs/fiber/src/scheduler.cpp
==============================================================================
--- sandbox/fiber/libs/fiber/src/scheduler.cpp (original)
+++ sandbox/fiber/libs/fiber/src/scheduler.cpp 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -101,6 +101,13 @@
         impl->re_schedule( f_id);
 }
 
+void
+scheduler::join( fiber::id const& f_id)
+{
+ detail::scheduler_impl * impl( impl_.get() );
+ impl->join( f_id);
+}
+
 detail::scheduler_impl *
 scheduler::access_()
 {

Modified: sandbox/fiber/libs/fiber/src/scheduler_impl.cpp
==============================================================================
--- sandbox/fiber/libs/fiber/src/scheduler_impl.cpp (original)
+++ sandbox/fiber/libs/fiber/src/scheduler_impl.cpp 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include <boost/assert.hpp>
+#include <boost/foreach.hpp>
 
 #include <boost/fiber/detail/fiber_info.hpp>
 #include <boost/fiber/detail/move.hpp>
@@ -56,12 +57,13 @@
 scheduler_impl::add_fiber( fiber f)
 {
         if ( ! f) throw fiber_moved();
+
         fiber::id id( f.get_id() );
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
         BOOST_ASSERT( STATE_NOT_STARTED == f.info_->state);
         f.info_->state = STATE_READY;
- std::pair< std::map< fiber::id, fiber >::iterator, bool > result(
- fibers_.insert( std::make_pair( id, f) ) );
+ std::pair< std::map< fiber::id, schedulable >::iterator, bool > result(
+ fibers_.insert( std::make_pair( id, schedulable( f) ) ) );
         if ( ! result.second) throw scheduler_error("inserting fiber failed");
         runnable_fibers_.push_back( result.first->first);
 }
@@ -73,30 +75,50 @@
 void
 scheduler_impl::yield_active_fiber()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( fibers_[f_id_].info_->state) );
- BOOST_ASSERT( STATE_RUNNING == fibers_[f_id_].info_->state);
- fibers_[f_id_].info_->state = STATE_READY;
+ BOOST_ASSERT( ! HAS_STATE_MASTER( fibers_[f_id_].f.info_->state) );
+ BOOST_ASSERT( STATE_RUNNING == fibers_[f_id_].f.info_->state);
+
+ fibers_[f_id_].f.info_->state = STATE_READY;
+
         runnable_fibers_.push_back( f_id_);
- fibers_[f_id_].switch_to_( master_);
+ fibers_[f_id_].f.switch_to_( master_);
 }
 
 void
 scheduler_impl::cancel_active_fiber()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( fibers_[f_id_].info_->state) );
- BOOST_ASSERT( STATE_RUNNING == fibers_[f_id_].info_->state);
- fibers_[f_id_].info_->state = STATE_TERMINATED;
+ BOOST_ASSERT( ! HAS_STATE_MASTER( fibers_[f_id_].f.info_->state) );
+ BOOST_ASSERT( STATE_RUNNING == fibers_[f_id_].f.info_->state);
+
+ fibers_[f_id_].f.info_->state = STATE_TERMINATED;
+
         terminated_fibers_.push( f_id_);
- fibers_[f_id_].switch_to_( master_);
+
+ BOOST_FOREACH( fiber::id f_id__, fibers_[f_id_].waiting)
+ {
+ fiber f__( fibers_[f_id__].f);
+ BOOST_ASSERT( HAS_STATE_WAITING( f__.info_->state) );
+ f__.info_->state &= ~STATE_WAITING;
+ if ( ( HAS_STATE_READY( f__.info_->state) || HAS_STATE_RUNNING( f__.info_->state) )
+ && ! HAS_STATE_SUSPENDED( f__.info_->state) )
+ {
+ f__.info_->state = STATE_READY;
+ runnable_fibers_.push_back( f__.get_id() );
+ }
+ }
+ fibers_[f_id_].waiting.clear();
+
+ fibers_[f_id_].f.switch_to_( master_);
 }
 
 void
 scheduler_impl::suspend_active_fiber()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( fibers_[f_id_].info_->state) );
- BOOST_ASSERT( STATE_RUNNING == fibers_[f_id_].info_->state);
- fibers_[f_id_].info_->state |= STATE_SUSPENDED;
- fibers_[f_id_].switch_to_( master_);
+ BOOST_ASSERT( ! HAS_STATE_MASTER( fibers_[f_id_].f.info_->state) );
+ BOOST_ASSERT( STATE_RUNNING == fibers_[f_id_].f.info_->state);
+
+ fibers_[f_id_].f.info_->state |= STATE_SUSPENDED;
+ fibers_[f_id_].f.switch_to_( master_);
 }
 
 void
@@ -104,7 +126,7 @@
 {
         container::iterator i = fibers_.find( f_id);
         if ( i == fibers_.end() ) return;
- fiber f( i->second);
+ fiber f( i->second.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
         
@@ -112,6 +134,20 @@
              HAS_STATE_NOT_STARTED( f.info_->state) )
                 return;
 
+ BOOST_FOREACH( fiber::id f_id__, fibers_[f_id].waiting)
+ {
+ fiber f__( fibers_[f_id__].f);
+ BOOST_ASSERT( HAS_STATE_WAITING( f__.info_->state) );
+ f__.info_->state &= ~STATE_WAITING;
+ if ( ( HAS_STATE_READY( f__.info_->state) || HAS_STATE_RUNNING( f__.info_->state) )
+ && ! HAS_STATE_SUSPENDED( f__.info_->state) )
+ {
+ f__.info_->state = STATE_READY;
+ runnable_fibers_.push_back( f__.get_id() );
+ }
+ }
+ fibers_[f_id].waiting.clear();
+
         if ( HAS_STATE_READY( f.info_->state) )
         {
                 f.info_->state = STATE_TERMINATED;
@@ -140,7 +176,7 @@
 {
         container::iterator i = fibers_.find( f_id);
         if ( i == fibers_.end() ) return;
- fiber f( i->second);
+ fiber f( i->second.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
         
@@ -160,10 +196,7 @@
                 f.switch_to_( master_);
         }
         else if ( HAS_STATE_WAITING( f.info_->state) )
- {
                 f.info_->state |= STATE_SUSPENDED;
- // TODO: remove from waiting-queue
- }
         else
                 BOOST_ASSERT( ! "should never reached");
 }
@@ -173,25 +206,18 @@
 {
         container::iterator i = fibers_.find( f_id);
         if ( i == fibers_.end() ) return;
- fiber f( i->second);
+ fiber f( i->second.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
 
         if ( HAS_STATE_SUSPENDED( f.info_->state) )
         {
                 f.info_->state &= ~STATE_SUSPENDED;
- switch ( f.info_->state)
+ if ( ( HAS_STATE_READY( f.info_->state) || HAS_STATE_RUNNING( f.info_->state) )
+ && ! HAS_STATE_WAITING( f.info_->state) )
                 {
- case STATE_READY:
- case STATE_RUNNING:
                         f.info_->state = STATE_READY;
                         runnable_fibers_.push_back( f.get_id() );
- break;
- case STATE_WAITING:
- // TODO: put it into the waiting-queue
- break;
- default:
- BOOST_ASSERT( ! "should never reached");
                 }
         }
 }
@@ -201,7 +227,7 @@
 {
         container::iterator i = fibers_.find( f_id);
         if ( i == fibers_.end() ) throw scheduler_error("fiber not found");
- fiber f( i->second);
+ fiber f( i->second.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
 
@@ -213,7 +239,7 @@
 {
         container::iterator i = fibers_.find( f_id);
         if ( i == fibers_.end() ) throw scheduler_error("fiber not found");
- fiber f( i->second);
+ fiber f( i->second.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
 
@@ -226,7 +252,7 @@
 {
         container::iterator i = fibers_.find( f_id);
         if ( i == fibers_.end() ) return;
- fiber f( i->second);
+ fiber f( i->second.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
 
@@ -234,24 +260,41 @@
         // runnable_fibers + re-insert
 }
 
+void
+scheduler_impl::join( fiber::id const& f_id)
+{
+ container::iterator i = fibers_.find( f_id);
+ if ( i == fibers_.end() ) return;
+ fiber f( i->second.f);
+ BOOST_ASSERT( f);
+ BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
+
+ fibers_[f_id].waiting.push_back( f_id_);
+ fibers_[f_id_].f.info_->state |= STATE_WAITING;
+ fibers_[f_id_].f.switch_to_( master_);
+}
+
 bool
 scheduler_impl::run()
 {
         bool result( false);
         if ( ! runnable_fibers_.empty() )
         {
- f_id_ = runnable_fibers_.front();
- BOOST_ASSERT( fibers_[f_id_].info_->state == STATE_READY);
- fibers_[f_id_].info_->state = STATE_RUNNING;
- master_.switch_to_( fibers_[f_id_]);
+ fiber f( fibers_[runnable_fibers_.front()].f);
+ f_id_ = f.get_id();
+ BOOST_ASSERT( f.info_->state == STATE_READY);
+ f.info_->state = STATE_RUNNING;
+ master_.switch_to_( f);
                 runnable_fibers_.pop_front();
                 result = true;
         }
         while ( ! terminated_fibers_.empty() )
         {
- BOOST_ASSERT( STATE_TERMINATED == fibers_[terminated_fibers_.front()].info_->state);
- fibers_.erase( terminated_fibers_.front() );
+ fiber f( fibers_[terminated_fibers_.front()].f);
                 terminated_fibers_.pop();
+ BOOST_ASSERT( STATE_TERMINATED == f.info_->state);
+ BOOST_ASSERT( fibers_[f.get_id()].waiting.empty() );
+ fibers_.erase( f.get_id() );
                 result = true;
         }
         return result;

Modified: sandbox/fiber/libs/fiber/test/Jamfile.v2
==============================================================================
--- sandbox/fiber/libs/fiber/test/Jamfile.v2 (original)
+++ sandbox/fiber/libs/fiber/test/Jamfile.v2 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -31,6 +31,7 @@
     [ fiber-test test_cancel ]
     [ fiber-test test_suspended ]
     [ fiber-test test_priority ]
+ [ fiber-test test_join ]
     [ fiber-test test_mutex ]
     [ fiber-test test_auto_reset_event ]
     [ fiber-test test_manual_reset_event ]

Added: sandbox/fiber/libs/fiber/test/test_join.cpp
==============================================================================
--- (empty file)
+++ sandbox/fiber/libs/fiber/test/test_join.cpp 2009-11-15 03:18:19 EST (Sun, 15 Nov 2009)
@@ -0,0 +1,300 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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)
+
+#include <sstream>
+#include <string>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/utility.hpp>
+
+#include <boost/fiber.hpp>
+
+int value1 = 0;
+int value2 = 0;
+int value3 = 0;
+
+void fn_1()
+{
+ for ( int i = 0; i < 5; ++i)
+ {
+ ++value1;
+ boost::this_fiber::yield();
+ }
+}
+
+void fn_2( boost::fiber f)
+{
+ for ( int i = 0; i < 5; ++i)
+ {
+ ++value2;
+ if ( i == 1) f.join();
+ boost::this_fiber::yield();
+ }
+}
+
+void fn_3( boost::fiber f)
+{
+ for ( int i = 0; i < 5; ++i)
+ {
+ ++value3;
+ if ( i == 3) f.cancel();
+ boost::this_fiber::yield();
+ }
+}
+
+void test_case_1()
+{
+ value1 = 0;
+ value2 = 0;
+
+ boost::fibers::scheduler sched;
+
+ boost::fiber f( fn_1);
+ sched.submit_fiber( f);
+ sched.make_fiber( fn_2, f);
+
+ BOOST_CHECK_EQUAL( 0, value1);
+ BOOST_CHECK_EQUAL( 0, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 1, value1);
+ BOOST_CHECK_EQUAL( 0, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 1, value1);
+ BOOST_CHECK_EQUAL( 1, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 2, value1);
+ BOOST_CHECK_EQUAL( 1, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 2, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 3, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 5, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
+ BOOST_CHECK_EQUAL( 5, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
+ BOOST_CHECK_EQUAL( 5, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
+ BOOST_CHECK_EQUAL( 5, value1);
+ BOOST_CHECK_EQUAL( 3, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
+ BOOST_CHECK_EQUAL( 5, value1);
+ BOOST_CHECK_EQUAL( 4, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
+ BOOST_CHECK_EQUAL( 5, value1);
+ BOOST_CHECK_EQUAL( 5, value2);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 0), sched.size() );
+ BOOST_CHECK_EQUAL( 5, value1);
+ BOOST_CHECK_EQUAL( 5, value2);
+
+ BOOST_CHECK( ! sched.run() );
+ BOOST_CHECK( sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 0), sched.size() );
+ BOOST_CHECK_EQUAL( 5, value1);
+ BOOST_CHECK_EQUAL( 5, value2);
+}
+
+void test_case_2()
+{
+ value1 = 0;
+ value2 = 0;
+ value3 = 0;
+
+ boost::fibers::scheduler sched;
+
+ boost::fiber f( fn_1);
+ sched.submit_fiber( f);
+ sched.make_fiber( fn_2, f);
+ sched.make_fiber( fn_3, f);
+
+ BOOST_CHECK_EQUAL( 0, value1);
+ BOOST_CHECK_EQUAL( 0, value2);
+ BOOST_CHECK_EQUAL( 0, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 3), sched.size() );
+ BOOST_CHECK_EQUAL( 1, value1);
+ BOOST_CHECK_EQUAL( 0, value2);
+ BOOST_CHECK_EQUAL( 0, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 3), sched.size() );
+ BOOST_CHECK_EQUAL( 1, value1);
+ BOOST_CHECK_EQUAL( 1, value2);
+ BOOST_CHECK_EQUAL( 0, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 3), sched.size() );
+ BOOST_CHECK_EQUAL( 1, value1);
+ BOOST_CHECK_EQUAL( 1, value2);
+ BOOST_CHECK_EQUAL( 1, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 3), sched.size() );
+ BOOST_CHECK_EQUAL( 2, value1);
+ BOOST_CHECK_EQUAL( 1, value2);
+ BOOST_CHECK_EQUAL( 1, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 3), sched.size() );
+ BOOST_CHECK_EQUAL( 2, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+ BOOST_CHECK_EQUAL( 1, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 3), sched.size() );
+ BOOST_CHECK_EQUAL( 2, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+ BOOST_CHECK_EQUAL( 2, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 3), sched.size() );
+ BOOST_CHECK_EQUAL( 3, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+ BOOST_CHECK_EQUAL( 2, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 3), sched.size() );
+ BOOST_CHECK_EQUAL( 3, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+ BOOST_CHECK_EQUAL( 3, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 3), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+ BOOST_CHECK_EQUAL( 3, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+ BOOST_CHECK_EQUAL( 4, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+ BOOST_CHECK_EQUAL( 4, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
+ BOOST_CHECK_EQUAL( 5, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 3, value2);
+ BOOST_CHECK_EQUAL( 5, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 3, value2);
+ BOOST_CHECK_EQUAL( 5, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 4, value2);
+ BOOST_CHECK_EQUAL( 5, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 5, value2);
+ BOOST_CHECK_EQUAL( 5, value3);
+
+ BOOST_CHECK( sched.run() );
+ BOOST_CHECK( sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 0), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 5, value2);
+ BOOST_CHECK_EQUAL( 5, value3);
+
+ BOOST_CHECK( ! sched.run() );
+ BOOST_CHECK( sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 0), sched.size() );
+ BOOST_CHECK_EQUAL( 4, value1);
+ BOOST_CHECK_EQUAL( 5, value2);
+ BOOST_CHECK_EQUAL( 5, value3);
+}
+
+boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
+{
+ boost::unit_test::test_suite * test =
+ BOOST_TEST_SUITE("Boost.Fiber: join test suite");
+
+ test->add( BOOST_TEST_CASE( & test_case_1) );
+ test->add( BOOST_TEST_CASE( & test_case_2) );
+
+ return test;
+}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk