Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r57761 - in sandbox/fiber: boost/fiber boost/fiber/detail libs/fiber/src libs/fiber/test
From: oliver.kowalke_at_[hidden]
Date: 2009-11-18 17:02:48


Author: olli
Date: 2009-11-18 17:02:46 EST (Wed, 18 Nov 2009)
New Revision: 57761
URL: http://svn.boost.org/trac/boost/changeset/57761

Log:
- refactoring of interface (remove _active_fiber/_fiber from function names)
- fiber::join() throw fiber_interrupted if fiber gets interrupted

Text files modified:
   sandbox/fiber/boost/fiber/detail/fiber_state.hpp | 2
   sandbox/fiber/boost/fiber/detail/scheduler_impl.hpp | 46 +++--
   sandbox/fiber/boost/fiber/interruption.hpp | 12
   sandbox/fiber/boost/fiber/scheduler.hpp | 44 +++--
   sandbox/fiber/boost/fiber/utility.hpp | 24 +-
   sandbox/fiber/libs/fiber/src/fiber.cpp | 41 +++--
   sandbox/fiber/libs/fiber/src/scheduler.cpp | 74 +++++----
   sandbox/fiber/libs/fiber/src/scheduler_impl.cpp | 293 +++++++++++++++++++++++++++++----------
   sandbox/fiber/libs/fiber/test/test_join.cpp | 62 +++++++
   9 files changed, 411 insertions(+), 187 deletions(-)

Modified: sandbox/fiber/boost/fiber/detail/fiber_state.hpp
==============================================================================
--- sandbox/fiber/boost/fiber/detail/fiber_state.hpp (original)
+++ sandbox/fiber/boost/fiber/detail/fiber_state.hpp 2009-11-18 17:02:46 EST (Wed, 18 Nov 2009)
@@ -20,7 +20,7 @@
         STATE_READY = 1 << 2,
         STATE_RUNNING = 1 << 3,
         STATE_SUSPENDED = 1 << 4,
- STATE_WAITING = 1 << 5,
+ STATE_WAIT_FOR_JOIN = 1 << 5,
         STATE_TERMINATED = 1 << 6
 };
 

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-18 17:02:46 EST (Wed, 18 Nov 2009)
@@ -13,6 +13,7 @@
 #include <queue>
 
 #include <boost/function.hpp>
+#include <boost/optional.hpp>
 #include <boost/utility.hpp>
 
 #include <boost/fiber/detail/config.hpp>
@@ -36,21 +37,22 @@
         struct schedulable
         {
                 fiber f;
- std::list< fiber::id > waiting;
+ std::list< fiber::id > joining_fibers;
+ optional< fiber::id > waiting_on;
 
                 schedulable() :
- f(), waiting()
+ f(), joining_fibers(), waiting_on()
                 {}
 
                 schedulable( fiber f_) :
- f( f_), waiting()
+ f( f_), joining_fibers(), waiting_on()
                 {}
         };
 
         typedef std::map< fiber::id, schedulable > container;
         typedef std::list< fiber::id > runnable_queue;
         typedef std::queue< fiber::id > terminated_queue;
- typedef function< void() > callable_t;
+ typedef function< void() > callable_t;
 
         fiber master_;
         fiber active_;
@@ -63,39 +65,41 @@
 
         ~scheduler_impl();
 
- void add_fiber( fiber);
+ void add( fiber);
 
- fiber::id id_active_fiber() const;
+ fiber::id get_id() const;
 
- void yield_active_fiber();
+ void yield();
 
- void cancel_active_fiber();
+ void cancel();
 
- void suspend_active_fiber();
+ void suspend();
 
- void interrupt_active_fiber();
+ void interrupt();
 
- bool interruption_requested_active_fiber() const;
+ bool interruption_requested();
 
- bool interruption_enabled_active_fiber() const;
+ bool interruption_enabled();
 
- fiber_interrupt_t & interrupt_flags_active_fiber();
+ fiber_interrupt_t & interrupt_flags();
 
- int priority_active_fiber();
+ int priority();
 
- void priority_active_fiber( int);
+ void priority( int);
 
- void at_exit_active_fiber( callable_t);
+ void at_exit( callable_t);
 
- void cancel_fiber( fiber::id const&);
+ void interrupt( fiber::id const&);
 
- void suspend_fiber( fiber::id const&);
+ void cancel( fiber::id const&);
 
- void resume_fiber( fiber::id const&);
+ void suspend( fiber::id const&);
 
- void reschedule_fiber( fiber::id const&);
+ void resume( fiber::id const&);
 
- void join_fiber( fiber::id const&);
+ void join( fiber::id const&);
+
+ void reschedule( fiber::id const&);
 
         bool run();
 

Modified: sandbox/fiber/boost/fiber/interruption.hpp
==============================================================================
--- sandbox/fiber/boost/fiber/interruption.hpp (original)
+++ sandbox/fiber/boost/fiber/interruption.hpp 2009-11-18 17:02:46 EST (Wed, 18 Nov 2009)
@@ -27,16 +27,16 @@
 
 public:
         disable_interruption() :
- set_( ( scheduler::interrupt_flags_active_fiber() & detail::INTERRUPTION_BLOCKED) != 0)
+ set_( ( scheduler::interrupt_flags() & detail::INTERRUPTION_BLOCKED) != 0)
         {
                 if ( ! set_)
- scheduler::interrupt_flags_active_fiber() |= detail::INTERRUPTION_BLOCKED;
+ scheduler::interrupt_flags() |= detail::INTERRUPTION_BLOCKED;
         }
 
         ~disable_interruption()
         {
                 if ( ! set_)
- scheduler::interrupt_flags_active_fiber() &= ~detail::INTERRUPTION_BLOCKED;
+ scheduler::interrupt_flags() &= ~detail::INTERRUPTION_BLOCKED;
         }
 };
 
@@ -47,16 +47,16 @@
 
 public:
         restore_interruption() :
- set_( ( scheduler::interrupt_flags_active_fiber() & detail::INTERRUPTION_BLOCKED) != 0)
+ set_( ( scheduler::interrupt_flags() & detail::INTERRUPTION_BLOCKED) != 0)
         {
                 if ( set_)
- scheduler::interrupt_flags_active_fiber() &= ~detail::INTERRUPTION_BLOCKED;
+ scheduler::interrupt_flags() &= ~detail::INTERRUPTION_BLOCKED;
         }
 
         ~restore_interruption()
         {
                 if ( set_)
- scheduler::interrupt_flags_active_fiber() |= detail::INTERRUPTION_BLOCKED;
+ scheduler::interrupt_flags() |= detail::INTERRUPTION_BLOCKED;
         }
 };
 

Modified: sandbox/fiber/boost/fiber/scheduler.hpp
==============================================================================
--- sandbox/fiber/boost/fiber/scheduler.hpp (original)
+++ sandbox/fiber/boost/fiber/scheduler.hpp 2009-11-18 17:02:46 EST (Wed, 18 Nov 2009)
@@ -81,37 +81,41 @@
 
         static bool runs_as_fiber();
 
- static fiber::id id_active_fiber();
+ static fiber::id get_id();
 
- static void yield_active_fiber();
+ static void interrupt();
 
- static void cancel_active_fiber();
+ static bool interruption_requested();
 
- static void suspend_active_fiber();
+ static bool interruption_enabled();
 
- static void interrupt_active_fiber();
+ static detail::fiber_interrupt_t & interrupt_flags();
 
- static bool interruption_requested_active_fiber();
+ static void yield();
 
- static bool interruption_enabled_active_fiber();
+ static void cancel();
 
- static detail::fiber_interrupt_t & interrupt_flags_active_fiber();
+ static void suspend();
 
- static int priority_active_fiber();
+ static int priority();
 
- static void priority_active_fiber( int);
+ static void priority( int);
 
- static void at_exit_active_fiber( callable_t);
+ static void at_exit( callable_t);
 
- static void cancel_fiber( fiber::id const&);
+ static void interrupt( fiber::id const&);
 
- static void suspend_fiber( fiber::id const&);
+ static bool interruption_requested( fiber::id const&);
 
- static void resume_fiber( fiber::id const&);
+ static void cancel( fiber::id const&);
 
- static void reschedule_fiber( fiber::id const&);
+ static void suspend( fiber::id const&);
 
- static void join_fiber( fiber::id const&);
+ static void resume( fiber::id const&);
+
+ static void join( fiber::id const&);
+
+ static void reschedule( fiber::id const&);
 
         detail::scheduler_impl * access_();
 
@@ -128,11 +132,11 @@
 
         template< typename Fn >
         void make_fiber( Fn fn)
- { access_()->add_fiber( fiber( fn) ); }
+ { access_()->add( fiber( fn) ); }
 
         template< typename Fn >
         void make_fiber( std::size_t stack_size, Fn fn)
- { access_()->add_fiber( fiber( stack_size, fn) ); }
+ { access_()->add( fiber( stack_size, fn) ); }
 
 #ifndef BOOST_FIBER_MAX_ARITY
 #define BOOST_FIBER_MAX_ARITY 10
@@ -145,10 +149,10 @@
 #define BOOST_FIBER_MAKE_FIBER_FUNCTION(z, n, unused) \
         template< typename Fn, BOOST_PP_ENUM_PARAMS(n, typename A) > \
         void make_fiber( Fn fn, BOOST_ENUM_FIBER_ARGS(n)) \
- { access_()->add_fiber( fiber( fn, BOOST_PP_ENUM_PARAMS(n, a) ) ); } \
+ { access_()->add( fiber( fn, BOOST_PP_ENUM_PARAMS(n, a) ) ); } \
         template< typename Fn, BOOST_PP_ENUM_PARAMS(n, typename A) > \
         void make_fiber( std::size_t stack_size, Fn fn, BOOST_ENUM_FIBER_ARGS(n)) \
- { access_()->add_fiber( fiber( stack_size, fn, BOOST_PP_ENUM_PARAMS(n, a) ) ); }
+ { access_()->add( fiber( stack_size, fn, BOOST_PP_ENUM_PARAMS(n, a) ) ); }
 
 BOOST_PP_REPEAT_FROM_TO( 1, BOOST_FIBER_MAX_ARITY, BOOST_FIBER_MAKE_FIBER_FUNCTION, ~)
 

Modified: sandbox/fiber/boost/fiber/utility.hpp
==============================================================================
--- sandbox/fiber/boost/fiber/utility.hpp (original)
+++ sandbox/fiber/boost/fiber/utility.hpp 2009-11-18 17:02:46 EST (Wed, 18 Nov 2009)
@@ -25,55 +25,55 @@
 
 inline
 fiber::id get_id()
-{ return fibers::scheduler::id_active_fiber(); }
+{ return fibers::scheduler::get_id(); }
 
 inline
 void yield()
-{ fibers::scheduler::yield_active_fiber(); }
+{ fibers::scheduler::yield(); }
 
 inline
 void cancel()
-{ fibers::scheduler::cancel_active_fiber(); }
+{ fibers::scheduler::cancel(); }
 
 inline
 void suspend()
-{ fibers::scheduler::suspend_active_fiber(); }
+{ fibers::scheduler::suspend(); }
 
 inline
 int priority()
-{ return fibers::scheduler::priority_active_fiber(); }
+{ return fibers::scheduler::priority(); }
 
 inline
 void priority( int prio)
-{ fibers::scheduler::priority_active_fiber( prio); }
+{ fibers::scheduler::priority( prio); }
 
 inline
 void interruption_point()
-{ fibers::scheduler::interrupt_active_fiber(); }
+{ fibers::scheduler::interrupt(); }
 
 inline
 bool interruption_requested()
-{ return fibers::scheduler::interruption_requested_active_fiber(); }
+{ return fibers::scheduler::interruption_requested(); }
 
 inline
 bool interruption_enabled()
-{ return fibers::scheduler::interruption_enabled_active_fiber(); }
+{ return fibers::scheduler::interruption_enabled(); }
 
 template< typename Callable >
 void at_fiber_exit( Callable ca)
 {
- fibers::scheduler::at_exit_active_fiber(
+ fibers::scheduler::at_exit(
                 boost::bind( boost::type< void >(), ca) );
 }
 
 inline
 void at_fiber_exit( function< void() > ca)
-{ fibers::scheduler::at_exit_active_fiber( ca); }
+{ fibers::scheduler::at_exit( ca); }
 
 inline
 void at_fiber_exit( void ( * ca)() )
 {
- fibers::scheduler::at_exit_active_fiber(
+ fibers::scheduler::at_exit(
                 boost::bind( boost::type< void >(), ca) );
 }
 

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-18 17:02:46 EST (Wed, 18 Nov 2009)
@@ -81,14 +81,6 @@
 fiber::operator!() const
 { return ! info_; }
 
-void
-fiber::swap( fiber & other)
-{ info_.swap( other.info_); }
-
-fiber::id
-fiber::get_id() const
-{ return fiber::id( info_); }
-
 bool
 fiber::operator==( fiber const& other) const
 { return get_id() == other.get_id(); }
@@ -97,6 +89,14 @@
 fiber::operator!=( fiber const& other) const
 { return !( get_id() == other.get_id() ); }
 
+void
+fiber::swap( fiber & other)
+{ info_.swap( other.info_); }
+
+fiber::id
+fiber::get_id() const
+{ return fiber::id( info_); }
+
 bool
 fiber::is_alive() const
 {
@@ -116,15 +116,14 @@
 {
         if ( ! info_) throw fiber_moved();
         info_->priority = prio;
- if ( is_alive() ) scheduler::reschedule_fiber( get_id() );
+ if ( is_alive() ) scheduler::reschedule( get_id() );
 }
 
 void
 fiber::interrupt()
 {
         if ( ! info_) throw fiber_moved();
- info_->interrupt &= ~detail::INTERRUPTION_DISABLED;
- info_->interrupt |= detail::INTERRUPTION_ENABLED;
+ scheduler::interrupt( get_id() );
 }
 
 bool
@@ -136,19 +135,31 @@
 
 void
 fiber::cancel()
-{ scheduler::cancel_fiber( get_id() ); }
+{
+ if ( ! info_) throw fiber_moved();
+ scheduler::cancel( get_id() );
+}
 
 void
 fiber::suspend()
-{ scheduler::suspend_fiber( get_id() ); }
+{
+ if ( ! info_) throw fiber_moved();
+ scheduler::suspend( get_id() );
+}
 
 void
 fiber::resume()
-{ scheduler::resume_fiber( get_id() ); }
+{
+ if ( ! info_) throw fiber_moved();
+ scheduler::resume( get_id() );
+}
 
 void
 fiber::join()
-{ scheduler::join_fiber( get_id() ); }
+{
+ if ( ! info_) throw fiber_moved();
+ scheduler::join( get_id() );
+}
 
 }}
 

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-18 17:02:46 EST (Wed, 18 Nov 2009)
@@ -22,131 +22,139 @@
 { return impl_.get() != 0; }
 
 fiber::id
-scheduler::id_active_fiber()
+scheduler::get_id()
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- return impl->id_active_fiber();
+ return impl->get_id();
 }
 
 void
-scheduler::yield_active_fiber()
+scheduler::yield()
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->yield_active_fiber();
+ impl->yield();
 }
 
 void
-scheduler::cancel_active_fiber()
+scheduler::cancel()
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->cancel_active_fiber();
+ impl->cancel();
 }
 
 void
-scheduler::suspend_active_fiber()
+scheduler::suspend()
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->suspend_active_fiber();
+ impl->suspend();
 }
 
 void
-scheduler::interrupt_active_fiber()
+scheduler::interrupt()
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->interrupt_active_fiber();
+ impl->interrupt();
 }
 
 bool
-scheduler::interruption_requested_active_fiber()
+scheduler::interruption_requested()
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- return impl->interruption_requested_active_fiber();
+ return impl->interruption_requested();
 }
 
 bool
-scheduler::interruption_enabled_active_fiber()
+scheduler::interruption_enabled()
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- return impl->interruption_enabled_active_fiber();
+ return impl->interruption_enabled();
 }
 
 detail::fiber_interrupt_t &
-scheduler::interrupt_flags_active_fiber()
+scheduler::interrupt_flags()
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- return impl->interrupt_flags_active_fiber();
+ return impl->interrupt_flags();
 }
 
 int
-scheduler::priority_active_fiber()
+scheduler::priority()
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- return impl->priority_active_fiber();
+ return impl->priority();
 }
 
 void
-scheduler::priority_active_fiber( int prio)
+scheduler::priority( int prio)
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->priority_active_fiber( prio);
+ impl->priority( prio);
 }
 
 void
-scheduler::at_exit_active_fiber( callable_t ca)
+scheduler::at_exit( callable_t ca)
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->at_exit_active_fiber( ca);
+ impl->at_exit( ca);
 }
 
 void
-scheduler::cancel_fiber( fiber::id const& id)
+scheduler::interrupt( fiber::id const& id)
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->cancel_fiber( id);
+ impl->interrupt( id);
 }
 
 void
-scheduler::suspend_fiber( fiber::id const& id)
+scheduler::cancel( fiber::id const& id)
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->suspend_fiber( id);
+ impl->cancel( id);
 }
 
 void
-scheduler::resume_fiber( fiber::id const& id)
+scheduler::suspend( fiber::id const& id)
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->resume_fiber( id);
+ impl->suspend( id);
 }
 
 void
-scheduler::reschedule_fiber( fiber::id const& id)
+scheduler::resume( fiber::id const& id)
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->reschedule_fiber( id);
+ impl->resume( id);
 }
 
 void
-scheduler::join_fiber( fiber::id const& id)
+scheduler::join( fiber::id const& id)
 {
         detail::scheduler_impl * impl( impl_.get() );
         if ( ! impl) throw fiber_error("not a fiber");
- impl->join_fiber( id);
+ impl->join( id);
+}
+
+void
+scheduler::reschedule( fiber::id const& id)
+{
+ detail::scheduler_impl * impl( impl_.get() );
+ if ( ! impl) throw fiber_error("not a fiber");
+ impl->reschedule( id);
 }
 
 detail::scheduler_impl *
@@ -174,7 +182,7 @@
 
 void
 scheduler::submit_fiber( fiber f)
-{ access_()->add_fiber( f); }
+{ access_()->add( f); }
 
 }}
 

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-18 17:02:46 EST (Wed, 18 Nov 2009)
@@ -37,8 +37,8 @@
 #define HAS_STATE_SUSPENDED( state) \
         ( state & STATE_SUSPENDED) != 0
 
-#define HAS_STATE_WAITING( state) \
- ( state & STATE_WAITING) != 0
+#define HAS_STATE_WAIT_FOR_JOIN( state) \
+ ( state & STATE_WAIT_FOR_JOIN) != 0
 
 #define HAS_STATE_TERMINATED( state) \
         ( state & STATE_TERMINATED) != 0
@@ -60,173 +60,271 @@
 { fiber::convert_fiber_to_thread(); }
 
 void
-scheduler_impl::add_fiber( fiber f)
+scheduler_impl::add( fiber f)
 {
         if ( ! f) throw fiber_moved();
 
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
         BOOST_ASSERT( STATE_NOT_STARTED == f.info_->state);
+
+ // set state to ready
         f.info_->state = STATE_READY;
+
+ // insert fiber to fiber-list
         std::pair< std::map< fiber::id, schedulable >::iterator, bool > result(
                 fibers_.insert(
                         std::make_pair(
                                 f.get_id(),
                                 schedulable( f) ) ) );
+
+ // check result
         if ( ! result.second) throw scheduler_error("inserting fiber failed");
+
+ // put fiber to runnable-queue
         runnable_fibers_.push_back( result.first->first);
 }
 
 fiber::id
-scheduler_impl::id_active_fiber() const
+scheduler_impl::get_id() const
 { return active_.get_id(); }
 
 void
-scheduler_impl::yield_active_fiber()
+scheduler_impl::yield()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( active_.info_->state) );
         BOOST_ASSERT( STATE_RUNNING == active_.info_->state);
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
 
+ // set state ready
         active_.info_->state = STATE_READY;
 
+ // put fiber to runnable-queue
         runnable_fibers_.push_back( active_.get_id() );
+
+ // switch to master-fiber
         active_.switch_to_( master_);
 }
 
 void
-scheduler_impl::cancel_active_fiber()
+scheduler_impl::cancel()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( active_.info_->state) );
         BOOST_ASSERT( STATE_RUNNING == active_.info_->state);
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
 
- active_.info_->state = STATE_TERMINATED;
-
- terminated_fibers_.push( active_.get_id() );
+ schedulable s( fibers_[active_.get_id()]);
 
- BOOST_FOREACH( fiber::id id__, fibers_[active_.get_id()].waiting)
+ // invoke each fiber waiting on this fiber
+ BOOST_FOREACH( fiber::id id__, s.joining_fibers)
         {
- fiber f__( fibers_[id__].f);
- BOOST_ASSERT( HAS_STATE_WAITING( f__.info_->state) );
- f__.info_->state &= ~STATE_WAITING;
+ schedulable s__( fibers_[id__]);
+ fiber f__( s__.f);
+ BOOST_ASSERT( s__.waiting_on);
+ BOOST_ASSERT( active_.get_id() == * s__.waiting_on);
+ BOOST_ASSERT( HAS_STATE_WAIT_FOR_JOIN( f__.info_->state) );
+
+ // clear waiting-on
+ fibers_[id__].waiting_on.reset();
+
+ // remove wait-for-join state
+ f__.info_->state &= ~STATE_WAIT_FOR_JOIN;
+
+ // if fiber is in state ready or running and not suspended
+ // put it on runnable-queue
                 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() );
+ runnable_fibers_.push_back( id__);
                 }
         }
- fibers_[active_.get_id()].waiting.clear();
+ // clear waiting-queue
+ fibers_[active_.get_id()].joining_fibers.clear();
+
+ // set state to terminated
+ active_.info_->state = STATE_TERMINATED;
+
+ // put fiber to terminated-queue
+ terminated_fibers_.push( active_.get_id() );
 
+ // switch to master-fiber
         active_.switch_to_( master_);
 }
 
 void
-scheduler_impl::suspend_active_fiber()
+scheduler_impl::suspend()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( active_.info_->state) );
         BOOST_ASSERT( STATE_RUNNING == active_.info_->state);
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
 
+ // set state suspended
         active_.info_->state |= STATE_SUSPENDED;
+
+ // switch to master-fiber
         active_.switch_to_( master_);
 }
 
 void
-scheduler_impl::interrupt_active_fiber()
+scheduler_impl::interrupt()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( active_.info_->state) );
         BOOST_ASSERT( STATE_RUNNING == active_.info_->state);
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
 
+ // gets invoked by interruption-points
+ // if interruption flag is set throw fiber_interrupted
+ // exceptions
         if ( INTERRUPTION_ENABLED == active_.info_->interrupt)
                 throw fiber_interrupted();
 }
 
 bool
-scheduler_impl::interruption_requested_active_fiber() const
+scheduler_impl::interruption_requested()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( active_.info_->state) );
         BOOST_ASSERT( STATE_RUNNING == active_.info_->state);
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
 
         return active_.interruption_requested();
 }
 
 bool
-scheduler_impl::interruption_enabled_active_fiber() const
+scheduler_impl::interruption_enabled()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( active_.info_->state) );
         BOOST_ASSERT( STATE_RUNNING == active_.info_->state);
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
 
         return active_.info_->interrupt == detail::INTERRUPTION_ENABLED;
 }
 
 fiber_interrupt_t &
-scheduler_impl::interrupt_flags_active_fiber()
+scheduler_impl::interrupt_flags()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( active_.info_->state) );
         BOOST_ASSERT( STATE_RUNNING == active_.info_->state);
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
 
         return active_.info_->interrupt;
 }
 
 int
-scheduler_impl::priority_active_fiber()
+scheduler_impl::priority()
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( active_.info_->state) );
         BOOST_ASSERT( STATE_RUNNING == active_.info_->state);
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
 
         return active_.priority();
 }
 
 void
-scheduler_impl::priority_active_fiber( int prio)
+scheduler_impl::priority( int prio)
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( active_.info_->state) );
         BOOST_ASSERT( STATE_RUNNING == active_.info_->state);
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
 
+ // set priority
         active_.priority( prio);
- reschedule_fiber( active_.get_id() );
 }
 
 void
-scheduler_impl::at_exit_active_fiber( callable_t ca)
+scheduler_impl::at_exit( callable_t ca)
 {
- BOOST_ASSERT( ! HAS_STATE_MASTER( active_.info_->state) );
         BOOST_ASSERT( STATE_RUNNING == active_.info_->state);
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
 
+ // push a exit-callback on fibers stack
         active_.info_->at_exit.push( ca);
 }
 
 void
-scheduler_impl::cancel_fiber( fiber::id const& id)
+scheduler_impl::interrupt( fiber::id const& id)
 {
         container::iterator i = fibers_.find( id);
         if ( i == fibers_.end() ) return;
- fiber f( i->second.f);
+ schedulable s( i->second);
+ fiber f( s.f);
+ BOOST_ASSERT( f);
+ BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
+ BOOST_ASSERT( ! HAS_STATE_NOT_STARTED( f.info_->state) );
+
+ // nothing to do for al terminated fiber
+ if ( HAS_STATE_TERMINATED( f.info_->state) ) return;
+
+ // remove disabled flag
+ f.info_->interrupt &= ~detail::INTERRUPTION_DISABLED;
+
+ // set enabled flag
+ f.info_->interrupt |= detail::INTERRUPTION_ENABLED;
+
+ // if fiber is waiting
+ if ( HAS_STATE_WAIT_FOR_JOIN( f.info_->state) )
+ {
+ // fiber is waiting (joining) on another fiber
+ // remove it from the waiting-queue, reset waiting-on
+ // and reset the waiting state
+ BOOST_ASSERT( s.waiting_on);
+ fibers_[* s.waiting_on].joining_fibers.remove( id);
+ fibers_[id].waiting_on.reset();
+ f.info_->interrupt &= ~STATE_WAIT_FOR_JOIN;
+
+ // if fiber is not suspended put it to runnable-queue
+ if ( ! HAS_STATE_SUSPENDED( f.info_->state) )
+ {
+ BOOST_ASSERT(
+ HAS_STATE_READY( f.info_->state) ||
+ HAS_STATE_RUNNING( f.info_->state) );
+ f.info_->state = STATE_READY;
+ runnable_fibers_.push_back( id);
+ }
+ }
+}
+
+void
+scheduler_impl::cancel( fiber::id const& id)
+{
+ container::iterator i = fibers_.find( id);
+ if ( i == fibers_.end() ) return;
+ schedulable s( i->second);
+ fiber f( s.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
-
- if ( HAS_STATE_TERMINATED( f.info_->state) ||
- HAS_STATE_NOT_STARTED( f.info_->state) )
- return;
-
- BOOST_FOREACH( fiber::id id__, fibers_[id].waiting)
- {
- fiber f__( fibers_[id__].f);
- BOOST_ASSERT( HAS_STATE_WAITING( f__.info_->state) );
- f__.info_->state &= ~STATE_WAITING;
+ BOOST_ASSERT( ! HAS_STATE_NOT_STARTED( f.info_->state) );
+
+ // nothing to do for al terminated fiber
+ if ( HAS_STATE_TERMINATED( f.info_->state) ) return;
+
+ // invoke each fiber waiting on this fiber
+ BOOST_FOREACH( fiber::id id__, s.joining_fibers)
+ {
+ schedulable s__( fibers_[id__]);
+ fiber f__( s__.f);
+ BOOST_ASSERT( s__.waiting_on);
+ BOOST_ASSERT( HAS_STATE_WAIT_FOR_JOIN( f__.info_->state) );
+
+ // clear waiting-on
+ fibers_[id__].waiting_on.reset();
+
+ // remove wait-for-join state
+ f__.info_->state &= ~STATE_WAIT_FOR_JOIN;
+
+ // if fiber is in state ready or running and not suspended
+ // put it on runnable-queue
                 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() );
+ runnable_fibers_.push_back( id__);
                 }
         }
- fibers_[id].waiting.clear();
+ // clear waiting-queue
+ fibers_[id].joining_fibers.clear();
 
+ // if fiber is ready remove it from the runnable-queue
+ // and put it to terminated-queue
         if ( HAS_STATE_READY( f.info_->state) )
         {
                 f.info_->state = STATE_TERMINATED;
- runnable_fibers_.remove( f.get_id() );
+ runnable_fibers_.remove( id);
                 terminated_fibers_.push( id);
         }
+ // if fiber is running (== active fiber)
+ // put it to terminated-queue and switch
+ // to master fiber
         else if ( HAS_STATE_RUNNING( f.info_->state) )
         {
                 BOOST_ASSERT( active_.get_id() == id);
@@ -234,95 +332,137 @@
                 terminated_fibers_.push( id);
                 f.switch_to_( master_);
         }
- else if ( HAS_STATE_WAITING( f.info_->state) )
+ // if fiber is waiting then remove it from the
+ // waiting-queue and put it to terminated-queue
+ else if ( HAS_STATE_WAIT_FOR_JOIN( f.info_->state) )
         {
+ BOOST_ASSERT( s.waiting_on);
                 f.info_->state = STATE_TERMINATED;
- // TODO: remove from waiting-queue
+ fibers_[* s.waiting_on].joining_fibers.remove( id);
                 terminated_fibers_.push( id);
         }
+ // suspended state is only used with one of the
+ // other states
         else
                 BOOST_ASSERT( ! "should never reached");
 }
 
 void
-scheduler_impl::suspend_fiber( fiber::id const& id)
+scheduler_impl::suspend( fiber::id const& id)
 {
         container::iterator i = fibers_.find( id);
         if ( i == fibers_.end() ) return;
         fiber f( i->second.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
-
- if ( HAS_STATE_TERMINATED( f.info_->state) ||
- HAS_STATE_NOT_STARTED( f.info_->state) )
- return;
+ BOOST_ASSERT( ! HAS_STATE_NOT_STARTED( f.info_->state) );
+
+ // nothing to do for a terminated fiber
+ if ( HAS_STATE_TERMINATED( f.info_->state) ) return;
 
+ // if fiber is ready remove it from the
+ // runnable-queue
         if ( HAS_STATE_READY( f.info_->state) )
         {
                 f.info_->state |= STATE_SUSPENDED;
- runnable_fibers_.remove( f.get_id() );
+ runnable_fibers_.remove( id);
         }
+ // if fiber is running (== active fiber)
+ // switch to master-fiber
         else if ( HAS_STATE_RUNNING( f.info_->state) )
         {
                 BOOST_ASSERT( active_.get_id() == id);
                 f.info_->state |= STATE_SUSPENDED;
                 f.switch_to_( master_);
         }
- else if ( HAS_STATE_WAITING( f.info_->state) )
+ // if fiber is in waiting state mark it only
+ // as suspended
+ else if ( HAS_STATE_WAIT_FOR_JOIN( f.info_->state) )
                 f.info_->state |= STATE_SUSPENDED;
         else
                 BOOST_ASSERT( ! "should never reached");
 }
 
 void
-scheduler_impl::resume_fiber( fiber::id const& id)
+scheduler_impl::resume( fiber::id const& id)
 {
         container::iterator i = fibers_.find( id);
         if ( i == fibers_.end() ) return;
         fiber f( i->second.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
+ BOOST_ASSERT( ! HAS_STATE_NOT_STARTED( f.info_->state) );
 
         BOOST_ASSERT( active_.get_id() != id);
 
+ // nothing to do for already terminated fiber
+ if ( HAS_STATE_TERMINATED( f.info_->state) ) return;
+
+ // remove suspended state an requeue fiber
         if ( HAS_STATE_SUSPENDED( f.info_->state) )
         {
                 f.info_->state &= ~STATE_SUSPENDED;
+ // if suspended fiber was ready or running and not waiting
+ // put it to the runnable-queue
                 if ( ( HAS_STATE_READY( f.info_->state) || HAS_STATE_RUNNING( f.info_->state) )
- && ! HAS_STATE_WAITING( f.info_->state) )
+ && ! HAS_STATE_WAIT_FOR_JOIN( f.info_->state) )
                 {
                         f.info_->state = STATE_READY;
- runnable_fibers_.push_back( f.get_id() );
+ runnable_fibers_.push_back( id);
                 }
         }
 }
 
 void
-scheduler_impl::reschedule_fiber( fiber::id const& id)
+scheduler_impl::join( fiber::id const& id)
 {
         container::iterator i = fibers_.find( id);
         if ( i == fibers_.end() ) return;
- fiber f( i->second.f);
+ schedulable s( i->second);
+ fiber f( s.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
+ BOOST_ASSERT( ! HAS_STATE_NOT_STARTED( f.info_->state) );
 
- // TODO: re-schedule fiber == remove from
- // runnable_fibers + re-insert
+ // nothing to do for a terminated fiber
+ if ( HAS_STATE_TERMINATED( f.info_->state) ) return;
+
+ // prevent self-join
+ if ( active_.get_id() == id) throw scheduler_error("self-join denied");
+
+ // register on fiber to be joined
+ fibers_[id].joining_fibers.push_back( active_.get_id() );
+
+ // set state waiting
+ active_.info_->state |= STATE_WAIT_FOR_JOIN;
+
+ // set fiber-id waiting-on
+ fibers_[active_.get_id()].waiting_on = id;
+
+ // switch to master-fiber
+ active_.switch_to_( master_);
+
+ // fiber was invoked
+ BOOST_ASSERT( ! HAS_STATE_WAIT_FOR_JOIN( active_.info_->state) );
+ BOOST_ASSERT( ! fibers_[active_.get_id()].waiting_on);
+
+ // check if interruption was requested
+ interrupt();
 }
 
 void
-scheduler_impl::join_fiber( fiber::id const& id)
+scheduler_impl::reschedule( fiber::id const& id)
 {
         container::iterator i = fibers_.find( id);
         if ( i == fibers_.end() ) return;
         fiber f( i->second.f);
         BOOST_ASSERT( f);
         BOOST_ASSERT( ! HAS_STATE_MASTER( f.info_->state) );
+ BOOST_ASSERT( ! HAS_STATE_NOT_STARTED( f.info_->state) );
+ BOOST_ASSERT( ! HAS_STATE_TERMINATED( f.info_->state) );
 
- if ( active_.get_id() == id) throw scheduler_error("self-join denied");
- fibers_[id].waiting.push_back( active_.get_id() );
- active_.info_->state |= STATE_WAITING;
- active_.switch_to_( master_);
+ // TODO: re-schedule fiber == remove from
+ // runnable_fibers + re-insert
 }
 
 bool
@@ -331,7 +471,9 @@
         bool result( false);
         if ( ! runnable_fibers_.empty() )
         {
- active_ = fibers_[runnable_fibers_.front()].f;
+ schedulable s = fibers_[runnable_fibers_.front()];
+ active_ = s.f;
+ BOOST_ASSERT( ! s.waiting_on);
                 BOOST_ASSERT( active_.info_->state == STATE_READY);
                 active_.info_->state = STATE_RUNNING;
                 master_.switch_to_( active_);
@@ -339,14 +481,15 @@
                 result = true;
         }
         else
- boost::move( active_);
+ active_.move();
 
         while ( ! terminated_fibers_.empty() )
         {
- fiber f( fibers_[terminated_fibers_.front()].f);
+ schedulable s = fibers_[terminated_fibers_.front()];
+ fiber f( s.f);
                 terminated_fibers_.pop();
+ BOOST_ASSERT( s.joining_fibers.empty() );
                 BOOST_ASSERT( STATE_TERMINATED == f.info_->state);
- BOOST_ASSERT( fibers_[f.get_id()].waiting.empty() );
                 fibers_.erase( f.get_id() );
                 result = true;
         }
@@ -366,7 +509,7 @@
 #undef HAS_STATE_READY
 #undef HAS_STATE_RUNNING
 #undef HAS_STATE_SUSPENDED
-#undef HAS_STATE_WAITING
+#undef HAS_STATE_WAIT_FOR_JOIN
 #undef HAS_STATE_TERMINATED
 
 }}}

Modified: sandbox/fiber/libs/fiber/test/test_join.cpp
==============================================================================
--- sandbox/fiber/libs/fiber/test/test_join.cpp (original)
+++ sandbox/fiber/libs/fiber/test/test_join.cpp 2009-11-18 17:02:46 EST (Wed, 18 Nov 2009)
@@ -15,6 +15,7 @@
 int value1 = 0;
 int value2 = 0;
 int value3 = 0;
+bool interrupted = false;
 
 void fn_1()
 {
@@ -27,12 +28,17 @@
 
 void fn_2( boost::fiber f)
 {
- for ( int i = 0; i < 5; ++i)
+ try
         {
- ++value2;
- if ( i == 1) f.join();
- boost::this_fiber::yield();
+ for ( int i = 0; i < 5; ++i)
+ {
+ ++value2;
+ if ( i == 1) f.join();
+ boost::this_fiber::yield();
+ }
         }
+ catch ( boost::fibers::fiber_interrupted const&)
+ { interrupted = true; }
 }
 
 void fn_3( boost::fiber f)
@@ -45,6 +51,16 @@
         }
 }
 
+void fn_4( boost::fiber f)
+{
+ for ( int i = 0; i < 5; ++i)
+ {
+ ++value3;
+ if ( i == 3) f.interrupt();
+ boost::this_fiber::yield();
+ }
+}
+
 void test_case_1()
 {
         value1 = 0;
@@ -288,6 +304,43 @@
         BOOST_CHECK_EQUAL( 5, value3);
 }
 
+void test_case_3()
+{
+ value1 = 0;
+ value2 = 0;
+ value3 = 0;
+
+ boost::fibers::scheduler sched;
+
+ boost::fiber f1( fn_1);
+ sched.submit_fiber( f1);
+ boost::fiber f2( fn_2, f1);
+ sched.submit_fiber( f2);
+ sched.make_fiber( fn_4, f2);
+
+ BOOST_CHECK( ! sched.empty() );
+ BOOST_CHECK_EQUAL( std::size_t( 3), sched.size() );
+
+ BOOST_CHECK_EQUAL( 0, value1);
+ BOOST_CHECK_EQUAL( 0, value2);
+ BOOST_CHECK_EQUAL( 0, value3);
+ BOOST_CHECK_EQUAL( false, interrupted);
+
+ for (;;)
+ {
+ while ( sched.run() );
+ if ( sched.empty() ) break;
+ }
+
+ 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( 2, value2);
+ BOOST_CHECK_EQUAL( 5, value3);
+ BOOST_CHECK_EQUAL( true, interrupted);
+}
+
 boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
 {
         boost::unit_test::test_suite * test =
@@ -295,6 +348,7 @@
 
         test->add( BOOST_TEST_CASE( & test_case_1) );
         test->add( BOOST_TEST_CASE( & test_case_2) );
+ test->add( BOOST_TEST_CASE( & test_case_3) );
 
         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