|
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