$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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;
+}