From bf46b2ee9603d22d48b259df98cd196134e28f2e Mon Sep 17 00:00:00 2001 From: Nicola Musatti Date: Sat, 13 Oct 2007 21:25:29 +0000 Subject: [PATCH] Merge from trunk [SVN r39987] --- build/Jamfile.v2 | 4 +- include/boost/thread/detail/move.hpp | 33 + include/boost/thread/locks.hpp | 162 ++- include/boost/thread/pthread/mutex.hpp | 10 +- .../boost/thread/pthread/recursive_mutex.hpp | 8 +- include/boost/thread/pthread/shared_mutex.hpp | 300 +++++ include/boost/thread/shared_mutex.hpp | 15 + include/boost/thread/thread_time.hpp | 2 +- include/boost/thread/win32/shared_mutex.hpp | 516 ++++++++ .../boost/thread/win32/thread_primitives.hpp | 3 +- include/boost/thread/xtime.hpp | 12 + src/condition.cpp | 13 + src/mutex.cpp | 561 --------- src/mutex.inl | 132 --- src/once.cpp | 50 - src/recursive_mutex.cpp | 1040 ----------------- src/thread.cpp | 1 + test/Jamfile.v2 | 3 +- test/test_lock_concept.cpp | 173 +++ test/test_mutex.cpp | 18 +- test/test_once.cpp | 99 ++ test/test_shared_mutex.cpp | 460 ++++++++ 22 files changed, 1746 insertions(+), 1869 deletions(-) create mode 100644 include/boost/thread/detail/move.hpp create mode 100644 include/boost/thread/pthread/shared_mutex.hpp create mode 100644 include/boost/thread/shared_mutex.hpp create mode 100644 include/boost/thread/win32/shared_mutex.hpp delete mode 100644 src/mutex.cpp delete mode 100644 src/mutex.inl delete mode 100644 src/once.cpp delete mode 100644 src/recursive_mutex.cpp create mode 100644 test/test_lock_concept.cpp create mode 100644 test/test_shared_mutex.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 2aadaf36..961e01e8 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -17,9 +17,9 @@ CPP_SOURCES = barrier condition exceptions - mutex +# mutex # once - recursive_mutex +# recursive_mutex # read_write_mutex thread tss_hooks diff --git a/include/boost/thread/detail/move.hpp b/include/boost/thread/detail/move.hpp new file mode 100644 index 00000000..ba4bb655 --- /dev/null +++ b/include/boost/thread/detail/move.hpp @@ -0,0 +1,33 @@ +// 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) +// (C) Copyright 2007 Anthony Williams + +#ifndef BOOST_THREAD_MOVE_HPP +#define BOOST_THREAD_MOVE_HPP + +namespace boost +{ + template + struct move_t + { + T& t; + move_t(T& t_): + t(t_) + {} + + T* operator->() const + { + return &t; + } + }; + + template + move_t move(T& t) + { + return move_t(t); + } +} + + +#endif diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index 258b0f60..b56c996e 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -24,13 +24,13 @@ namespace boost const adopt_lock_t adopt_lock={}; template - class shareable_lock; + class shared_lock; template class exclusive_lock; template - class upgradeable_lock; + class upgrade_lock; template class lock_guard @@ -86,21 +86,21 @@ namespace boost { timed_lock(target_time); } - unique_lock(boost::move_t other): + unique_lock(boost::move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; } - unique_lock(boost::move_t > other); + unique_lock(boost::move_t > other); - unique_lock& operator=(boost::move_t other) + unique_lock& operator=(boost::move_t > other) { unique_lock temp(other); swap(temp); return *this; } - unique_lock& operator=(boost::move_t > other) + unique_lock& operator=(boost::move_t > other) { unique_lock temp(other); swap(temp); @@ -112,7 +112,7 @@ namespace boost std::swap(m,other.m); std::swap(is_locked,other.is_locked); } - void swap(boost::move_t other) + void swap(boost::move_t > other) { std::swap(m,other->m); std::swap(is_locked,other->is_locked); @@ -170,6 +170,10 @@ namespace boost { return is_locked?&unique_lock::lock:0; } + bool operator!() const + { + return !owns_lock(); + } bool owns_lock() const { return is_locked; @@ -188,91 +192,100 @@ namespace boost return res; } - friend class shareable_lock; - friend class upgradeable_lock; + friend class shared_lock; + friend class upgrade_lock; }; template - class shareable_lock + class shared_lock { protected: Mutex* m; bool is_locked; private: - explicit shareable_lock(shareable_lock&); - shareable_lock& operator=(shareable_lock&); + explicit shared_lock(shared_lock&); + shared_lock& operator=(shared_lock&); public: - explicit shareable_lock(Mutex& m_): + explicit shared_lock(Mutex& m_): m(&m_),is_locked(false) { lock(); } - shareable_lock(Mutex& m_,bool do_lock): + shared_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + {} + shared_lock(Mutex& m_,defer_lock_t): + m(&m_),is_locked(false) + {} + shared_lock(Mutex& m_,try_to_lock_t): m(&m_),is_locked(false) { - if(do_lock) - { - lock(); - } + try_lock(); } - shareable_lock(boost::move_t other): + shared_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } + + shared_lock(boost::move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; } - shareable_lock(boost::move_t > other): + shared_lock(boost::move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; if(is_locked) { - m->unlock_and_lock_shareable(); + m->unlock_and_lock_shared(); } } - shareable_lock(boost::move_t > other): + shared_lock(boost::move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; if(is_locked) { - m->unlock_upgradeable_and_lock_shareable(); + m->unlock_upgrade_and_lock_shared(); } } - shareable_lock& operator=(boost::move_t other) + shared_lock& operator=(boost::move_t > other) { - shareable_lock temp(other); + shared_lock temp(other); swap(temp); return *this; } - shareable_lock& operator=(boost::move_t > other) + shared_lock& operator=(boost::move_t > other) { - shareable_lock temp(other); + shared_lock temp(other); swap(temp); return *this; } - shareable_lock& operator=(boost::move_t > other) + shared_lock& operator=(boost::move_t > other) { - shareable_lock temp(other); + shared_lock temp(other); swap(temp); return *this; } - void swap(shareable_lock& other) + void swap(shared_lock& other) { std::swap(m,other.m); std::swap(is_locked,other.is_locked); } - ~shareable_lock() + ~shared_lock() { if(owns_lock()) { - m->unlock_shareable(); + m->unlock_shared(); } } void lock() @@ -281,7 +294,7 @@ namespace boost { throw boost::lock_error(); } - m->lock_shareable(); + m->lock_shared(); is_locked=true; } bool try_lock() @@ -290,7 +303,16 @@ namespace boost { throw boost::lock_error(); } - is_locked=m->try_lock_shareable(); + is_locked=m->try_lock_shared(); + return is_locked; + } + bool timed_lock(boost::system_time const& target_time) + { + if(owns_lock()) + { + throw boost::lock_error(); + } + is_locked=m->timed_lock_shared(target_time); return is_locked; } void unlock() @@ -299,14 +321,18 @@ namespace boost { throw boost::lock_error(); } - m->unlock_shareable(); + m->unlock_shared(); is_locked=false; } - typedef void (shareable_lock::*bool_type)(); + typedef void (shared_lock::*bool_type)(); operator bool_type() const { - return is_locked?&shareable_lock::lock:0; + return is_locked?&shared_lock::lock:0; + } + bool operator!() const + { + return !owns_lock(); } bool owns_lock() const { @@ -316,21 +342,21 @@ namespace boost }; template - class upgradeable_lock + class upgrade_lock { protected: Mutex* m; bool is_locked; private: - explicit upgradeable_lock(upgradeable_lock&); - upgradeable_lock& operator=(upgradeable_lock&); + explicit upgrade_lock(upgrade_lock&); + upgrade_lock& operator=(upgrade_lock&); public: - explicit upgradeable_lock(Mutex& m_): + explicit upgrade_lock(Mutex& m_): m(&m_),is_locked(false) { lock(); } - upgradeable_lock(Mutex& m_,bool do_lock): + upgrade_lock(Mutex& m_,bool do_lock): m(&m_),is_locked(false) { if(do_lock) @@ -338,47 +364,47 @@ namespace boost lock(); } } - upgradeable_lock(boost::move_t other): + upgrade_lock(boost::move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; } - upgradeable_lock(boost::move_t > other): + upgrade_lock(boost::move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; if(is_locked) { - m->unlock_and_lock_upgradeable(); + m->unlock_and_lock_upgrade(); } } - upgradeable_lock& operator=(boost::move_t other) + upgrade_lock& operator=(boost::move_t > other) { - upgradeable_lock temp(other); + upgrade_lock temp(other); swap(temp); return *this; } - upgradeable_lock& operator=(boost::move_t > other) + upgrade_lock& operator=(boost::move_t > other) { - upgradeable_lock temp(other); + upgrade_lock temp(other); swap(temp); return *this; } - void swap(upgradeable_lock& other) + void swap(upgrade_lock& other) { std::swap(m,other.m); std::swap(is_locked,other.is_locked); } - ~upgradeable_lock() + ~upgrade_lock() { if(owns_lock()) { - m->unlock_upgradeable(); + m->unlock_upgrade(); } } void lock() @@ -387,7 +413,7 @@ namespace boost { throw boost::lock_error(); } - m->lock_upgradeable(); + m->lock_upgrade(); is_locked=true; } bool try_lock() @@ -396,7 +422,7 @@ namespace boost { throw boost::lock_error(); } - is_locked=m->try_lock_upgradeable(); + is_locked=m->try_lock_upgrade(); return is_locked; } void unlock() @@ -405,31 +431,35 @@ namespace boost { throw boost::lock_error(); } - m->unlock_upgradeable(); + m->unlock_upgrade(); is_locked=false; } - typedef void (upgradeable_lock::*bool_type)(); + typedef void (upgrade_lock::*bool_type)(); operator bool_type() const { - return is_locked?&upgradeable_lock::lock:0; + return is_locked?&upgrade_lock::lock:0; + } + bool operator!() const + { + return !owns_lock(); } bool owns_lock() const { return is_locked; } - friend class shareable_lock; + friend class shared_lock; friend class unique_lock; }; template - unique_lock::unique_lock(boost::move_t > other): + unique_lock::unique_lock(boost::move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; if(is_locked) { - m->unlock_upgradeable_and_lock(); + m->unlock_upgrade_and_lock(); } } @@ -437,13 +467,13 @@ namespace boost class upgrade_to_unique_lock { private: - upgradeable_lock* source; + upgrade_lock* source; unique_lock exclusive; explicit upgrade_to_unique_lock(upgrade_to_unique_lock&); upgrade_to_unique_lock& operator=(upgrade_to_unique_lock&); public: - explicit upgrade_to_unique_lock(upgradeable_lock& m_): + explicit upgrade_to_unique_lock(upgrade_lock& m_): source(&m_),exclusive(boost::move(*source)) {} ~upgrade_to_unique_lock() @@ -454,13 +484,13 @@ namespace boost } } - upgrade_to_unique_lock(boost::move_t other): + upgrade_to_unique_lock(boost::move_t > other): source(other->source),exclusive(boost::move(other->exclusive)) { other->source=0; } - upgrade_to_unique_lock& operator=(boost::move_t other) + upgrade_to_unique_lock& operator=(boost::move_t > other) { upgrade_to_unique_lock temp(other); swap(temp); @@ -476,6 +506,10 @@ namespace boost { return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0; } + bool operator!() const + { + return !owns_lock(); + } bool owns_lock() const { return exclusive.owns_lock(); diff --git a/include/boost/thread/pthread/mutex.hpp b/include/boost/thread/pthread/mutex.hpp index 09e5313b..b8b9c670 100644 --- a/include/boost/thread/pthread/mutex.hpp +++ b/include/boost/thread/pthread/mutex.hpp @@ -72,7 +72,7 @@ namespace boost { private: pthread_mutex_t m; -#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK pthread_cond_t cond; bool is_locked; @@ -103,7 +103,7 @@ namespace boost { throw thread_resource_error(); } -#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK int const res2=pthread_cond_init(&cond,NULL); if(res2) { @@ -118,7 +118,7 @@ namespace boost { int const res=pthread_mutex_destroy(&m); BOOST_ASSERT(!res); -#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK int const res2=pthread_cond_destroy(&cond); BOOST_ASSERT(!res2); #endif @@ -193,8 +193,8 @@ namespace boost pthread_mutex_scoped_lock const _(&m); while(is_locked) { - int const cond_res=pthread_cond_timewait(&cond,&m,&timeout); - if(cond_res==ETIMEOUT) + int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout); + if(cond_res==ETIMEDOUT) { return false; } diff --git a/include/boost/thread/pthread/recursive_mutex.hpp b/include/boost/thread/pthread/recursive_mutex.hpp index 2ccc3ae1..92002600 100644 --- a/include/boost/thread/pthread/recursive_mutex.hpp +++ b/include/boost/thread/pthread/recursive_mutex.hpp @@ -133,6 +133,8 @@ namespace boost int const res=pthread_mutex_init(&m,&attr); if(res) { + int const destroy_attr_res=pthread_mutexattr_destroy(&attr); + BOOST_ASSERT(!destroy_attr_res); throw thread_resource_error(); } int const destroy_attr_res=pthread_mutexattr_destroy(&attr); @@ -247,12 +249,12 @@ namespace boost if(is_locked && owner==pthread_self()) { ++count; - return; + return true; } while(is_locked) { - int const cond_res=pthread_cond_timewait(&cond,&m,&timeout); - if(cond_res==ETIMEOUT) + int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout); + if(cond_res==ETIMEDOUT) { return false; } diff --git a/include/boost/thread/pthread/shared_mutex.hpp b/include/boost/thread/pthread/shared_mutex.hpp new file mode 100644 index 00000000..673cfc00 --- /dev/null +++ b/include/boost/thread/pthread/shared_mutex.hpp @@ -0,0 +1,300 @@ +#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP + +// (C) Copyright 2006-7 Anthony Williams +// +// 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 +#include +#include +#include +#include + +namespace boost +{ + class shared_mutex + { + private: + struct state_data + { + unsigned shared_count; + bool exclusive; + bool upgrade; + bool exclusive_waiting_blocked; + }; + + + + state_data state; + boost::mutex state_change; + boost::condition shared_cond; + boost::condition exclusive_cond; + boost::condition upgrade_cond; + + void release_waiters() + { + exclusive_cond.notify_one(); + shared_cond.notify_all(); + } + + + public: + shared_mutex() + { + state_data state_={0}; + state=state_; + } + + ~shared_mutex() + { + } + + void lock_shared() + { + boost::mutex::scoped_lock lock(state_change); + + while(true) + { + if(!state.exclusive && !state.exclusive_waiting_blocked) + { + ++state.shared_count; + return; + } + + shared_cond.wait(lock); + } + } + + bool try_lock_shared() + { + boost::mutex::scoped_lock lock(state_change); + + if(state.exclusive || state.exclusive_waiting_blocked) + { + return false; + } + else + { + ++state.shared_count; + return true; + } + } + + bool timed_lock_shared(system_time const& timeout) + { + boost::mutex::scoped_lock lock(state_change); + + while(true) + { + if(!state.exclusive && !state.exclusive_waiting_blocked) + { + ++state.shared_count; + return true; + } + + if(!shared_cond.timed_wait(lock,get_xtime(timeout))) + { + return false; + } + } + } + + void unlock_shared() + { + boost::mutex::scoped_lock lock(state_change); + bool const last_reader=!--state.shared_count; + + if(last_reader) + { + if(state.upgrade) + { + state.upgrade=false; + state.exclusive=true; + upgrade_cond.notify_one(); + } + else + { + state.exclusive_waiting_blocked=false; + } + release_waiters(); + } + } + + void lock() + { + boost::mutex::scoped_lock lock(state_change); + + while(true) + { + if(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=true; + } + else + { + state.exclusive=true; + return; + } + exclusive_cond.wait(lock); + } + } + + bool timed_lock(system_time const& timeout) + { + boost::mutex::scoped_lock lock(state_change); + + while(true) + { + if(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=true; + } + else + { + state.exclusive=true; + return true; + } + if(!exclusive_cond.timed_wait(lock,get_xtime(timeout))) + { + return false; + } + } + } + + bool try_lock() + { + boost::mutex::scoped_lock lock(state_change); + + if(state.shared_count || state.exclusive) + { + return false; + } + else + { + state.exclusive=true; + return true; + } + + } + + void unlock() + { + boost::mutex::scoped_lock lock(state_change); + state.exclusive=false; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + + void lock_upgrade() + { + boost::mutex::scoped_lock lock(state_change); + while(true) + { + if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade) + { + ++state.shared_count; + state.upgrade=true; + return; + } + + shared_cond.wait(lock); + } + } + + bool timed_lock_upgrade(system_time const& timeout) + { + boost::mutex::scoped_lock lock(state_change); + while(true) + { + if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade) + { + ++state.shared_count; + state.upgrade=true; + return true; + } + + if(!shared_cond.timed_wait(lock,get_xtime(timeout))) + { + return false; + } + } + } + + bool try_lock_upgrade() + { + boost::mutex::scoped_lock lock(state_change); + if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + return false; + } + else + { + ++state.shared_count; + state.upgrade=true; + return true; + } + } + + void unlock_upgrade() + { + boost::mutex::scoped_lock lock(state_change); + state.upgrade=false; + bool const last_reader=!--state.shared_count; + + if(last_reader) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + } + } + + void unlock_upgrade_and_lock() + { + boost::mutex::scoped_lock lock(state_change); + --state.shared_count; + while(true) + { + if(!state.shared_count) + { + state.upgrade=false; + state.exclusive=true; + break; + } + upgrade_cond.wait(lock); + } + } + + void unlock_and_lock_upgrade() + { + boost::mutex::scoped_lock lock(state_change); + state.exclusive=false; + state.upgrade=true; + ++state.shared_count; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + + void unlock_and_lock_shared() + { + boost::mutex::scoped_lock lock(state_change); + state.exclusive=false; + ++state.shared_count; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + + void unlock_upgrade_and_lock_shared() + { + boost::mutex::scoped_lock lock(state_change); + state.upgrade=false; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + }; +} + + +#endif diff --git a/include/boost/thread/shared_mutex.hpp b/include/boost/thread/shared_mutex.hpp new file mode 100644 index 00000000..17f72d84 --- /dev/null +++ b/include/boost/thread/shared_mutex.hpp @@ -0,0 +1,15 @@ +#ifndef BOOST_THREAD_SHARED_MUTEX_HPP +#define BOOST_THREAD_SHARED_MUTEX_HPP + +// shared_mutex.hpp +// +// (C) Copyright 2007 Anthony Williams +// +// 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 +#include BOOST_THREAD_PLATFORM(shared_mutex.hpp) + +#endif diff --git a/include/boost/thread/thread_time.hpp b/include/boost/thread/thread_time.hpp index 8c735977..017a112f 100644 --- a/include/boost/thread/thread_time.hpp +++ b/include/boost/thread/thread_time.hpp @@ -30,7 +30,7 @@ namespace boost { return 0; } - return (target_time-now).total_milliseconds(); + return (target_time-now).total_milliseconds()+1; } } diff --git a/include/boost/thread/win32/shared_mutex.hpp b/include/boost/thread/win32/shared_mutex.hpp new file mode 100644 index 00000000..2b0cf8d8 --- /dev/null +++ b/include/boost/thread/win32/shared_mutex.hpp @@ -0,0 +1,516 @@ +#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP +#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP + +// (C) Copyright 2006-7 Anthony Williams +// +// 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 +#include +#include +#include +#include +#include +#include + +namespace boost +{ + class shared_mutex: + private boost::noncopyable + { + private: + struct state_data + { + unsigned shared_count:11; + unsigned shared_waiting:11; + unsigned exclusive:1; + unsigned upgrade:1; + unsigned exclusive_waiting:7; + unsigned exclusive_waiting_blocked:1; + + friend bool operator==(state_data const& lhs,state_data const& rhs) + { + return *reinterpret_cast(&lhs)==*reinterpret_cast(&rhs); + } + }; + + + template + T interlocked_compare_exchange(T* target,T new_value,T comparand) + { + BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long)); + long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast(target), + *reinterpret_cast(&new_value), + *reinterpret_cast(&comparand)); + return *reinterpret_cast(&res); + } + + state_data state; + void* semaphores[2]; + void* &unlock_sem; + void* &exclusive_sem; + void* upgrade_sem; + + void release_waiters(state_data old_state) + { + if(old_state.exclusive_waiting) + { + bool const success=detail::win32::ReleaseSemaphore(exclusive_sem,1,NULL)!=0; + BOOST_ASSERT(success); + } + + if(old_state.shared_waiting || old_state.exclusive_waiting) + { + bool const success=detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),NULL)!=0; + BOOST_ASSERT(success); + } + } + + + public: + shared_mutex(): + unlock_sem(semaphores[0]), + exclusive_sem(semaphores[1]) + { + unlock_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + exclusive_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + state_data state_={0}; + state=state_; + } + + ~shared_mutex() + { + detail::win32::CloseHandle(upgrade_sem); + detail::win32::CloseHandle(unlock_sem); + detail::win32::CloseHandle(exclusive_sem); + } + + bool try_lock_shared() + { + state_data old_state=state; + do + { + state_data new_state=old_state; + if(!new_state.exclusive && !new_state.exclusive_waiting_blocked) + { + ++new_state.shared_count; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + while(true); + return !(old_state.exclusive| old_state.exclusive_waiting_blocked); + } + + void lock_shared() + { + bool const success=timed_lock_shared(::boost::detail::get_system_time_sentinel()); + BOOST_ASSERT(success); + } + + bool timed_lock_shared(boost::system_time const& wait_until) + { + while(true) + { + state_data old_state=state; + do + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked) + { + ++new_state.shared_waiting; + } + else + { + ++new_state.shared_count; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + while(true); + + if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) + { + return true; + } + + unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until)); + if(res==detail::win32::timeout) + { + do + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked) + { + if(new_state.shared_waiting) + { + --new_state.shared_waiting; + } + } + else + { + ++new_state.shared_count; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + while(true); + + if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) + { + return true; + } + return false; + } + + BOOST_ASSERT(res==0); + } + } + + void unlock_shared() + { + state_data old_state=state; + do + { + state_data new_state=old_state; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + if(new_state.upgrade) + { + new_state.upgrade=false; + new_state.exclusive=true; + } + else + { + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(last_reader) + { + if(old_state.upgrade) + { + bool const success=detail::win32::ReleaseSemaphore(upgrade_sem,1,NULL)!=0; + BOOST_ASSERT(success); + } + else + { + release_waiters(old_state); + } + } + break; + } + old_state=current_state; + } + while(true); + } + + void lock() + { + bool const success=timed_lock(::boost::detail::get_system_time_sentinel()); + BOOST_ASSERT(success); + } + + bool timed_lock(boost::system_time const& wait_until) + { + while(true) + { + state_data old_state=state; + + do + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + ++new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=true; + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + while(true); + + if(!old_state.shared_count && !old_state.exclusive) + { + return true; + } + unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until)); + if(wait_res==detail::win32::timeout) + { + do + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + } + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + while(true); + if(!old_state.shared_count && !old_state.exclusive) + { + return true; + } + return false; + } + BOOST_ASSERT(wait_res<2); + } + } + + void unlock() + { + state_data old_state=state; + do + { + state_data new_state=old_state; + new_state.exclusive=false; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + while(true); + release_waiters(old_state); + } + + void lock_upgrade() + { + while(true) + { + state_data old_state=state; + do + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) + { + ++new_state.shared_waiting; + } + else + { + ++new_state.shared_count; + new_state.upgrade=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + while(true); + + if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade)) + { + return; + } + + unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite); + BOOST_ASSERT(res==0); + } + } + + void unlock_upgrade() + { + state_data old_state=state; + do + { + state_data new_state=old_state; + new_state.upgrade=false; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(last_reader) + { + release_waiters(old_state); + } + break; + } + old_state=current_state; + } + while(true); + } + + void unlock_upgrade_and_lock() + { + state_data old_state=state; + do + { + state_data new_state=old_state; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + new_state.upgrade=false; + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(!last_reader) + { + unsigned long const res=detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite); + BOOST_ASSERT(res==0); + } + break; + } + old_state=current_state; + } + while(true); + } + + void unlock_and_lock_upgrade() + { + state_data old_state=state; + do + { + state_data new_state=old_state; + new_state.exclusive=false; + new_state.upgrade=true; + ++new_state.shared_count; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + while(true); + release_waiters(old_state); + } + + void unlock_and_lock_shared() + { + state_data old_state=state; + do + { + state_data new_state=old_state; + new_state.exclusive=false; + ++new_state.shared_count; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + while(true); + release_waiters(old_state); + } + + void unlock_upgrade_and_lock_shared() + { + state_data old_state=state; + do + { + state_data new_state=old_state; + new_state.upgrade=false; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + while(true); + release_waiters(old_state); + } + + }; +} + + +#endif diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index 6ada6ae4..604263e1 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -112,7 +112,7 @@ namespace boost inline handle create_anonymous_event(event_type type,initial_event_state state) { - handle const res=CreateEventA(0,type,state,0); + handle const res=win32::CreateEventA(0,type,state,0); if(!res) { throw thread_resource_error(); @@ -177,6 +177,7 @@ namespace boost { cleanup(); handle_to_manage=new_handle; + return *this; } operator handle() const diff --git a/include/boost/thread/xtime.hpp b/include/boost/thread/xtime.hpp index 5f66c629..a8fa1c9f 100644 --- a/include/boost/thread/xtime.hpp +++ b/include/boost/thread/xtime.hpp @@ -10,6 +10,8 @@ #include #include +#include +#include namespace boost { @@ -49,6 +51,16 @@ inline int xtime_cmp(const xtime& xt1, const xtime& xt2) return (xt1.sec > xt2.sec) ? 1 : -1; } +inline xtime get_xtime(boost::system_time const& abs_time) +{ + xtime res={0}; + boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); + + res.sec=time_since_epoch.total_seconds(); + res.nsec=time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second()); + return res; +} + } // namespace boost #endif //BOOST_XTIME_WEK070601_HPP diff --git a/src/condition.cpp b/src/condition.cpp index ffccad05..18ca0ef8 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -342,6 +342,9 @@ condition_impl::condition_impl() res = pthread_cond_init(&m_condition, 0); if (res != 0) throw thread_resource_error(); + res = pthread_mutex_init(&m_mutex, 0); + if (res != 0) + throw thread_resource_error(); } condition_impl::~condition_impl() @@ -349,20 +352,30 @@ condition_impl::~condition_impl() int res = 0; res = pthread_cond_destroy(&m_condition); assert(res == 0); + res = pthread_mutex_destroy(&m_mutex); + assert(res == 0); } void condition_impl::notify_one() { int res = 0; + res = pthread_mutex_lock(&m_mutex); + assert(res == 0); res = pthread_cond_signal(&m_condition); assert(res == 0); + res = pthread_mutex_unlock(&m_mutex); + assert(res == 0); } void condition_impl::notify_all() { int res = 0; + res = pthread_mutex_lock(&m_mutex); + assert(res == 0); res = pthread_cond_broadcast(&m_condition); assert(res == 0); + res = pthread_mutex_unlock(&m_mutex); + assert(res == 0); } void condition_impl::do_wait(pthread_mutex_t* pmutex) diff --git a/src/mutex.cpp b/src/mutex.cpp deleted file mode 100644 index bb73b9ce..00000000 --- a/src/mutex.cpp +++ /dev/null @@ -1,561 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include "timeconv.inl" - -#if defined(BOOST_HAS_WINTHREADS) -# include -# include -# include -# include -# include "mutex.inl" -#elif defined(BOOST_HAS_PTHREADS) -# include -#elif defined(BOOST_HAS_MPTASKS) -# include -# include "mac/init.hpp" -# include "mac/safe.hpp" -#endif - -namespace boost { - -#if defined(BOOST_HAS_WINTHREADS) - -mutex::mutex() - : m_mutex(0) - , m_critical_section(false) -{ - m_critical_section = true; - if (m_critical_section) - m_mutex = new_critical_section(); - else - m_mutex = new_mutex(0); -} - -mutex::~mutex() -{ - if (m_critical_section) - delete_critical_section(m_mutex); - else - delete_mutex(m_mutex); -} - -void mutex::do_lock() -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); -} - -void mutex::do_unlock() -{ - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); -} - -void mutex::do_lock(cv_state&) -{ - do_lock(); -} - -void mutex::do_unlock(cv_state&) -{ - do_unlock(); -} - -try_mutex::try_mutex() - : m_mutex(0) - , m_critical_section(false) -{ - m_critical_section = has_TryEnterCriticalSection(); - if (m_critical_section) - m_mutex = new_critical_section(); - else - m_mutex = new_mutex(0); -} - -try_mutex::~try_mutex() -{ - if (m_critical_section) - delete_critical_section(m_mutex); - else - delete_mutex(m_mutex); -} - -void try_mutex::do_lock() -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); -} - -bool try_mutex::do_trylock() -{ - if (m_critical_section) - return wait_critical_section_try(m_mutex); - else - return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; -} - -void try_mutex::do_unlock() -{ - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); -} - -void try_mutex::do_lock(cv_state&) -{ - do_lock(); -} - -void try_mutex::do_unlock(cv_state&) -{ - do_unlock(); -} - -timed_mutex::timed_mutex() - : m_mutex(0) -{ - m_mutex = new_mutex(0); -} - -timed_mutex::~timed_mutex() -{ - delete_mutex(m_mutex); -} - -void timed_mutex::do_lock() -{ - wait_mutex(m_mutex, INFINITE); -} - -bool timed_mutex::do_trylock() -{ - return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; -} - -bool timed_mutex::do_timedlock(const xtime& xt) -{ - for (;;) - { - int milliseconds; - to_duration(xt, milliseconds); - - int res = wait_mutex(m_mutex, milliseconds); - - if (res == WAIT_TIMEOUT) - { - boost::xtime cur; - boost::xtime_get(&cur, boost::TIME_UTC); - if (boost::xtime_cmp(xt, cur) > 0) - continue; - } - - return res == WAIT_OBJECT_0; - } -} - -void timed_mutex::do_unlock() -{ - release_mutex(m_mutex); -} - -void timed_mutex::do_lock(cv_state&) -{ - do_lock(); -} - -void timed_mutex::do_unlock(cv_state&) -{ - do_unlock(); -} - -#elif defined(BOOST_HAS_PTHREADS) - -mutex::mutex() -{ - int res = 0; - res = pthread_mutex_init(&m_mutex, 0); - if (res != 0) - throw thread_resource_error(); -} - -mutex::~mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); -} - -void mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - if (res == EDEADLK) throw lock_error(); - assert(res == 0); -} - -void mutex::do_unlock() -{ - int res = 0; - res = pthread_mutex_unlock(&m_mutex); - if (res == EPERM) throw lock_error(); - assert(res == 0); -} - -void mutex::do_lock(cv_state&) -{ -} - -void mutex::do_unlock(cv_state& state) -{ - state.pmutex = &m_mutex; -} - -try_mutex::try_mutex() -{ - int res = 0; - res = pthread_mutex_init(&m_mutex, 0); - if (res != 0) - throw thread_resource_error(); -} - -try_mutex::~try_mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); -} - -void try_mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - if (res == EDEADLK) throw lock_error(); - assert(res == 0); -} - -bool try_mutex::do_trylock() -{ - int res = 0; - res = pthread_mutex_trylock(&m_mutex); - if (res == EDEADLK) throw lock_error(); - assert(res == 0 || res == EBUSY); - return res == 0; -} - -void try_mutex::do_unlock() -{ - int res = 0; - res = pthread_mutex_unlock(&m_mutex); - if (res == EPERM) throw lock_error(); - assert(res == 0); -} - -void try_mutex::do_lock(cv_state&) -{ -} - -void try_mutex::do_unlock(cv_state& state) -{ - state.pmutex = &m_mutex; -} - -timed_mutex::timed_mutex() - : m_locked(false) -{ - int res = 0; - res = pthread_mutex_init(&m_mutex, 0); - if (res != 0) - throw thread_resource_error(); - - res = pthread_cond_init(&m_condition, 0); - if (res != 0) - { - pthread_mutex_destroy(&m_mutex); - throw thread_resource_error(); - } -} - -timed_mutex::~timed_mutex() -{ - assert(!m_locked); - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); - - res = pthread_cond_destroy(&m_condition); - assert(res == 0); -} - -void timed_mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - while (m_locked) - { - res = pthread_cond_wait(&m_condition, &m_mutex); - assert(res == 0); - } - - assert(!m_locked); - m_locked = true; - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -bool timed_mutex::do_trylock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - bool ret = false; - if (!m_locked) - { - m_locked = true; - ret = true; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - return ret; -} - -bool timed_mutex::do_timedlock(const xtime& xt) -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - timespec ts; - to_timespec(xt, ts); - - while (m_locked) - { - res = pthread_cond_timedwait(&m_condition, &m_mutex, &ts); - assert(res == 0 || res == ETIMEDOUT); - - if (res == ETIMEDOUT) - break; - } - - bool ret = false; - if (!m_locked) - { - m_locked = true; - ret = true; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - return ret; -} - -void timed_mutex::do_unlock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - assert(m_locked); - m_locked = false; - - res = pthread_cond_signal(&m_condition); - assert(res == 0); - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -void timed_mutex::do_lock(cv_state&) -{ - int res = 0; - while (m_locked) - { - res = pthread_cond_wait(&m_condition, &m_mutex); - assert(res == 0); - } - - assert(!m_locked); - m_locked = true; - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -void timed_mutex::do_unlock(cv_state& state) -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - assert(m_locked); - m_locked = false; - - res = pthread_cond_signal(&m_condition); - assert(res == 0); - - state.pmutex = &m_mutex; -} - -#elif defined(BOOST_HAS_MPTASKS) - -using threads::mac::detail::safe_enter_critical_region; - -mutex::mutex() -{ -} - -mutex::~mutex() -{ -} - -void mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); -} - -void mutex::do_unlock() -{ - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} - -void mutex::do_lock(cv_state& /*state*/) -{ - do_lock(); -} - -void mutex::do_unlock(cv_state& /*state*/) -{ - do_unlock(); -} - -try_mutex::try_mutex() -{ -} - -try_mutex::~try_mutex() -{ -} - -void try_mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); -} - -bool try_mutex::do_trylock() -{ - OSStatus lStatus = noErr; - lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - return lStatus == noErr; -} - -void try_mutex::do_unlock() -{ - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} - -void try_mutex::do_lock(cv_state& /*state*/) -{ - do_lock(); -} - -void try_mutex::do_unlock(cv_state& /*state*/) -{ - do_unlock(); -} - -timed_mutex::timed_mutex() -{ -} - -timed_mutex::~timed_mutex() -{ -} - -void timed_mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); -} - -bool timed_mutex::do_trylock() -{ - OSStatus lStatus = noErr; - lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - return(lStatus == noErr); -} - -bool timed_mutex::do_timedlock(const xtime& xt) -{ - int microseconds; - to_microduration(xt, microseconds); - Duration lDuration = kDurationMicrosecond * microseconds; - - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - - return(lStatus == noErr); -} - -void timed_mutex::do_unlock() -{ - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} - -void timed_mutex::do_lock(cv_state& /*state*/) -{ - do_lock(); -} - -void timed_mutex::do_unlock(cv_state& /*state*/) -{ - do_unlock(); -} - -#endif - -} // namespace boost - -// Change Log: -// 8 Feb 01 WEKEMPF Initial version. diff --git a/src/mutex.inl b/src/mutex.inl deleted file mode 100644 index b2c625e0..00000000 --- a/src/mutex.inl +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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) -// boostinspect:nounnamed - -namespace { - -#if defined(BOOST_HAS_WINTHREADS) -//:PREVENT THIS FROM BEING DUPLICATED -typedef BOOL (WINAPI* TryEnterCriticalSection_type)(LPCRITICAL_SECTION lpCriticalSection); -TryEnterCriticalSection_type g_TryEnterCriticalSection = 0; -boost::once_flag once_init_TryEnterCriticalSection = BOOST_ONCE_INIT; - -void init_TryEnterCriticalSection() -{ - //TryEnterCriticalSection is only available on WinNT 4.0 or later; - //it is not available on Win9x. - - OSVERSIONINFO version_info = {sizeof(OSVERSIONINFO)}; - ::GetVersionEx(&version_info); - if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && - version_info.dwMajorVersion >= 4) - { - if (HMODULE kernel_module = GetModuleHandle(TEXT("KERNEL32.DLL"))) - { - g_TryEnterCriticalSection = reinterpret_cast( -#if defined(BOOST_NO_ANSI_APIS) - GetProcAddressW(kernel_module, L"TryEnterCriticalSection") -#else - GetProcAddress(kernel_module, "TryEnterCriticalSection") -#endif - ); - } - } -} - -inline bool has_TryEnterCriticalSection() -{ - boost::call_once(once_init_TryEnterCriticalSection, init_TryEnterCriticalSection); - return g_TryEnterCriticalSection != 0; -} - -inline HANDLE mutex_cast(void* p) -{ - return reinterpret_cast(p); -} - -inline LPCRITICAL_SECTION critical_section_cast(void* p) -{ - return reinterpret_cast(p); -} - -inline void* new_critical_section() -{ - try - { - LPCRITICAL_SECTION critical_section = new CRITICAL_SECTION; - if (critical_section == 0) throw boost::thread_resource_error(); - InitializeCriticalSection(critical_section); - return critical_section; - } - catch(...) - { - throw boost::thread_resource_error(); - } -} - -inline void* new_mutex(const char* name) -{ -#if defined(BOOST_NO_ANSI_APIS) - int const num_wide_chars = ::MultiByteToWideChar(CP_ACP, 0, name, -1, 0, 0); - LPWSTR const wide_name = (LPWSTR)_alloca( (num_wide_chars+1) * 2 ); - int const res=::MultiByteToWideChar(CP_ACP, 0, name, -1, wide_name, num_wide_chars); - if(!res) - throw boost::thread_resource_error(); - HANDLE mutex = CreateMutexW(0, 0, wide_name); -#else - HANDLE mutex = CreateMutexA(0, 0, name); -#endif - if (mutex == 0 || mutex == INVALID_HANDLE_VALUE) //:xxx (check for both values?) - throw boost::thread_resource_error(); - return reinterpret_cast(mutex); -} - -inline void delete_critical_section(void* mutex) -{ - DeleteCriticalSection(critical_section_cast(mutex)); - delete critical_section_cast(mutex); -} - -inline void delete_mutex(void* mutex) -{ - int res = 0; - res = CloseHandle(mutex_cast(mutex)); - assert(res); -} - -inline void wait_critical_section_infinite(void* mutex) -{ - EnterCriticalSection(critical_section_cast(mutex)); //:xxx Can throw an exception under low memory conditions -} - -inline bool wait_critical_section_try(void* mutex) -{ - BOOL res = g_TryEnterCriticalSection(critical_section_cast(mutex)); - return res != 0; -} - -inline int wait_mutex(void* mutex, int time) -{ - unsigned int res = 0; - res = WaitForSingleObject(mutex_cast(mutex), time); -//:xxx assert(res != WAIT_FAILED && res != WAIT_ABANDONED); - return res; -} - -inline void release_critical_section(void* mutex) -{ - LeaveCriticalSection(critical_section_cast(mutex)); -} - -inline void release_mutex(void* mutex) -{ - BOOL res = FALSE; - res = ReleaseMutex(mutex_cast(mutex)); - assert(res); -} -#endif - -} diff --git a/src/once.cpp b/src/once.cpp deleted file mode 100644 index 0215995f..00000000 --- a/src/once.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// Copyright (C) 2007 Anthony Williams -// -// 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 -#ifdef BOOST_HAS_MPTASKS - -#include - -#include -#include -#include - -#include - -namespace { -void *remote_call_proxy(void *pData) -{ - std::pair &rData( - *reinterpret_cast *>(pData)); - - if(*rData.second == false) - { - rData.first(); - *rData.second = true; - } - - return(NULL); -} -} - -namespace boost { - - void call_once(once_flag& flag, void (*func)()) -{ - if(flag == false) - { - // all we do here is make a remote call to blue, as blue is not - // reentrant. - std::pair sData(func, &flag); - MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext); - assert(flag == true); - } -} - -} -#endif diff --git a/src/recursive_mutex.cpp b/src/recursive_mutex.cpp deleted file mode 100644 index ebe17c1a..00000000 --- a/src/recursive_mutex.cpp +++ /dev/null @@ -1,1040 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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 - -#include -#include -#include -#include -#include -#include -#include -#include "timeconv.inl" - -#if defined(BOOST_HAS_WINTHREADS) -# include -# include -# include -# include -# include "mutex.inl" -#elif defined(BOOST_HAS_PTHREADS) -# include -#elif defined(BOOST_HAS_MPTASKS) -# include -# include "safe.hpp" -#endif - -namespace boost { - -#if defined(BOOST_HAS_WINTHREADS) - -recursive_mutex::recursive_mutex() - : m_mutex(0) - , m_critical_section(false) - , m_count(0) -{ - m_critical_section = true; - if (m_critical_section) - m_mutex = new_critical_section(); - else - m_mutex = new_mutex(0); -} - -recursive_mutex::~recursive_mutex() -{ - if (m_critical_section) - delete_critical_section(m_mutex); - else - delete_mutex(m_mutex); -} - -void recursive_mutex::do_lock() -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); - - if (++m_count > 1) - { - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); - } -} - -void recursive_mutex::do_unlock() -{ - if (--m_count == 0) - { - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); - } -} - -void recursive_mutex::do_lock(cv_state& state) -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); - - m_count = state; -} - -void recursive_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); -} - -recursive_try_mutex::recursive_try_mutex() - : m_mutex(0) - , m_critical_section(false) - , m_count(0) -{ - m_critical_section = has_TryEnterCriticalSection(); - if (m_critical_section) - m_mutex = new_critical_section(); - else - m_mutex = new_mutex(0); -} - -recursive_try_mutex::~recursive_try_mutex() -{ - if (m_critical_section) - delete_critical_section(m_mutex); - else - delete_mutex(m_mutex); -} - -void recursive_try_mutex::do_lock() -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); - - if (++m_count > 1) - { - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); - } -} - -bool recursive_try_mutex::do_trylock() -{ - bool res = false; - if (m_critical_section) - res = wait_critical_section_try(m_mutex); - else - res = wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; - - if (res) - { - if (++m_count > 1) - { - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); - } - return true; - } - return false; -} - -void recursive_try_mutex::do_unlock() -{ - if (--m_count == 0) - { - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); - } -} - -void recursive_try_mutex::do_lock(cv_state& state) -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); - - m_count = state; -} - -void recursive_try_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); -} - -recursive_timed_mutex::recursive_timed_mutex() - : m_mutex(0) - , m_count(0) -{ - m_mutex = new_mutex(0); -} - -recursive_timed_mutex::~recursive_timed_mutex() -{ - delete_mutex(m_mutex); -} - -void recursive_timed_mutex::do_lock() -{ - wait_mutex(m_mutex, INFINITE); - - if (++m_count > 1) - release_mutex(m_mutex); -} - -bool recursive_timed_mutex::do_trylock() -{ - bool res = wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; - - if (res) - { - if (++m_count > 1) - release_mutex(m_mutex); - return true; - } - return false; -} - -bool recursive_timed_mutex::do_timedlock(const xtime& xt) -{ - for (;;) - { - int milliseconds; - to_duration(xt, milliseconds); - - unsigned int res = wait_mutex(m_mutex, milliseconds); - - if (res == WAIT_TIMEOUT) - { - xtime cur; - xtime_get(&cur, TIME_UTC); - if (xtime_cmp(xt, cur) > 0) - continue; - } - - if (res == WAIT_OBJECT_0) - { - if (++m_count > 1) - release_mutex(m_mutex); - return true; - } - - return false; - } -} - -void recursive_timed_mutex::do_unlock() -{ - if (--m_count == 0) - release_mutex(m_mutex); -} - -void recursive_timed_mutex::do_lock(cv_state& state) -{ - wait_mutex(m_mutex, INFINITE); - - m_count = state; -} - -void recursive_timed_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - release_mutex(m_mutex); -} - -#elif defined(BOOST_HAS_PTHREADS) - -recursive_mutex::recursive_mutex() - : m_count(0) -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - , m_valid_id(false) -# endif -{ - pthread_mutexattr_t attr; - int res = pthread_mutexattr_init(&attr); - assert(res == 0); - -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - assert(res == 0); -# endif - - res = pthread_mutex_init(&m_mutex, &attr); - { - int res = 0; - res = pthread_mutexattr_destroy(&attr); - assert(res == 0); - } - if (res != 0) - throw thread_resource_error(); - -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_cond_init(&m_unlocked, 0); - if (res != 0) - { - pthread_mutex_destroy(&m_mutex); - throw thread_resource_error(); - } -# endif -} - -recursive_mutex::~recursive_mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); - -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_cond_destroy(&m_unlocked); - assert(res == 0); -# endif -} - -void recursive_mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - if (++m_count > 1) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - } -# else - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - ++m_count; - else - { - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -void recursive_mutex::do_unlock() -{ -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - if (--m_count == 0) - { - int res = 0; - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - } -# else - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - pthread_t tid = pthread_self(); - if (m_valid_id && !pthread_equal(m_thread_id, tid)) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - throw lock_error(); - } - - if (--m_count == 0) - { - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -void recursive_mutex::do_lock(cv_state& state) -{ -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - m_count = state.count; -# else - int res = 0; - - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = pthread_self(); - m_valid_id = true; - m_count = state.count; - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -void recursive_mutex::do_unlock(cv_state& state) -{ -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); -# endif - - state.pmutex = &m_mutex; - state.count = m_count; - m_count = 0; -} - -recursive_try_mutex::recursive_try_mutex() - : m_count(0) -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - , m_valid_id(false) -# endif -{ - pthread_mutexattr_t attr; - int res = pthread_mutexattr_init(&attr); - assert(res == 0); - -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - assert(res == 0); -# endif - - res = pthread_mutex_init(&m_mutex, &attr); - { - int res = 0; - res = pthread_mutexattr_destroy(&attr); - assert(res == 0); - } - if (res != 0) - throw thread_resource_error(); - -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_cond_init(&m_unlocked, 0); - if (res != 0) - { - pthread_mutex_destroy(&m_mutex); - throw thread_resource_error(); - } -# endif -} - -recursive_try_mutex::~recursive_try_mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); - -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_cond_destroy(&m_unlocked); - assert(res == 0); -# endif -} - -void recursive_try_mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - if (++m_count > 1) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - } -# else - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - ++m_count; - else - { - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -bool recursive_try_mutex::do_trylock() -{ -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - int res = 0; - res = pthread_mutex_trylock(&m_mutex); - assert(res == 0 || res == EBUSY); - - if (res == 0) - { - if (++m_count > 1) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - } - return true; - } - - return false; -# else - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - bool ret = false; - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - { - ++m_count; - ret = true; - } - else if (!m_valid_id) - { - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - ret = true; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - return ret; -# endif -} - -void recursive_try_mutex::do_unlock() -{ -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - if (--m_count == 0) - { - int res = 0; - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - } -# else - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - pthread_t tid = pthread_self(); - if (m_valid_id && !pthread_equal(m_thread_id, tid)) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - throw lock_error(); - } - - if (--m_count == 0) - { - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -void recursive_try_mutex::do_lock(cv_state& state) -{ -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - m_count = state.count; -# else - int res = 0; - - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = pthread_self(); - m_valid_id = true; - m_count = state.count; - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -void recursive_try_mutex::do_unlock(cv_state& state) -{ -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); -# endif - - state.pmutex = &m_mutex; - state.count = m_count; - m_count = 0; -} - -recursive_timed_mutex::recursive_timed_mutex() - : m_valid_id(false), m_count(0) -{ - int res = 0; - res = pthread_mutex_init(&m_mutex, 0); - if (res != 0) - throw thread_resource_error(); - - res = pthread_cond_init(&m_unlocked, 0); - if (res != 0) - { - pthread_mutex_destroy(&m_mutex); - throw thread_resource_error(); - } -} - -recursive_timed_mutex::~recursive_timed_mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); - - res = pthread_cond_destroy(&m_unlocked); - assert(res == 0); -} - -void recursive_timed_mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - ++m_count; - else - { - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -bool recursive_timed_mutex::do_trylock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - bool ret = false; - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - { - ++m_count; - ret = true; - } - else if (!m_valid_id) - { - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - ret = true; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - return ret; -} - -bool recursive_timed_mutex::do_timedlock(const xtime& xt) -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - bool ret = false; - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - { - ++m_count; - ret = true; - } - else - { - timespec ts; - to_timespec(xt, ts); - - while (m_valid_id) - { - res = pthread_cond_timedwait(&m_unlocked, &m_mutex, &ts); - if (res == ETIMEDOUT) - break; - assert(res == 0); - } - - if (!m_valid_id) - { - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - ret = true; - } - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - return ret; -} - -void recursive_timed_mutex::do_unlock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - pthread_t tid = pthread_self(); - if (m_valid_id && !pthread_equal(m_thread_id, tid)) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - throw lock_error(); - } - - if (--m_count == 0) - { - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -void recursive_timed_mutex::do_lock(cv_state& state) -{ - int res = 0; - - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = pthread_self(); - m_valid_id = true; - m_count = state.count; - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -void recursive_timed_mutex::do_unlock(cv_state& state) -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); - - state.pmutex = &m_mutex; - state.count = m_count; - m_count = 0; -} -#elif defined(BOOST_HAS_MPTASKS) - -using threads::mac::detail::safe_enter_critical_region; - - -recursive_mutex::recursive_mutex() - : m_count(0) -{ -} - -recursive_mutex::~recursive_mutex() -{ -} - -void recursive_mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -void recursive_mutex::do_unlock() -{ - if (--m_count == 0) - { - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -void recursive_mutex::do_lock(cv_state& state) -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - m_count = state; -} - -void recursive_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} - -recursive_try_mutex::recursive_try_mutex() - : m_count(0) -{ -} - -recursive_try_mutex::~recursive_try_mutex() -{ -} - -void recursive_try_mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -bool recursive_try_mutex::do_trylock() -{ - OSStatus lStatus = noErr; - lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - - if (lStatus == noErr) - { - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } - return true; - } - return false; -} - -void recursive_try_mutex::do_unlock() -{ - if (--m_count == 0) - { - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -void recursive_try_mutex::do_lock(cv_state& state) -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - m_count = state; -} - -void recursive_try_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} - -recursive_timed_mutex::recursive_timed_mutex() - : m_count(0) -{ -} - -recursive_timed_mutex::~recursive_timed_mutex() -{ -} - -void recursive_timed_mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -bool recursive_timed_mutex::do_trylock() -{ - OSStatus lStatus = noErr; - lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - - if (lStatus == noErr) - { - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } - return true; - } - return false; -} - -bool recursive_timed_mutex::do_timedlock(const xtime& xt) -{ - int microseconds; - to_microduration(xt, microseconds); - Duration lDuration = kDurationMicrosecond * microseconds; - - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - - if (lStatus == noErr) - { - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } - return true; - } - return false; -} - -void recursive_timed_mutex::do_unlock() -{ - if (--m_count == 0) - { - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -void recursive_timed_mutex::do_lock(cv_state& state) -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - m_count = state; -} - -void recursive_timed_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} -#endif - -} // namespace boost - -// Change Log: -// 8 Feb 01 WEKEMPF Initial version. diff --git a/src/thread.cpp b/src/thread.cpp index e96e5829..dc8ff078 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #if defined(BOOST_HAS_WINTHREADS) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index f3605d5b..209e6b07 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -40,6 +40,7 @@ rule thread-run ( sources ) [ thread-run test_once.cpp ] [ thread-run test_xtime.cpp ] [ thread-run test_barrier.cpp ] -# [ thread-run test_read_write_mutex.cpp ] + [ thread-run test_shared_mutex.cpp ] + [ thread-run test_lock_concept.cpp ] ; } diff --git a/test/test_lock_concept.cpp b/test/test_lock_concept.cpp new file mode 100644 index 00000000..b0f5dc72 --- /dev/null +++ b/test/test_lock_concept.cpp @@ -0,0 +1,173 @@ +// (C) Copyright 2006-7 Anthony Williams +// 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 +#include +#include +#include +#include + +template +struct test_initially_locked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + +template +struct test_initially_unlocked_with_defer_lock_parameter +{ + void operator()() const + { + Mutex m; + Lock lock(m,boost::defer_lock); + + BOOST_CHECK(!lock); + BOOST_CHECK(!lock.owns_lock()); + } +}; + +template +struct test_initially_locked_with_adopt_lock_parameter +{ + void operator()() const + { + Mutex m; + m.lock(); + Lock lock(m,boost::adopt_lock); + + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + + +template +struct test_unlocked_after_unlock_called +{ + void operator()() const + { + Mutex m; + Lock lock(m); + lock.unlock(); + BOOST_CHECK(!lock); + BOOST_CHECK(!lock.owns_lock()); + } +}; + +template +struct test_locked_after_lock_called +{ + void operator()() const + { + Mutex m; + Lock lock(m,boost::defer_lock); + lock.lock(); + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + +template +struct test_locked_after_try_lock_called +{ + void operator()() const + { + Mutex m; + Lock lock(m,boost::defer_lock); + lock.try_lock(); + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + +template +struct test_throws_if_lock_called_when_already_locked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + + BOOST_CHECK_THROW( lock.lock(), boost::lock_error ); + } +}; + +template +struct test_throws_if_try_lock_called_when_already_locked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + + BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error ); + } +}; + +template +struct test_throws_if_unlock_called_when_already_unlocked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + lock.unlock(); + + BOOST_CHECK_THROW( lock.unlock(), boost::lock_error ); + } +}; + +BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex) +{ + typedef typename Mutex::scoped_lock Lock; + + test_initially_locked()(); + test_initially_unlocked_with_defer_lock_parameter()(); + test_initially_locked_with_adopt_lock_parameter()(); + test_unlocked_after_unlock_called()(); + test_locked_after_lock_called()(); + test_throws_if_lock_called_when_already_locked()(); + test_throws_if_unlock_called_when_already_unlocked()(); +} + +BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex) +{ + typedef typename Mutex::scoped_try_lock Lock; + + test_initially_locked()(); + test_initially_unlocked_with_defer_lock_parameter()(); + test_initially_locked_with_adopt_lock_parameter()(); + test_unlocked_after_unlock_called()(); + test_locked_after_lock_called()(); + test_locked_after_try_lock_called()(); + test_throws_if_lock_called_when_already_locked()(); + test_throws_if_try_lock_called_when_already_locked()(); + test_throws_if_unlock_called_when_already_unlocked()(); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: lock concept test suite"); + + typedef boost::mpl::vector mutex_types; + + test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types)); + + typedef boost::mpl::vector try_mutex_types; + + test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,try_mutex_types)); + + return test; +} diff --git a/test/test_mutex.cpp b/test/test_mutex.cpp index 831e6bba..08170fd2 100644 --- a/test/test_mutex.cpp +++ b/test/test_mutex.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include @@ -29,7 +29,7 @@ struct test_lock // Test the lock's constructors. { - lock_type lock(mutex, false); + lock_type lock(mutex, boost::defer_lock); BOOST_CHECK(!lock); } lock_type lock(mutex); @@ -69,10 +69,10 @@ struct test_trylock BOOST_CHECK(lock ? true : false); } { - try_lock_type lock(mutex, false); + try_lock_type lock(mutex, boost::defer_lock); BOOST_CHECK(!lock); } - try_lock_type lock(mutex, true); + try_lock_type lock(mutex); BOOST_CHECK(lock ? true : false); // Construct and initialize an xtime for a fast time out. @@ -110,16 +110,16 @@ struct test_timedlock // Test the lock's constructors. { // Construct and initialize an xtime for a fast time out. - boost::xtime xt = delay(0, 100); + boost::system_time xt = boost::get_system_time()+boost::posix_time::milliseconds(100); timed_lock_type lock(mutex, xt); BOOST_CHECK(lock ? true : false); } { - timed_lock_type lock(mutex, false); + timed_lock_type lock(mutex, boost::defer_lock); BOOST_CHECK(!lock); } - timed_lock_type lock(mutex, true); + timed_lock_type lock(mutex); BOOST_CHECK(lock ? true : false); // Construct and initialize an xtime for a fast time out. @@ -139,8 +139,8 @@ struct test_timedlock BOOST_CHECK(lock ? true : false); lock.unlock(); BOOST_CHECK(!lock); - xt = delay(0, 100); - BOOST_CHECK(lock.timed_lock(xt)); + boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100); + BOOST_CHECK(lock.timed_lock(target)); BOOST_CHECK(lock ? true : false); } }; diff --git a/test/test_once.cpp b/test/test_once.cpp index f9f59b79..eb9510d8 100644 --- a/test/test_once.cpp +++ b/test/test_once.cpp @@ -49,6 +49,103 @@ void test_call_once() BOOST_CHECK_EQUAL(var_to_init,1); } +int var_to_init_with_functor=0; + +struct increment_value +{ + int* value; + explicit increment_value(int* value_): + value(value_) + {} + + void operator()() const + { + boost::mutex::scoped_lock lock(m); + ++(*value); + } +}; + +void call_once_with_functor() +{ + unsigned const loop_count=100; + int my_once_value=0; + static boost::once_flag functor_flag=BOOST_ONCE_INIT; + for(unsigned i=0;iadd(BOOST_TEST_CASE(test_call_once)); + test->add(BOOST_TEST_CASE(test_call_once_arbitrary_functor)); + test->add(BOOST_TEST_CASE(test_call_once_retried_on_exception)); return test; } diff --git a/test/test_shared_mutex.cpp b/test/test_shared_mutex.cpp new file mode 100644 index 00000000..763758d3 --- /dev/null +++ b/test/test_shared_mutex.cpp @@ -0,0 +1,460 @@ +// (C) Copyright 2006-7 Anthony Williams +// 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 +#include +#include +#include +#include +#include "util.inl" + +#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ + { \ + boost::mutex::scoped_lock lock(mutex_name); \ + BOOST_CHECK_EQUAL(value,expected_value); \ + } + + +namespace +{ + template + class locking_thread + { + boost::shared_mutex& rw_mutex; + unsigned& unblocked_count; + unsigned& simultaneous_running_count; + unsigned& max_simultaneous_running; + boost::mutex& unblocked_count_mutex; + boost::mutex& finish_mutex; + public: + locking_thread(boost::shared_mutex& rw_mutex_, + unsigned& unblocked_count_, + boost::mutex& unblocked_count_mutex_, + boost::mutex& finish_mutex_, + unsigned& simultaneous_running_count_, + unsigned& max_simultaneous_running_): + rw_mutex(rw_mutex_), + unblocked_count(unblocked_count_), + unblocked_count_mutex(unblocked_count_mutex_), + finish_mutex(finish_mutex_), + simultaneous_running_count(simultaneous_running_count_), + max_simultaneous_running(max_simultaneous_running_) + {} + + void operator()() + { + // acquire lock + lock_type lock(rw_mutex); + + // increment count to show we're unblocked + { + boost::mutex::scoped_lock ublock(unblocked_count_mutex); + ++unblocked_count; + ++simultaneous_running_count; + if(simultaneous_running_count>max_simultaneous_running) + { + max_simultaneous_running=simultaneous_running_count; + } + } + + // wait to finish + boost::mutex::scoped_lock finish_lock(finish_mutex); + { + boost::mutex::scoped_lock ublock(unblocked_count_mutex); + --simultaneous_running_count; + } + } + }; + +} + + +void test_multiple_readers() +{ + unsigned const number_of_threads=100; + + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + boost::thread::sleep(delay(1)); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); + + finish_lock.unlock(); + + pool.join_all(); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,number_of_threads); +} + +void test_only_one_writer_permitted() +{ + unsigned const number_of_threads=100; + + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + boost::thread::sleep(delay(1)); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1); +} + +void test_reader_blocks_writer() +{ + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1); +} + +void test_unlocking_writer_unblocks_all_readers() +{ + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + boost::unique_lock write_lock(rw_mutex); + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + unsigned const reader_count=100; + + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U); + + write_lock.unlock(); + + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count); + + finish_lock.unlock(); + pool.join_all(); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count); +} + +void test_unlocking_last_reader_only_unblocks_one_writer() +{ + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_readers=0; + unsigned max_simultaneous_readers=0; + unsigned simultaneous_running_writers=0; + unsigned max_simultaneous_writers=0; + boost::mutex unblocked_count_mutex; + boost::mutex finish_reading_mutex; + boost::mutex::scoped_lock finish_reading_lock(finish_reading_mutex); + boost::mutex finish_writing_mutex; + boost::mutex::scoped_lock finish_writing_lock(finish_writing_mutex); + + unsigned const reader_count=100; + unsigned const writer_count=100; + + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers)); + } + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers)); + } + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count); + + finish_reading_lock.unlock(); + + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + + finish_writing_lock.unlock(); + pool.join_all(); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+writer_count); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_readers,reader_count); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1); +} + +void test_only_one_upgrade_lock_permitted() +{ + unsigned const number_of_threads=100; + + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + boost::thread::sleep(delay(1)); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1); +} + +void test_can_lock_upgrade_if_currently_locked_shared() +{ + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + unsigned const reader_count=100; + + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + + finish_lock.unlock(); + pool.join_all(); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1); +} + +namespace +{ + class simple_writing_thread + { + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + public: + simple_writing_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::unique_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } + }; +} + +void test_if_other_thread_has_write_lock_try_lock_shared_returns_false() +{ + + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1); + + bool const try_succeeded=rw_mutex.try_lock_shared(); + BOOST_CHECK(!try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_shared(); + } + + finish_lock.unlock(); + writer.join(); +} + +void test_if_no_thread_has_lock_try_lock_shared_returns_true() +{ + boost::shared_mutex rw_mutex; + bool const try_succeeded=rw_mutex.try_lock_shared(); + BOOST_CHECK(try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_shared(); + } +} + +namespace +{ + class simple_reading_thread + { + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + public: + simple_reading_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::shared_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } + }; +} + +void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true() +{ + + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1); + + bool const try_succeeded=rw_mutex.try_lock_shared(); + BOOST_CHECK(try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_shared(); + } + + finish_lock.unlock(); + writer.join(); +} + +void test_timed_lock_shared_times_out_if_write_lock_held() +{ + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1); + + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+boost::posix_time::milliseconds(100); + bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout); + BOOST_CHECK(timeout<=boost::get_system_time()); + BOOST_CHECK(!timed_lock_succeeded); + if(timed_lock_succeeded) + { + rw_mutex.unlock_shared(); + } + + finish_lock.unlock(); + writer.join(); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite"); + + test->add(BOOST_TEST_CASE(&test_multiple_readers)); + test->add(BOOST_TEST_CASE(&test_only_one_writer_permitted)); + test->add(BOOST_TEST_CASE(&test_reader_blocks_writer)); + test->add(BOOST_TEST_CASE(&test_unlocking_writer_unblocks_all_readers)); + test->add(BOOST_TEST_CASE(&test_unlocking_last_reader_only_unblocks_one_writer)); + test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted)); + test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared)); + test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false)); + test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true)); + test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true)); + test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held)); + + return test; +}