diff --git a/build/Jamfile.v2 b/build/Jamfile.v2
index 9cb776f9..aa30a294 100644
--- a/build/Jamfile.v2
+++ b/build/Jamfile.v2
@@ -67,7 +67,9 @@ lib boost_fibers
interruption.cpp
mutex.cpp
recursive_mutex.cpp
+ recursive_timed_mutex.cpp
round_robin.cpp
+ timed_mutex.cpp
: shared:../../context/build//boost_context
shared:../../chrono/build//boost_chrono
;
diff --git a/include/boost/fiber/algorithm.hpp b/include/boost/fiber/algorithm.hpp
index a44d2946..1134868e 100644
--- a/include/boost/fiber/algorithm.hpp
+++ b/include/boost/fiber/algorithm.hpp
@@ -10,7 +10,6 @@
#include
#include
-#include
#include
#include
@@ -39,10 +38,11 @@ struct BOOST_FIBERS_DECL algorithm : private noncopyable
virtual bool run() = 0;
virtual void wait() = 0;
- virtual void timed_wait( chrono::system_clock::time_point const&) = 0;
- template< typename TimeDuration >
- void timed_wait( TimeDuration const& dt)
- { timed_wait( chrono::system_clock::now() + dt); }
+ virtual bool wait_until( clock_type::time_point const&) = 0;
+
+ template< typename Rep, typename Period >
+ bool wait_for( chrono::duration< Rep, Period > const& timeout_duration)
+ { return wait_until( clock_type::now() + timeout_duration); }
virtual void yield() = 0;
diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp
index e8bde3c2..951bb418 100644
--- a/include/boost/fiber/all.hpp
+++ b/include/boost/fiber/all.hpp
@@ -26,7 +26,9 @@
#include
#include
#include
+#include
#include
+#include
#include
#endif // BOOST_FIBERS_H
diff --git a/include/boost/fiber/condition.hpp b/include/boost/fiber/condition.hpp
index 1b8b9aeb..fd6ab4fc 100644
--- a/include/boost/fiber/condition.hpp
+++ b/include/boost/fiber/condition.hpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
@@ -38,6 +39,13 @@
namespace boost {
namespace fibers {
+BOOST_SCOPED_ENUM_DECLARE_BEGIN(cv_status)
+{
+ no_timeout = 1,
+ timeout
+}
+BOOST_SCOPED_ENUM_DECLARE_END(cv_status)
+
class BOOST_FIBERS_DECL condition : private noncopyable
{
private:
@@ -96,7 +104,7 @@ public:
}
catch (...)
{
- // remove fiber from waiting_
+ // remove fiber from waiting-list
waiting_.erase(
std::find( waiting_.begin(), waiting_.end(), n) );
throw;
@@ -105,6 +113,100 @@ public:
// lock external again before returning
lt.lock();
}
+
+ template< typename LockType >
+ cv_status wait_until( LockType & lt, clock_type::time_point const& timeout_time)
+ {
+ cv_status status = cv_status::no_timeout;
+
+ detail::notify::ptr_t n( detail::scheduler::instance()->active() );
+ try
+ {
+ if ( n)
+ {
+ // store this fiber in order to be notified later
+ waiting_.push_back( n);
+ lt.unlock();
+
+ // suspend fiber
+ if ( ! detail::scheduler::instance()->wait_until( timeout_time) )
+ {
+ // remove fiber from waiting-list
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+
+ status = cv_status::timeout;
+ }
+
+ // check if fiber was interrupted
+ this_fiber::interruption_point();
+ }
+ else
+ {
+ // notifier for main-fiber
+ detail::main_notifier mn;
+ n = detail::main_notifier::make_pointer( mn);
+
+ // store this fiber in order to be notified later
+ waiting_.push_back( n);
+
+ lt.unlock();
+ while ( ! n->is_ready() )
+ {
+ if ( ! ( clock_type::now() < timeout_time) )
+ {
+ // remove fiber from waiting-list
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+
+ status = cv_status::timeout;
+
+ break;
+ }
+ // run scheduler
+ detail::scheduler::instance()->run();
+ }
+ }
+ }
+ catch (...)
+ {
+ // remove fiber from waiting-list
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+ throw;
+ }
+
+ // lock external again before returning
+ lt.lock();
+
+ return status;
+ }
+
+ template< typename LockType, typename Pred >
+ bool wait_until( LockType & lt, clock_type::time_point const& timeout_time, Pred pred)
+ {
+ while ( ! pred() )
+ {
+ if ( cv_status::timeout == wait_until( lt, timeout_time) )
+ return pred();
+ }
+ return true;
+ }
+
+ template< typename LockType, typename Rep, typename Period >
+ cv_status wait_for( LockType & lt, chrono::duration< Rep, Period > const& timeout_duration)
+ { return wait_until( lt, clock_type::now() + timeout_duration); }
+
+ template< typename LockType, typename Rep, typename Period, typename Pred >
+ bool wait_for( LockType & lt, chrono::duration< Rep, Period > const& timeout_duration, Pred pred)
+ {
+ while ( ! pred() )
+ {
+ if ( cv_status::timeout == wait_for( lt, timeout_duration) )
+ return pred();
+ }
+ return true;
+ }
};
typedef condition condition_variable;
diff --git a/include/boost/fiber/detail/config.hpp b/include/boost/fiber/detail/config.hpp
index a7f71a81..14258990 100644
--- a/include/boost/fiber/detail/config.hpp
+++ b/include/boost/fiber/detail/config.hpp
@@ -7,6 +7,7 @@
#ifndef BOOST_FIBERS_DETAIL_CONFIG_H
#define BOOST_FIBERS_DETAIL_CONFIG_H
+#include
#include
#include
@@ -42,4 +43,13 @@
# define BOOST_FIBERS_SEGMENTS 10
#endif
+namespace boost {
+namespace fibers {
+#if defined(BOOST_HAS_CLOCK_STEADY)
+ typedef boost::chrono::steady_clock clock_type;
+#else
+ typedef boost::chrono::system_clock clock_type;
+#endif
+}}
+
#endif // BOOST_FIBERS_DETAIL_CONFIG_H
diff --git a/include/boost/fiber/exceptions.hpp b/include/boost/fiber/exceptions.hpp
index 1ab964be..100e90b1 100644
--- a/include/boost/fiber/exceptions.hpp
+++ b/include/boost/fiber/exceptions.hpp
@@ -158,10 +158,10 @@ public:
BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc)
{
- broken_promise = 1,
- future_already_retrieved,
- promise_already_satisfied,
- no_state
+ broken_promise = 1,
+ future_already_retrieved,
+ promise_already_satisfied,
+ no_state
}
BOOST_SCOPED_ENUM_DECLARE_END(future_errc)
diff --git a/include/boost/fiber/mutex.hpp b/include/boost/fiber/mutex.hpp
index c9a91423..6abe3ee8 100644
--- a/include/boost/fiber/mutex.hpp
+++ b/include/boost/fiber/mutex.hpp
@@ -3,8 +3,6 @@
// 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)
-//
-// based on boost::interprocess::sync::interprocess_spinlock
#ifndef BOOST_FIBERS_MUTEX_H
#define BOOST_FIBERS_MUTEX_H
@@ -60,8 +58,6 @@ public:
void unlock();
};
-typedef mutex try_mutex;
-
}}
# if defined(BOOST_MSVC)
diff --git a/include/boost/fiber/operations.hpp b/include/boost/fiber/operations.hpp
index 640cdc59..2323e11a 100644
--- a/include/boost/fiber/operations.hpp
+++ b/include/boost/fiber/operations.hpp
@@ -7,6 +7,7 @@
#define BOOST_THIS_FIBER_OPERATIONS_H
#include
+#include
#include
#include
@@ -20,8 +21,8 @@ namespace this_fiber {
inline
fibers::fiber::id get_id()
{
- return fibers::detail::scheduler::instance()->active()
- ? fibers::detail::scheduler::instance()->active()->get_id()
+ return fibers::detail::scheduler::instance()->active()
+ ? fibers::detail::scheduler::instance()->active()->get_id()
: fibers::fiber::id();
}
@@ -29,6 +30,14 @@ inline
void yield()
{ fibers::detail::scheduler::instance()->yield(); }
+inline
+void sleep_until( fibers::clock_type::time_point const& sleep_time)
+{ fibers::detail::scheduler::instance()->wait_until( sleep_time); }
+
+template< typename Rep, typename Period >
+void sleep_for( chrono::duration< Rep, Period > const& timeout_duration)
+{ fibers::detail::scheduler::instance()->wait_for( timeout_duration); }
+
}
namespace fibers {
diff --git a/include/boost/fiber/recursive_mutex.hpp b/include/boost/fiber/recursive_mutex.hpp
index 564c618e..1f0c55b9 100644
--- a/include/boost/fiber/recursive_mutex.hpp
+++ b/include/boost/fiber/recursive_mutex.hpp
@@ -62,8 +62,6 @@ public:
void unlock();
};
-typedef recursive_mutex recursive_try_mutex;
-
}}
# if defined(BOOST_MSVC)
diff --git a/include/boost/fiber/recursive_timed_mutex.hpp b/include/boost/fiber/recursive_timed_mutex.hpp
new file mode 100644
index 00000000..f4b6d881
--- /dev/null
+++ b/include/boost/fiber/recursive_timed_mutex.hpp
@@ -0,0 +1,81 @@
+
+// Copyright Oliver Kowalke 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// based on boost::interprocess::sync::interprocess_spinlock
+
+#ifndef BOOST_FIBERS_RECURSIVE_TIMED_MUTEX_H
+#define BOOST_FIBERS_RECURSIVE_TIMED_MUTEX_H
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+# if defined(BOOST_MSVC)
+# pragma warning(push)
+# pragma warning(disable:4355 4251 4275)
+# endif
+
+namespace boost {
+namespace fibers {
+
+class BOOST_FIBERS_DECL recursive_timed_mutex : private noncopyable
+{
+private:
+ enum state_t
+ {
+ LOCKED = 0,
+ UNLOCKED
+ };
+
+ detail::fiber_base::id owner_;
+ std::size_t count_;
+ volatile state_t state_;
+ std::deque<
+ detail::notify::ptr_t
+ > waiting_;
+
+public:
+ typedef unique_lock< recursive_timed_mutex > scoped_lock;
+
+ recursive_timed_mutex();
+
+ ~recursive_timed_mutex();
+
+ void lock();
+
+ bool try_lock();
+
+ bool try_lock_until( clock_type::time_point const& timeout_time);
+
+ template< typename Rep, typename Period >
+ bool try_lock_for( chrono::duration< Rep, Period > const& timeout_duration)
+ { return try_lock_until( clock_type::now() + timeout_duration); }
+
+ void unlock();
+};
+
+}}
+
+# if defined(BOOST_MSVC)
+# pragma warning(pop)
+# endif
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_FIBERS_RECURSIVE_TIMED_MUTEX_H
diff --git a/include/boost/fiber/round_robin.hpp b/include/boost/fiber/round_robin.hpp
index 25653dda..c8e8d8e4 100644
--- a/include/boost/fiber/round_robin.hpp
+++ b/include/boost/fiber/round_robin.hpp
@@ -9,7 +9,6 @@
#include
#include
-#include
#include
#include
#include
@@ -38,20 +37,13 @@ private:
struct schedulable
{
detail::fiber_base::ptr_t f;
- chrono::system_clock::time_point tp;
-
- schedulable( detail::fiber_base::ptr_t const& f_) :
- f( f_),
- tp( (chrono::system_clock::time_point::max)() )
- { BOOST_ASSERT( f); }
+ clock_type::time_point tp;
schedulable( detail::fiber_base::ptr_t const& f_,
- chrono::system_clock::time_point const& tp_) :
+ clock_type::time_point const& tp_ =
+ (clock_type::time_point::max)() ) :
f( f_), tp( tp_)
- {
- BOOST_ASSERT( f);
- BOOST_ASSERT( (chrono::system_clock::time_point::max)() != tp);
- }
+ { BOOST_ASSERT( f); }
};
typedef std::deque< schedulable > wqueue_t;
@@ -78,7 +70,7 @@ public:
bool run();
void wait();
- void timed_wait( chrono::system_clock::time_point const&);
+ bool wait_until( clock_type::time_point const&);
void yield();
};
diff --git a/include/boost/fiber/timed_mutex.hpp b/include/boost/fiber/timed_mutex.hpp
new file mode 100644
index 00000000..fd88751c
--- /dev/null
+++ b/include/boost/fiber/timed_mutex.hpp
@@ -0,0 +1,77 @@
+
+// Copyright Oliver Kowalke 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_FIBERS_TIMED_MUTEX_H
+#define BOOST_FIBERS_TIMED_MUTEX_H
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+# if defined(BOOST_MSVC)
+# pragma warning(push)
+# pragma warning(disable:4355 4251 4275)
+# endif
+
+namespace boost {
+namespace fibers {
+
+class BOOST_FIBERS_DECL timed_mutex : private noncopyable
+{
+private:
+ enum state_t
+ {
+ LOCKED = 0,
+ UNLOCKED
+ };
+
+ detail::fiber_base::id owner_;
+ volatile state_t state_;
+ std::deque<
+ detail::notify::ptr_t
+ > waiting_;
+
+public:
+ typedef unique_lock< timed_mutex > scoped_lock;
+
+ timed_mutex();
+
+ ~timed_mutex();
+
+ void lock();
+
+ bool try_lock();
+
+ bool try_lock_until( clock_type::time_point const& timeout_time);
+
+ template< typename Rep, typename Period >
+ bool try_lock_for( chrono::duration< Rep, Period > const& timeout_duration)
+ { return try_lock_until( clock_type::now() + timeout_duration); }
+
+ void unlock();
+};
+
+}}
+
+# if defined(BOOST_MSVC)
+# pragma warning(pop)
+# endif
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_FIBERS_TIMED_MUTEX_H
diff --git a/src/mutex.cpp b/src/mutex.cpp
index f28759be..aa3a490a 100644
--- a/src/mutex.cpp
+++ b/src/mutex.cpp
@@ -84,7 +84,11 @@ mutex::lock()
bool
mutex::try_lock()
{
- if ( LOCKED == state_) return false;
+ if ( LOCKED == state_) {
+ // let other fiber release the lock
+ detail::scheduler::instance()->yield();
+ return false;
+ }
state_ = LOCKED;
owner_ = this_fiber::get_id();
diff --git a/src/recursive_mutex.cpp b/src/recursive_mutex.cpp
index 4a980ec5..63ff2cc8 100644
--- a/src/recursive_mutex.cpp
+++ b/src/recursive_mutex.cpp
@@ -94,7 +94,20 @@ recursive_mutex::lock()
bool
recursive_mutex::try_lock()
{
- if ( LOCKED == state_) return false;
+ if ( LOCKED == state_)
+ {
+ if ( this_fiber::get_id() == owner_)
+ {
+ ++count_;
+ return true;
+ }
+ else
+ {
+ // let other fiber release the lock
+ detail::scheduler::instance()->yield();
+ return false;
+ }
+ }
state_ = LOCKED;
owner_ = this_fiber::get_id();
diff --git a/src/recursive_timed_mutex.cpp b/src/recursive_timed_mutex.cpp
new file mode 100644
index 00000000..c2443c2b
--- /dev/null
+++ b/src/recursive_timed_mutex.cpp
@@ -0,0 +1,215 @@
+
+// Copyright Oliver Kowalke 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "boost/fiber/recursive_timed_mutex.hpp"
+
+#include
+
+#include
+
+#include "boost/fiber/detail/main_notifier.hpp"
+#include "boost/fiber/detail/scheduler.hpp"
+#include "boost/fiber/interruption.hpp"
+#include "boost/fiber/operations.hpp"
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace fibers {
+
+recursive_timed_mutex::recursive_timed_mutex() :
+ owner_(),
+ count_( 0),
+ state_( UNLOCKED),
+ waiting_()
+{}
+
+recursive_timed_mutex::~recursive_timed_mutex()
+{
+ BOOST_ASSERT( ! owner_);
+ BOOST_ASSERT( 0 == count_);
+ BOOST_ASSERT( waiting_.empty() );
+}
+
+void
+recursive_timed_mutex::lock()
+{
+ if ( LOCKED == state_ && this_fiber::get_id() == owner_)
+ {
+ ++count_;
+ return;
+ }
+
+ while ( LOCKED == state_)
+ {
+ detail::notify::ptr_t n( detail::scheduler::instance()->active() );
+ try
+ {
+ if ( n)
+ {
+ // store this fiber in order to be notified later
+ waiting_.push_back( n);
+
+ // suspend this fiber
+ detail::scheduler::instance()->wait();
+ }
+ else
+ {
+ // notifier for main-fiber
+ detail::main_notifier mn;
+ n = detail::main_notifier::make_pointer( mn);
+
+ // store this fiber in order to be notified later
+ waiting_.push_back( n);
+
+ // wait until main-fiber gets notified
+ while ( ! n->is_ready() )
+ {
+ // run scheduler
+ detail::scheduler::instance()->run();
+ }
+ }
+ }
+ catch (...)
+ {
+ // remove fiber from waiting_
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+ throw;
+ }
+ }
+ BOOST_ASSERT( ! owner_);
+ BOOST_ASSERT( 0 == count_);
+
+ state_ = LOCKED;
+ owner_ = this_fiber::get_id();
+ ++count_;
+}
+
+bool
+recursive_timed_mutex::try_lock()
+{
+ if ( LOCKED == state_)
+ {
+ if ( this_fiber::get_id() == owner_)
+ {
+ ++count_;
+ return true;
+ }
+ else
+ {
+ // let other fiber release the lock
+ detail::scheduler::instance()->yield();
+ return false;
+ }
+ }
+
+ state_ = LOCKED;
+ owner_ = this_fiber::get_id();
+ ++count_;
+ return true;
+}
+
+bool
+recursive_timed_mutex::try_lock_until( clock_type::time_point const& timeout_time)
+{
+ if ( LOCKED == state_ && this_fiber::get_id() == owner_)
+ {
+ ++count_;
+ return true;
+ }
+
+ while ( LOCKED == state_ && clock_type::now() < timeout_time)
+ {
+ detail::notify::ptr_t n( detail::scheduler::instance()->active() );
+ try
+ {
+ if ( n)
+ {
+ // store this fiber in order to be notified later
+ waiting_.push_back( n);
+
+ // suspend this fiber until notified or timed-out
+ if ( ! detail::scheduler::instance()->wait_until( timeout_time) )
+ // remove fiber from waiting-list
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+ }
+ else
+ {
+ // notifier for main-fiber
+ detail::main_notifier mn;
+ n = detail::main_notifier::make_pointer( mn);
+
+ // store this fiber in order to be notified later
+ waiting_.push_back( n);
+
+ // wait until main-fiber gets notified
+ while ( ! n->is_ready() )
+ {
+ if ( ! ( clock_type::now() < timeout_time) )
+ {
+ // remove fiber from waiting-list
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+ break;
+ }
+ // run scheduler
+ detail::scheduler::instance()->run();
+ }
+ }
+ }
+ catch (...)
+ {
+ // remove fiber from waiting-list
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+ throw;
+ }
+ }
+
+ if ( LOCKED == state_) return false;
+
+ BOOST_ASSERT( ! owner_);
+ BOOST_ASSERT( 0 == count_);
+
+ state_ = LOCKED;
+ owner_ = this_fiber::get_id();
+ ++count_;
+
+ return true;
+}
+
+void
+recursive_timed_mutex::unlock()
+{
+ BOOST_ASSERT( LOCKED == state_);
+ BOOST_ASSERT( this_fiber::get_id() == owner_);
+
+ if ( 0 == --count_)
+ {
+ detail::notify::ptr_t n;
+
+ if ( ! waiting_.empty() ) {
+ n.swap( waiting_.front() );
+ waiting_.pop_front();
+ }
+
+ state_ = UNLOCKED;
+ owner_ = detail::fiber_base::id();
+
+ if ( n)
+ n->set_ready();
+ }
+}
+
+}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
diff --git a/src/round_robin.cpp b/src/round_robin.cpp
index f1f29831..8127938a 100644
--- a/src/round_robin.cpp
+++ b/src/round_robin.cpp
@@ -36,13 +36,11 @@ round_robin::round_robin() BOOST_NOEXCEPT :
round_robin::~round_robin() BOOST_NOEXCEPT
{
-#if 0
- BOOST_FOREACH( detail::fiber_base::ptr_t const& p, rqueue_)
- { p->release(); }
-
- BOOST_FOREACH( detail::fiber_base::ptr_t const& p, wqueue_)
- { p->release(); }
-#endif
+ // fibers will be destroyed (stack-unwinding)
+ // if last reference goes out-of-scope
+ // therefore destructing wqueue_ && rqueue_
+ // will destroy the fibers in this scheduler
+ // if not referenced on other places
if ( detail::scheduler::instance() == this)
detail::scheduler::replace( 0);
}
@@ -91,7 +89,7 @@ round_robin::run()
BOOST_ASSERT( ! f->is_terminated() );
// set fiber to state_ready if dead-line was reached
- if ( s.tp <= chrono::system_clock::now() )
+ if ( s.tp <= clock_type::now() )
f->set_ready();
// set fiber to state_ready if interruption was requested
if ( f->interruption_requested() )
@@ -126,18 +124,20 @@ round_robin::run()
void
round_robin::wait()
-{ timed_wait( chrono::system_clock::time_point() ); }
+{ wait_until( clock_type::time_point( (clock_type::duration::max)() ) ); }
-void
-round_robin::timed_wait( chrono::system_clock::time_point const& abs_time)
+bool
+round_robin::wait_until( clock_type::time_point const& timeout_time)
{
+ clock_type::time_point start( clock_type::now() );
+
BOOST_ASSERT( active_fiber_);
BOOST_ASSERT( active_fiber_->is_running() );
// set active fiber to state_waiting
active_fiber_->set_waiting();
// push active fiber to wqueue_
- wqueue_.push_back( schedulable( active_fiber_, abs_time) );
+ wqueue_.push_back( schedulable( active_fiber_, timeout_time) );
// store active fiber in local var
detail::fiber_base::ptr_t tmp = active_fiber_;
// suspend active fiber
@@ -146,6 +146,8 @@ round_robin::timed_wait( chrono::system_clock::time_point const& abs_time)
BOOST_ASSERT( tmp == active_fiber_);
BOOST_ASSERT( active_fiber_->is_running() );
+
+ return clock_type::now() < timeout_time;
}
void
diff --git a/src/timed_mutex.cpp b/src/timed_mutex.cpp
new file mode 100644
index 00000000..21131a75
--- /dev/null
+++ b/src/timed_mutex.cpp
@@ -0,0 +1,184 @@
+
+// Copyright Oliver Kowalke 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "boost/fiber/timed_mutex.hpp"
+
+#include
+
+#include
+
+#include "boost/fiber/detail/main_notifier.hpp"
+#include "boost/fiber/detail/scheduler.hpp"
+#include "boost/fiber/interruption.hpp"
+#include "boost/fiber/operations.hpp"
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace fibers {
+
+timed_mutex::timed_mutex() :
+ owner_(),
+ state_( UNLOCKED),
+ waiting_()
+{}
+
+timed_mutex::~timed_mutex()
+{
+ BOOST_ASSERT( ! owner_);
+ BOOST_ASSERT( waiting_.empty() );
+}
+
+void
+timed_mutex::lock()
+{
+ while ( LOCKED == state_)
+ {
+ detail::notify::ptr_t n( detail::scheduler::instance()->active() );
+ try
+ {
+ if ( n)
+ {
+ // store this fiber in order to be notified later
+ waiting_.push_back( n);
+
+ // suspend this fiber
+ detail::scheduler::instance()->wait();
+ }
+ else
+ {
+ // notifier for main-fiber
+ detail::main_notifier mn;
+ n = detail::main_notifier::make_pointer( mn);
+
+ // store this fiber in order to be notified later
+ waiting_.push_back( n);
+
+ // wait until main-fiber gets notified
+ while ( ! n->is_ready() )
+ {
+ // run scheduler
+ detail::scheduler::instance()->run();
+ }
+ }
+ }
+ catch (...)
+ {
+ // remove fiber from waiting_
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+ throw;
+ }
+ }
+ BOOST_ASSERT( ! owner_);
+
+ state_ = LOCKED;
+ owner_ = this_fiber::get_id();
+}
+
+bool
+timed_mutex::try_lock()
+{
+ if ( LOCKED == state_) {
+ // let other fiber release the lock
+ detail::scheduler::instance()->yield();
+ return false;
+ }
+
+ state_ = LOCKED;
+ owner_ = this_fiber::get_id();
+ return true;
+}
+
+bool
+timed_mutex::try_lock_until( clock_type::time_point const& timeout_time)
+{
+ while ( LOCKED == state_ && clock_type::now() < timeout_time)
+ {
+ detail::notify::ptr_t n( detail::scheduler::instance()->active() );
+ try
+ {
+ if ( n)
+ {
+ // store this fiber in order to be notified later
+ waiting_.push_back( n);
+
+ // suspend this fiber until notified or timed-out
+ if ( ! detail::scheduler::instance()->wait_until( timeout_time) )
+ // remove fiber from waiting-list
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+ }
+ else
+ {
+ // notifier for main-fiber
+ detail::main_notifier mn;
+ n = detail::main_notifier::make_pointer( mn);
+
+ // store this fiber in order to be notified later
+ waiting_.push_back( n);
+
+ // wait until main-fiber gets notified
+ while ( ! n->is_ready() )
+ {
+ if ( ! ( clock_type::now() < timeout_time) )
+ {
+ // remove fiber from waiting-list
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+ break;
+ }
+ // run scheduler
+ detail::scheduler::instance()->run();
+ }
+ }
+ }
+ catch (...)
+ {
+ // remove fiber from waiting-list
+ waiting_.erase(
+ std::find( waiting_.begin(), waiting_.end(), n) );
+ throw;
+ }
+ }
+
+ if ( LOCKED == state_) return false;
+
+ BOOST_ASSERT( ! owner_);
+
+ state_ = LOCKED;
+ owner_ = this_fiber::get_id();
+
+ return true;
+}
+
+void
+timed_mutex::unlock()
+{
+ BOOST_ASSERT( LOCKED == state_);
+ BOOST_ASSERT( this_fiber::get_id() == owner_);
+
+ detail::notify::ptr_t n;
+
+ if ( ! waiting_.empty() ) {
+ n.swap( waiting_.front() );
+ waiting_.pop_front();
+ }
+
+ state_ = UNLOCKED;
+ owner_ = detail::fiber_base::id();
+
+ if ( n)
+ n->set_ready();
+}
+
+}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index a39413ea..d1fa5801 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -12,6 +12,7 @@ project boost/fiber/test
../../test/build//boost_unit_test_framework
/boost/fiber//boost_fibers
/boost/system//boost_system
+ /boost/thread//boost_thread
static
multi
;
diff --git a/test/test_condition.cpp b/test/test_condition.cpp
index 53c3e362..993aa9f5 100644
--- a/test/test_condition.cpp
+++ b/test/test_condition.cpp
@@ -3,6 +3,8 @@
// 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)
+//
+// This test is based on the tests of Boost.Thread
#include
#include
@@ -21,6 +23,9 @@
#include
+typedef boost::chrono::nanoseconds ns;
+typedef boost::chrono::milliseconds ms;
+
int value = 0;
inline
@@ -86,125 +91,6 @@ void wait_fn(
++value;
}
-void condition_test_waits( condition_test_data * data)
-{
- boost::fibers::mutex::scoped_lock lock( data->mutex);
- BOOST_CHECK( lock ? true : false);
-
- // Test wait.
- while ( data->notified != 1)
- {
- data->condition.wait(lock);
- }
- BOOST_CHECK(lock ? true : false);
- BOOST_CHECK_EQUAL(data->notified, 1);
- data->awoken++;
- data->condition.notify_one();
-
- while ( data->notified != 2)
- {
- data->condition.wait(lock);
- }
- BOOST_CHECK(lock ? true : false);
- BOOST_CHECK_EQUAL(data->notified, 2);
- data->awoken++;
- data->condition.notify_one();
-
- // Test predicate wait.
-// data->condition.wait(lock, cond_predicate(data->notified, 2));
-// BOOST_CHECK(lock ? true : false);
-// BOOST_CHECK_EQUAL(data->notified, 2);
-// data->awoken++;
-// data->condition.notify_one();
-#if 0
- // Test timed_wait.
- boost::chrono::system_clock::time_point xt = delay(10);
- while (data->notified != 3)
- data->condition.wait(lock);
- //data->condition.timed_wait(lock, xt);
- BOOST_CHECK(lock ? true : false);
- BOOST_CHECK_EQUAL(data->notified, 3);
- data->awoken++;
- data->condition.notify_one();
-
- // Test predicate timed_wait.
- xt = delay(10);
- cond_predicate pred(data->notified, 4);
- BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
- BOOST_CHECK(lock ? true : false);
- BOOST_CHECK(pred());
- BOOST_CHECK_EQUAL(data->notified, 4);
- data->awoken++;
- data->condition.notify_one();
-
- // Test predicate timed_wait with relative timeout
- cond_predicate pred_rel(data->notified, 5);
- BOOST_CHECK(data->condition.timed_wait(lock, boost::chrono::seconds(10), pred_rel));
- BOOST_CHECK(lock ? true : false);
- BOOST_CHECK(pred_rel());
- BOOST_CHECK_EQUAL(data->notified, 5);
- data->awoken++;
- data->condition.notify_one();
-
- // Test timeout timed_wait.
- BOOST_CHECK(!data->condition.timed_wait(lock, boost::chrono::seconds(2)));
- BOOST_CHECK(lock ? true : false);
-#endif
-}
-
-void do_test_condition_waits()
-{
- condition_test_data data;
-
- boost::fibers::fiber s(
- boost::bind( & condition_test_waits, & data) );
-
- {
- boost::fibers::mutex::scoped_lock lock( data.mutex);
- BOOST_CHECK(lock ? true : false);
-
- data.notified++;
- data.condition.notify_one();
- while (data.awoken != 1)
- data.condition.wait(lock);
- BOOST_CHECK(lock ? true : false);
- BOOST_CHECK_EQUAL(data.awoken, 1);
-
- data.notified++;
- data.condition.notify_one();
- while (data.awoken != 2)
- data.condition.wait(lock);
- BOOST_CHECK(lock ? true : false);
- BOOST_CHECK_EQUAL(data.awoken, 2);
-#if 0
- data.notified++;
- data.condition.notify_one();
- while (data.awoken != 3)
- data.condition.wait(lock);
- BOOST_CHECK(lock ? true : false);
- BOOST_CHECK_EQUAL(data.awoken, 3);
-
- data.notified++;
- data.condition.notify_one();
- while (data.awoken != 4)
- data.condition.wait(lock);
- BOOST_CHECK(lock ? true : false);
- BOOST_CHECK_EQUAL(data.awoken, 4);
-
- data.notified++;
- data.condition.notify_one();
- while (data.awoken != 5)
- data.condition.wait(lock);
- BOOST_CHECK(lock ? true : false);
- BOOST_CHECK_EQUAL(data.awoken, 5);
-#endif
- }
-
- s.join();
-
- BOOST_CHECK_EQUAL(data.awoken, 2);
-}
-
void test_condition_wait_is_a_interruption_point()
{
boost::fibers::round_robin ds;
@@ -346,12 +232,333 @@ void test_two_waiter_notify_all()
BOOST_CHECK_EQUAL( 3, value);
}
-void test_condition_waits()
+int test1 = 0;
+int test2 = 0;
+
+int runs = 0;
+
+void fn1( boost::fibers::mutex & m, boost::fibers::condition_variable & cv)
+{
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ BOOST_CHECK(test2 == 0);
+ test1 = 1;
+ cv.notify_one();
+ while (test2 == 0) {
+ cv.wait(lk);
+ }
+ BOOST_CHECK(test2 != 0);
+}
+
+void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable & cv)
+{
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ BOOST_CHECK(test2 == 0);
+ test1 = 1;
+ cv.notify_one();
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ boost::fibers::clock_type::time_point t = t0 + ms(250);
+ int count=0;
+ while (test2 == 0 && cv.wait_until(lk, t) == boost::fibers::cv_status::no_timeout)
+ count++;
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ if (runs == 0)
+ {
+ BOOST_CHECK(t1 - t0 < ms(250));
+ BOOST_CHECK(test2 != 0);
+ }
+ else
+ {
+ BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+5+1000));
+ BOOST_CHECK(test2 == 0);
+ }
+ ++runs;
+}
+
+class Pred
+{
+ int & i_;
+
+public:
+ explicit Pred(int& i) :
+ i_(i)
+ {}
+
+ bool operator()()
+ { return i_ != 0; }
+};
+
+void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable & cv)
+{
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ BOOST_CHECK(test2 == 0);
+ test1 = 1;
+ cv.notify_one();
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ boost::fibers::clock_type::time_point t = t0 + ms(250);
+ bool r = cv.wait_until(lk, t, Pred(test2));
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ if (runs == 0)
+ {
+ BOOST_CHECK(t1 - t0 < ms(250));
+ BOOST_CHECK(test2 != 0);
+ BOOST_CHECK(r);
+ }
+ else
+ {
+ BOOST_CHECK(t1 - t0 - ms(250) < ms(250+2));
+ BOOST_CHECK(test2 == 0);
+ BOOST_CHECK(!r);
+ }
+ ++runs;
+}
+
+void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable & cv)
+{
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ BOOST_CHECK(test2 == 0);
+ test1 = 1;
+ cv.notify_one();
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ int count=0;
+ while (test2 == 0 && cv.wait_for(lk, ms(250)) == boost::fibers::cv_status::no_timeout)
+ count++;
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ if (runs == 0)
+ {
+ BOOST_CHECK(t1 - t0 < ms(250));
+ BOOST_CHECK(test2 != 0);
+ }
+ else
+ {
+ BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+5+1000));
+ BOOST_CHECK(test2 == 0);
+ }
+ ++runs;
+}
+
+void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable & cv)
+{
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ BOOST_CHECK(test2 == 0);
+ test1 = 1;
+ cv.notify_one();
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ int count=0;
+ cv.wait_for(lk, ms(250), Pred(test2));
+ count++;
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ if (runs == 0)
+ {
+ BOOST_CHECK(t1 - t0 < ms(250+1000));
+ BOOST_CHECK(test2 != 0);
+ }
+ else
+ {
+ BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+2));
+ BOOST_CHECK(test2 == 0);
+ }
+ ++runs;
+}
+
+void do_test_condition_wait()
+{
+ test1 = 0;
+ test2 = 0;
+ runs = 0;
+
+ boost::fibers::mutex m;
+ boost::fibers::condition_variable cv;
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ boost::fibers::fiber f( boost::bind( & fn1, boost::ref( m), boost::ref( cv) ) );
+ BOOST_CHECK(test1 == 0);
+ while (test1 == 0)
+ cv.wait(lk);
+ BOOST_CHECK(test1 != 0);
+ test2 = 1;
+ lk.unlock();
+ cv.notify_one();
+ f.join();
+}
+
+void test_condition_wait()
{
boost::fibers::round_robin ds;
boost::fibers::scheduling_algorithm( & ds);
- do_test_condition_waits();
+ boost::fibers::fiber( & do_test_condition_wait).join();
+ do_test_condition_wait();
+}
+
+void do_test_condition_wait_until()
+{
+ test1 = 0;
+ test2 = 0;
+ runs = 0;
+
+ boost::fibers::mutex m;
+ boost::fibers::condition_variable cv;
+ {
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ boost::fibers::fiber f( boost::bind( & fn2, boost::ref( m), boost::ref( cv) ) );
+ BOOST_CHECK(test1 == 0);
+ while (test1 == 0)
+ cv.wait(lk);
+ BOOST_CHECK(test1 != 0);
+ test2 = 1;
+ lk.unlock();
+ cv.notify_one();
+ f.join();
+ }
+ test1 = 0;
+ test2 = 0;
+ {
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ boost::fibers::fiber f( boost::bind( & fn2, boost::ref( m), boost::ref( cv) ) );
+ BOOST_CHECK(test1 == 0);
+ while (test1 == 0)
+ cv.wait(lk);
+ BOOST_CHECK(test1 != 0);
+ lk.unlock();
+ f.join();
+ }
+}
+
+void test_condition_wait_until()
+{
+ boost::fibers::round_robin ds;
+ boost::fibers::scheduling_algorithm( & ds);
+
+ boost::fibers::fiber( & do_test_condition_wait_until).join();
+ do_test_condition_wait_until();
+}
+
+void do_test_condition_wait_until_pred()
+{
+ test1 = 0;
+ test2 = 0;
+ runs = 0;
+
+ boost::fibers::mutex m;
+ boost::fibers::condition_variable cv;
+ {
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ boost::fibers::fiber f( boost::bind( & fn3, boost::ref( m), boost::ref( cv) ) );
+ BOOST_CHECK(test1 == 0);
+ while (test1 == 0)
+ cv.wait(lk);
+ BOOST_CHECK(test1 != 0);
+ test2 = 1;
+ lk.unlock();
+ cv.notify_one();
+ f.join();
+ }
+ test1 = 0;
+ test2 = 0;
+ {
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ boost::fibers::fiber f( boost::bind( & fn3, boost::ref( m), boost::ref( cv) ) );
+ BOOST_CHECK(test1 == 0);
+ while (test1 == 0)
+ cv.wait(lk);
+ BOOST_CHECK(test1 != 0);
+ lk.unlock();
+ f.join();
+ }
+}
+
+void test_condition_wait_until_pred()
+{
+ boost::fibers::round_robin ds;
+ boost::fibers::scheduling_algorithm( & ds);
+
+ boost::fibers::fiber( & do_test_condition_wait_until_pred).join();
+ do_test_condition_wait_until_pred();
+}
+
+void do_test_condition_wait_for()
+{
+ test1 = 0;
+ test2 = 0;
+ runs = 0;
+
+ boost::fibers::mutex m;
+ boost::fibers::condition_variable cv;
+ {
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ boost::fibers::fiber f( boost::bind( & fn4, boost::ref( m), boost::ref( cv) ) );
+ BOOST_CHECK(test1 == 0);
+ while (test1 == 0)
+ cv.wait(lk);
+ BOOST_CHECK(test1 != 0);
+ test2 = 1;
+ lk.unlock();
+ cv.notify_one();
+ f.join();
+ }
+ test1 = 0;
+ test2 = 0;
+ {
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ boost::fibers::fiber f( boost::bind( & fn4, boost::ref( m), boost::ref( cv) ) );
+ BOOST_CHECK(test1 == 0);
+ while (test1 == 0)
+ cv.wait(lk);
+ BOOST_CHECK(test1 != 0);
+ lk.unlock();
+ f.join();
+ }
+}
+
+void test_condition_wait_for()
+{
+ boost::fibers::round_robin ds;
+ boost::fibers::scheduling_algorithm( & ds);
+
+ boost::fibers::fiber( & do_test_condition_wait_for).join();
+ do_test_condition_wait_for();
+}
+
+void do_test_condition_wait_for_pred()
+{
+ test1 = 0;
+ test2 = 0;
+ runs = 0;
+
+ boost::fibers::mutex m;
+ boost::fibers::condition_variable cv;
+ {
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ boost::fibers::fiber f( boost::bind( & fn5, boost::ref( m), boost::ref( cv) ) );
+ BOOST_CHECK(test1 == 0);
+ while (test1 == 0)
+ cv.wait(lk);
+ BOOST_CHECK(test1 != 0);
+ test2 = 1;
+ lk.unlock();
+ cv.notify_one();
+ f.join();
+ }
+ test1 = 0;
+ test2 = 0;
+ {
+ boost::unique_lock< boost::fibers::mutex > lk( m);
+ boost::fibers::fiber f( boost::bind( & fn5, boost::ref( m), boost::ref( cv) ) );
+ BOOST_CHECK(test1 == 0);
+ while (test1 == 0)
+ cv.wait(lk);
+ BOOST_CHECK(test1 != 0);
+ lk.unlock();
+ f.join();
+ }
+}
+
+void test_condition_wait_for_pred()
+{
+ boost::fibers::round_robin ds;
+ boost::fibers::scheduling_algorithm( & ds);
+
+ boost::fibers::fiber( & do_test_condition_wait_for_pred).join();
+ do_test_condition_wait_for_pred();
}
boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
@@ -362,8 +569,12 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
test->add( BOOST_TEST_CASE( & test_one_waiter_notify_one) );
test->add( BOOST_TEST_CASE( & test_two_waiter_notify_one) );
test->add( BOOST_TEST_CASE( & test_two_waiter_notify_all) );
- test->add( BOOST_TEST_CASE( & test_condition_waits) );
- test->add( BOOST_TEST_CASE( & test_condition_wait_is_a_interruption_point) );
+ test->add( BOOST_TEST_CASE( & test_condition_wait) );
+ test->add( BOOST_TEST_CASE( & test_condition_wait_is_a_interruption_point) );
+ test->add( BOOST_TEST_CASE( & test_condition_wait_until) );
+ test->add( BOOST_TEST_CASE( & test_condition_wait_until_pred) );
+ test->add( BOOST_TEST_CASE( & test_condition_wait_for) );
+ test->add( BOOST_TEST_CASE( & test_condition_wait_for_pred) );
return test;
}
diff --git a/test/test_mutex.cpp b/test/test_mutex.cpp
index 6f8b0b64..4d515ec2 100644
--- a/test/test_mutex.cpp
+++ b/test/test_mutex.cpp
@@ -13,13 +13,206 @@
#include
#include
+#include
#include
#include
#include
+#include
#include
#include
+typedef boost::chrono::nanoseconds ns;
+typedef boost::chrono::milliseconds ms;
+
+int value1 = 0;
+int value2 = 0;
+
+template< typename M >
+void fn1( M & mtx)
+{
+ typedef M mutex_type;
+ typename mutex_type::scoped_lock lk( mtx);
+ ++value1;
+ for ( int i = 0; i < 3; ++i)
+ boost::this_fiber::yield();
+}
+
+template< typename M >
+void fn2( M & mtx)
+{
+ typedef M mutex_type;
+ ++value2;
+ typename mutex_type::scoped_lock lk( mtx);
+ ++value2;
+}
+
+void fn3( boost::fibers::timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ m.lock();
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms
+}
+
+void fn4( boost::fibers::timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ while ( ! m.try_lock() );
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
+}
+
+void fn5( boost::fibers::timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ BOOST_CHECK( m.try_lock_for(ms(300)+ms(2000)) == true);
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
+}
+
+void fn6( boost::fibers::timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ BOOST_CHECK(m.try_lock_for(ms(250)) == false);
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms
+}
+
+void fn7( boost::fibers::timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ BOOST_CHECK(m.try_lock_until(boost::fibers::clock_type::now() + ms(300) + ms(1000)) == true);
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5ms
+}
+
+void fn8( boost::fibers::timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ BOOST_CHECK(m.try_lock_until(boost::fibers::clock_type::now() + ms(250)) == false);
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5ms
+}
+
+void fn9( boost::fibers::recursive_timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ m.lock();
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ m.lock();
+ m.unlock();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms
+}
+
+void fn10( boost::fibers::recursive_timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ while (!m.try_lock()) ;
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ BOOST_CHECK(m.try_lock());
+ m.unlock();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(50000000)+ms(1000)); // within 50 ms
+}
+
+void fn11( boost::fibers::recursive_timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ BOOST_CHECK(m.try_lock_for(ms(300)+ms(1000)) == true);
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ BOOST_CHECK(m.try_lock());
+ m.unlock();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms
+}
+
+void fn12( boost::fibers::recursive_timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ BOOST_CHECK(m.try_lock_for(ms(250)) == false);
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms
+}
+
+void fn13( boost::fibers::recursive_timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ BOOST_CHECK(m.try_lock_until(boost::fibers::clock_type::now() + ms(300) + ms(1000)) == true);
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms
+}
+
+void fn14( boost::fibers::recursive_timed_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ BOOST_CHECK(m.try_lock_until(boost::fibers::clock_type::now() + ms(250)) == false);
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(5000000)+ms(1000)); // within 5 ms
+}
+
+void fn15( boost::fibers::recursive_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ m.lock();
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ m.lock();
+ m.unlock();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms
+}
+
+void fn16( boost::fibers::recursive_mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ while (!m.try_lock());
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ BOOST_CHECK(m.try_lock());
+ m.unlock();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(50000000)+ms(1000)); // within 50 ms
+}
+
+void fn17( boost::fibers::mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ m.lock();
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(2500000)+ms(1000)); // within 2.5 ms
+}
+
+void fn18( boost::fibers::mutex & m)
+{
+ boost::fibers::clock_type::time_point t0 = boost::fibers::clock_type::now();
+ while (!m.try_lock()) ;
+ boost::fibers::clock_type::time_point t1 = boost::fibers::clock_type::now();
+ m.unlock();
+ ns d = t1 - t0 - ms(250);
+ BOOST_CHECK(d < ns(50000000)+ms(1000)); // within 50 ms
+}
+
template< typename M >
struct test_lock
{
@@ -45,51 +238,36 @@ struct test_lock
BOOST_CHECK(lk ? true : false);
}
};
-#if 0
+
template< typename M >
-struct test_trylock
+struct test_exclusive
{
typedef M mutex_type;
- typedef typename M::scoped_try_lock try_lock_type;
+ typedef typename M::scoped_lock lock_type;
void operator()()
{
- mutex_type mutex;
- boost::fibers::condition condition;
+ value1 = 0;
+ value2 = 0;
+ BOOST_CHECK_EQUAL( 0, value1);
+ BOOST_CHECK_EQUAL( 0, value2);
- // Test the lock's constructors.
- {
- try_lock_type lock(mutex);
- BOOST_CHECK(lock ? true : false);
- }
- {
- try_lock_type lock(mutex, boost::defer_lock);
- BOOST_CHECK(!lock);
- }
- try_lock_type lock(mutex);
- BOOST_CHECK(lock ? true : false);
+ mutex_type mtx;
+ boost::fibers::fiber f1(
+ boost::bind( & fn1< mutex_type >, boost::ref( mtx) ) );
+ boost::fibers::fiber f2(
+ boost::bind( & fn2< mutex_type >, boost::ref( mtx) ) );
+ BOOST_ASSERT( f1);
+ BOOST_ASSERT( f2);
+ BOOST_CHECK_EQUAL( 1, value1);
+ BOOST_CHECK_EQUAL( 1, value2);
- // Construct and initialize an xtime for a fast time out.
- boost::xtime xt = delay(0, 100);
-
- // Test the lock and the mutex with condition variables.
- // No one is going to notify this condition variable. We expect to
- // time out.
- BOOST_CHECK(!condition.timed_wait(lock, xt));
- BOOST_CHECK(lock ? true : false);
-
- // Test the lock, unlock and trylock methods.
- lock.unlock();
- BOOST_CHECK(!lock);
- lock.lock();
- BOOST_CHECK(lock ? true : false);
- lock.unlock();
- BOOST_CHECK(!lock);
- BOOST_CHECK(lock.try_lock());
- BOOST_CHECK(lock ? true : false);
+ f1.join();
+ f2.join();
+ BOOST_CHECK_EQUAL( 1, value1);
+ BOOST_CHECK_EQUAL( 2, value2);
}
};
-#endif
template< typename M >
struct test_recursive_lock
@@ -108,66 +286,58 @@ struct test_recursive_lock
void do_test_mutex()
{
test_lock< boost::fibers::mutex >()();
+ test_exclusive< boost::fibers::mutex >()();
+
+ {
+ boost::fibers::mutex mtx;
+ mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn17, boost::ref( mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::mutex mtx;
+ mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn18, boost::ref( mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ mtx.unlock();
+ f.join();
+ }
}
-int value1 = 0;
-int value2 = 0;
-
-void fn1( boost::fibers::mutex & mtx)
-{
- boost::fibers::mutex::scoped_lock lk( mtx);
- ++value1;
- for ( int i = 0; i < 3; ++i)
- boost::this_fiber::yield();
-}
-
-void fn2( boost::fibers::mutex & mtx)
-{
- ++value2;
- boost::fibers::mutex::scoped_lock lk( mtx);
- ++value2;
-}
-
-void test_locking()
+void test_mutex()
{
boost::fibers::round_robin ds;
boost::fibers::scheduling_algorithm( & ds);
- boost::fibers::fiber s( & do_test_mutex);
- s.join();
- BOOST_ASSERT( ! s);
-}
-
-void test_exclusive()
-{
- boost::fibers::round_robin ds;
- boost::fibers::scheduling_algorithm( & ds);
-
- value1 = 0;
- value2 = 0;
- BOOST_CHECK_EQUAL( 0, value1);
- BOOST_CHECK_EQUAL( 0, value2);
-
- boost::fibers::mutex mtx;
- boost::fibers::fiber s1(
- boost::bind( & fn1, boost::ref( mtx) ) );
- boost::fibers::fiber s2(
- boost::bind( & fn2, boost::ref( mtx) ) );
- BOOST_ASSERT( s1);
- BOOST_ASSERT( s2);
- BOOST_CHECK_EQUAL( 1, value1);
- BOOST_CHECK_EQUAL( 1, value2);
-
- s1.join();
- s2.join();
- BOOST_CHECK_EQUAL( 1, value1);
- BOOST_CHECK_EQUAL( 2, value2);
+ boost::fibers::fiber( & do_test_mutex).join();
}
void do_test_recursive_mutex()
{
test_lock< boost::fibers::recursive_mutex >()();
+ test_exclusive< boost::fibers::recursive_mutex >()();
test_recursive_lock< boost::fibers::recursive_mutex >()();
+
+ {
+ boost::fibers::recursive_mutex mtx;
+ mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn15, boost::ref( mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::recursive_mutex mtx;
+ mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn16, boost::ref( mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ mtx.unlock();
+ f.join();
+ }
}
void test_recursive_mutex()
@@ -178,19 +348,141 @@ void test_recursive_mutex()
boost::fibers::fiber( do_test_recursive_mutex).join();
}
-void do_test_recursive_try_mutex()
+void do_test_timed_mutex()
{
- test_lock< boost::fibers::recursive_try_mutex >()();
- //test_trylock< boost::fibers::recursive_try_mutex >()();
- test_recursive_lock< boost::fibers::recursive_try_mutex >()();
+ test_lock< boost::fibers::timed_mutex >()();
+ test_exclusive< boost::fibers::timed_mutex >()();
+
+ {
+ boost::fibers::timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn3, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ timed_mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn4, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ timed_mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn5, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ timed_mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn6, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(300) );
+ timed_mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn7, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ timed_mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn8, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(300) + ms(1000) );
+ timed_mtx.unlock();
+ f.join();
+ }
}
-void test_recursive_try_mutex()
+void test_timed_mutex()
{
boost::fibers::round_robin ds;
boost::fibers::scheduling_algorithm( & ds);
- boost::fibers::fiber( do_test_recursive_try_mutex).join();
+ boost::fibers::fiber( & do_test_timed_mutex).join();
+}
+
+void do_test_recursive_timed_mutex()
+{
+ test_lock< boost::fibers::recursive_timed_mutex >()();
+ test_exclusive< boost::fibers::recursive_timed_mutex >()();
+ test_recursive_lock< boost::fibers::recursive_timed_mutex >()();
+
+ {
+ boost::fibers::recursive_timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn9, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ timed_mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::recursive_timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn10, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ timed_mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::recursive_timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn11, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ timed_mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::recursive_timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn12, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(400) );
+ timed_mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::recursive_timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn13, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(250) );
+ timed_mtx.unlock();
+ f.join();
+ }
+
+ {
+ boost::fibers::recursive_timed_mutex timed_mtx;
+ timed_mtx.lock();
+ boost::fibers::fiber f( boost::bind( & fn14, boost::ref( timed_mtx) ) );
+ boost::this_fiber::sleep_for( ms(300) );
+ timed_mtx.unlock();
+ f.join();
+ }
+}
+
+void test_recursive_timed_mutex()
+{
+ boost::fibers::round_robin ds;
+ boost::fibers::scheduling_algorithm( & ds);
+
+ boost::fibers::fiber( & do_test_recursive_timed_mutex).join();
}
boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
@@ -198,10 +490,10 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
boost::unit_test::test_suite * test =
BOOST_TEST_SUITE("Boost.Fiber: mutex test suite");
- test->add( BOOST_TEST_CASE( & test_locking) );
- test->add( BOOST_TEST_CASE( & test_exclusive) );
+ test->add( BOOST_TEST_CASE( & test_mutex) );
test->add( BOOST_TEST_CASE( & test_recursive_mutex) );
- test->add( BOOST_TEST_CASE( & test_recursive_try_mutex) );
+ test->add( BOOST_TEST_CASE( & test_timed_mutex) );
+ test->add( BOOST_TEST_CASE( & test_recursive_timed_mutex) );
return test;
}