Updated to r8541

This commit is contained in:
Jordan Sherer
2018-03-05 14:49:51 -05:00
parent a4fa5b9988
commit a32fe6a4dc
200 changed files with 20394 additions and 4957 deletions
+21
View File
@@ -0,0 +1,21 @@
#ifndef BOOST_THREAD_CONDITION_HPP
#define BOOST_THREAD_CONDITION_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 <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_CONDITION
#include <boost/thread/condition_variable.hpp>
namespace boost
{
typedef condition_variable_any condition;
}
#endif
#endif
+155
View File
@@ -0,0 +1,155 @@
#ifndef BOOST_THREAD_DETAIL_THREAD_GROUP_HPP
#define BOOST_THREAD_DETAIL_THREAD_GROUP_HPP
// 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-9 Anthony Williams
#include <list>
#include <boost/thread/csbl/memory/unique_ptr.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/config/abi_prefix.hpp>
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4251)
#endif
namespace boost
{
class thread_group
{
private:
thread_group(thread_group const&);
thread_group& operator=(thread_group const&);
public:
thread_group() {}
~thread_group()
{
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
delete *it;
}
}
bool is_this_thread_in()
{
thread::id id = this_thread::get_id();
boost::shared_lock<shared_mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
if ((*it)->get_id() == id)
return true;
}
return false;
}
bool is_thread_in(thread* thrd)
{
if(thrd)
{
thread::id id = thrd->get_id();
boost::shared_lock<shared_mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
if ((*it)->get_id() == id)
return true;
}
return false;
}
else
{
return false;
}
}
template<typename F>
thread* create_thread(F threadfunc)
{
boost::lock_guard<shared_mutex> guard(m);
boost::csbl::unique_ptr<thread> new_thread(new thread(threadfunc));
threads.push_back(new_thread.get());
return new_thread.release();
}
void add_thread(thread* thrd)
{
if(thrd)
{
BOOST_THREAD_ASSERT_PRECONDITION( ! is_thread_in(thrd) ,
thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying to add a duplicated thread")
);
boost::lock_guard<shared_mutex> guard(m);
threads.push_back(thrd);
}
}
void remove_thread(thread* thrd)
{
boost::lock_guard<shared_mutex> guard(m);
std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
if(it!=threads.end())
{
threads.erase(it);
}
}
void join_all()
{
BOOST_THREAD_ASSERT_PRECONDITION( ! is_this_thread_in() ,
thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying joining itself")
);
boost::shared_lock<shared_mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
if ((*it)->joinable())
(*it)->join();
}
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
void interrupt_all()
{
boost::shared_lock<shared_mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
(*it)->interrupt();
}
}
#endif
size_t size() const
{
boost::shared_lock<shared_mutex> guard(m);
return threads.size();
}
private:
std::list<thread*> threads;
mutable shared_mutex m;
};
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <boost/config/abi_suffix.hpp>
#endif
+716
View File
@@ -0,0 +1,716 @@
#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
// (C) Copyright 2006-8 Anthony Williams
// (C) Copyright 2012 Vicente J. Botet Escriba
//
// 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/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/detail/thread_interruption.hpp>
#endif
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
#include <boost/assert.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class shared_mutex
{
private:
class state_data
{
public:
state_data () :
shared_count(0),
exclusive(false),
upgrade(false),
exclusive_waiting_blocked(false)
{}
void assert_free() const
{
BOOST_ASSERT( ! exclusive );
BOOST_ASSERT( ! upgrade );
BOOST_ASSERT( shared_count==0 );
}
void assert_locked() const
{
BOOST_ASSERT( exclusive );
BOOST_ASSERT( shared_count==0 );
BOOST_ASSERT( ! upgrade );
}
void assert_lock_shared () const
{
BOOST_ASSERT( ! exclusive );
BOOST_ASSERT( shared_count>0 );
//BOOST_ASSERT( (! upgrade) || (shared_count>1));
// if upgraded there are at least 2 threads sharing the mutex,
// except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership.
}
void assert_lock_upgraded () const
{
BOOST_ASSERT( ! exclusive );
BOOST_ASSERT( upgrade );
BOOST_ASSERT( shared_count>0 );
}
void assert_lock_not_upgraded () const
{
BOOST_ASSERT( ! upgrade );
}
bool can_lock () const
{
return ! (shared_count || exclusive);
}
void exclusive_blocked (bool blocked)
{
exclusive_waiting_blocked = blocked;
}
void lock ()
{
exclusive = true;
}
void unlock ()
{
exclusive = false;
exclusive_waiting_blocked = false;
}
bool can_lock_shared () const
{
return ! (exclusive || exclusive_waiting_blocked);
}
bool more_shared () const
{
return shared_count > 0 ;
}
unsigned get_shared_count () const
{
return shared_count ;
}
unsigned lock_shared ()
{
return ++shared_count;
}
void unlock_shared ()
{
--shared_count;
}
bool unlock_shared_downgrades()
{
if (upgrade) {
upgrade=false;
exclusive=true;
return true;
} else {
exclusive_waiting_blocked=false;
return false;
}
}
void lock_upgrade ()
{
++shared_count;
upgrade=true;
}
bool can_lock_upgrade () const
{
return ! (exclusive || exclusive_waiting_blocked || upgrade);
}
void unlock_upgrade ()
{
upgrade=false;
--shared_count;
}
//private:
unsigned shared_count;
bool exclusive;
bool upgrade;
bool exclusive_waiting_blocked;
};
state_data state;
boost::mutex state_change;
boost::condition_variable shared_cond;
boost::condition_variable exclusive_cond;
boost::condition_variable upgrade_cond;
void release_waiters()
{
exclusive_cond.notify_one();
shared_cond.notify_all();
}
public:
BOOST_THREAD_NO_COPYABLE(shared_mutex)
shared_mutex()
{
}
~shared_mutex()
{
}
void lock_shared()
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_shared())
{
shared_cond.wait(lk);
}
state.lock_shared();
}
bool try_lock_shared()
{
boost::unique_lock<boost::mutex> lk(state_change);
if(!state.can_lock_shared())
{
return false;
}
state.lock_shared();
return true;
}
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock_shared(system_time const& timeout)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_shared())
{
if(!shared_cond.timed_wait(lk,timeout))
{
return false;
}
}
state.lock_shared();
return true;
}
template<typename TimeDuration>
bool timed_lock_shared(TimeDuration const & relative_time)
{
return timed_lock_shared(get_system_time()+relative_time);
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_shared())
//while(state.exclusive || state.exclusive_waiting_blocked)
{
if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
{
return false;
}
}
state.lock_shared();
return true;
}
#endif
void unlock_shared()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
state.unlock_shared();
if (! state.more_shared())
{
if (state.upgrade)
{
// As there is a thread doing a unlock_upgrade_and_lock that is waiting for ! state.more_shared()
// avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified.
state.upgrade=false;
state.exclusive=true;
//lk.unlock();
upgrade_cond.notify_one();
}
else
{
state.exclusive_waiting_blocked=false;
//lk.unlock();
}
release_waiters();
}
}
void lock()
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while (state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
exclusive_cond.wait(lk);
}
state.exclusive=true;
}
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(system_time const& timeout)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
if(!exclusive_cond.timed_wait(lk,timeout))
{
if(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=false;
release_waiters();
return false;
}
break;
}
}
state.exclusive=true;
return true;
}
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
{
if(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=false;
release_waiters();
return false;
}
break;
}
}
state.exclusive=true;
return true;
}
#endif
bool try_lock()
{
boost::unique_lock<boost::mutex> lk(state_change);
if(state.shared_count || state.exclusive)
{
return false;
}
else
{
state.exclusive=true;
return true;
}
}
void unlock()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_locked();
state.exclusive=false;
state.exclusive_waiting_blocked=false;
state.assert_free();
release_waiters();
}
void lock_upgrade()
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
shared_cond.wait(lk);
}
state.lock_shared();
state.upgrade=true;
}
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock_upgrade(system_time const& timeout)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
if(!shared_cond.timed_wait(lk,timeout))
{
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
return false;
}
break;
}
}
state.lock_shared();
state.upgrade=true;
return true;
}
template<typename TimeDuration>
bool timed_lock_upgrade(TimeDuration const & relative_time)
{
return timed_lock_upgrade(get_system_time()+relative_time);
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
{
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
return false;
}
break;
}
}
state.lock_shared();
state.upgrade=true;
return true;
}
#endif
bool try_lock_upgrade()
{
boost::unique_lock<boost::mutex> lk(state_change);
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
return false;
}
else
{
state.lock_shared();
state.upgrade=true;
state.assert_lock_upgraded();
return true;
}
}
void unlock_upgrade()
{
boost::unique_lock<boost::mutex> lk(state_change);
//state.upgrade=false;
state.unlock_upgrade();
if(! state.more_shared() )
{
state.exclusive_waiting_blocked=false;
release_waiters();
} else {
shared_cond.notify_all();
}
}
// Upgrade <-> Exclusive
void unlock_upgrade_and_lock()
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
state.unlock_shared();
while (state.more_shared())
{
upgrade_cond.wait(lk);
}
state.upgrade=false;
state.exclusive=true;
state.assert_locked();
}
void unlock_and_lock_upgrade()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_locked();
state.exclusive=false;
state.upgrade=true;
state.lock_shared();
state.exclusive_waiting_blocked=false;
state.assert_lock_upgraded();
release_waiters();
}
bool try_unlock_upgrade_and_lock()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
if( !state.exclusive
&& !state.exclusive_waiting_blocked
&& state.upgrade
&& state.shared_count==1)
{
state.shared_count=0;
state.exclusive=true;
state.upgrade=false;
state.assert_locked();
return true;
}
return false;
}
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool
try_unlock_upgrade_and_lock_for(
const chrono::duration<Rep, Period>& rel_time)
{
return try_unlock_upgrade_and_lock_until(
chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool
try_unlock_upgrade_and_lock_until(
const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
if (state.shared_count != 1)
{
for (;;)
{
cv_status status = shared_cond.wait_until(lk,abs_time);
if (state.shared_count == 1)
break;
if(status == cv_status::timeout)
return false;
}
}
state.upgrade=false;
state.exclusive=true;
state.exclusive_waiting_blocked=false;
state.shared_count=0;
return true;
}
#endif
// Shared <-> Exclusive
void unlock_and_lock_shared()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_locked();
state.exclusive=false;
state.lock_shared();
state.exclusive_waiting_blocked=false;
release_waiters();
}
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
bool try_unlock_shared_and_lock()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if( !state.exclusive
&& !state.exclusive_waiting_blocked
&& !state.upgrade
&& state.shared_count==1)
{
state.shared_count=0;
state.exclusive=true;
return true;
}
return false;
}
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool
try_unlock_shared_and_lock_for(
const chrono::duration<Rep, Period>& rel_time)
{
return try_unlock_shared_and_lock_until(
chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool
try_unlock_shared_and_lock_until(
const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if (state.shared_count != 1)
{
for (;;)
{
cv_status status = shared_cond.wait_until(lk,abs_time);
if (state.shared_count == 1)
break;
if(status == cv_status::timeout)
return false;
}
}
state.upgrade=false;
state.exclusive=true;
state.exclusive_waiting_blocked=false;
state.shared_count=0;
return true;
}
#endif
#endif
// Shared <-> Upgrade
void unlock_upgrade_and_lock_shared()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
state.upgrade=false;
state.exclusive_waiting_blocked=false;
release_waiters();
}
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
bool try_unlock_shared_and_lock_upgrade()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if( !state.exclusive
&& !state.exclusive_waiting_blocked
&& !state.upgrade
)
{
state.upgrade=true;
return true;
}
return false;
}
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool
try_unlock_shared_and_lock_upgrade_for(
const chrono::duration<Rep, Period>& rel_time)
{
return try_unlock_shared_and_lock_upgrade_until(
chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool
try_unlock_shared_and_lock_upgrade_until(
const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if( state.exclusive
|| state.exclusive_waiting_blocked
|| state.upgrade
)
{
for (;;)
{
cv_status status = exclusive_cond.wait_until(lk,abs_time);
if( ! state.exclusive
&& ! state.exclusive_waiting_blocked
&& ! state.upgrade
)
break;
if(status == cv_status::timeout)
return false;
}
}
state.upgrade=true;
return true;
}
#endif
#endif
};
typedef shared_mutex upgrade_mutex;
}
#include <boost/config/abi_suffix.hpp>
#endif
+50
View File
@@ -0,0 +1,50 @@
#ifndef BOOST_THREAD_SHARED_MUTEX_HPP
#define BOOST_THREAD_SHARED_MUTEX_HPP
// shared_mutex.hpp
//
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
//
// 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/thread/detail/config.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#if defined(BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN)
#include <boost/thread/pthread/shared_mutex.hpp>
#else
#include <boost/thread/win32/shared_mutex.hpp>
#endif
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
//#include <boost/thread/v2/shared_mutex.hpp>
#include <boost/thread/pthread/shared_mutex.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#include <boost/thread/lockable_traits.hpp>
namespace boost
{
typedef shared_mutex shared_timed_mutex;
namespace sync
{
#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
template<>
struct is_basic_lockable<shared_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<>
struct is_lockable<shared_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
#endif
}
}
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef BOOST_THREAD_THREAD_HPP
#define BOOST_THREAD_THREAD_HPP
// thread.hpp
//
// (C) Copyright 2007-8 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 <boost/thread/thread_only.hpp>
#include <boost/thread/detail/thread_group.hpp>
#endif
+903
View File
@@ -0,0 +1,903 @@
#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
// (C) Copyright 2006-8 Anthony Williams
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
//
// 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/assert.hpp>
#include <boost/detail/interlocked.hpp>
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/static_assert.hpp>
#include <limits.h>
#include <boost/thread/thread_time.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class shared_mutex
{
private:
struct state_data
{
unsigned shared_count:11,
shared_waiting:11,
exclusive:1,
upgrade:1,
exclusive_waiting:7,
exclusive_waiting_blocked:1;
friend bool operator==(state_data const& lhs,state_data const& rhs)
{
return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
}
};
template<typename T>
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<long*>(target),
*reinterpret_cast<long*>(&new_value),
*reinterpret_cast<long*>(&comparand));
return *reinterpret_cast<T const*>(&res);
}
enum
{
unlock_sem = 0,
exclusive_sem = 1
};
state_data state;
detail::win32::handle semaphores[2];
detail::win32::handle upgrade_sem;
void release_waiters(state_data old_state)
{
if(old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
}
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
void release_shared_waiters(state_data old_state)
{
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
public:
BOOST_THREAD_NO_COPYABLE(shared_mutex)
shared_mutex()
{
semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
if (!semaphores[exclusive_sem])
{
detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
boost::throw_exception(thread_resource_error());
}
upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
if (!upgrade_sem)
{
detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX);
boost::throw_exception(thread_resource_error());
}
state_data state_={0,0,0,0,0,0};
state=state_;
}
~shared_mutex()
{
detail::win32::CloseHandle(upgrade_sem);
detail::win32::CloseHandle(semaphores[unlock_sem]);
detail::win32::CloseHandle(semaphores[exclusive_sem]);
}
bool try_lock_shared()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
{
++new_state.shared_count;
if(!new_state.shared_count)
{
return false;
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
}
void lock_shared()
{
#if defined BOOST_THREAD_USES_DATETIME
BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
#else
BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now()));
#endif
}
#if defined BOOST_THREAD_USES_DATETIME
template<typename TimeDuration>
bool timed_lock_shared(TimeDuration const & relative_time)
{
return timed_lock_shared(get_system_time()+relative_time);
}
bool timed_lock_shared(boost::system_time const& wait_until)
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
{
++new_state.shared_waiting;
if(!new_state.shared_waiting)
{
boost::throw_exception(boost::lock_error());
}
}
else
{
++new_state.shared_count;
if(!new_state.shared_count)
{
boost::throw_exception(boost::lock_error());
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
return true;
}
unsigned long const res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0);
if(res==detail::win32::timeout)
{
for(;;)
{
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;
if(!new_state.shared_count)
{
return false;
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
return true;
}
return false;
}
BOOST_ASSERT(res==0);
}
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
typename Clock::time_point c_now = Clock::now();
return try_lock_shared_until(s_now + ceil<system_clock::duration>(t - c_now));
}
template <class Duration>
bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, Duration>& t)
{
using namespace chrono;
typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
return try_lock_shared_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
}
bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
{
++new_state.shared_waiting;
if(!new_state.shared_waiting)
{
boost::throw_exception(boost::lock_error());
}
}
else
{
++new_state.shared_count;
if(!new_state.shared_count)
{
boost::throw_exception(boost::lock_error());
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
return true;
}
chrono::system_clock::time_point n = chrono::system_clock::now();
unsigned long res;
if (tp>n) {
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n);
res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],
static_cast<unsigned long>(rel_time.count()), 0);
} else {
res=detail::win32::timeout;
}
if(res==detail::win32::timeout)
{
for(;;)
{
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;
if(!new_state.shared_count)
{
return false;
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
return true;
}
return false;
}
BOOST_ASSERT(res==0);
}
}
#endif
void unlock_shared()
{
state_data old_state=state;
for(;;)
{
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)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
}
else
{
release_waiters(old_state);
}
}
break;
}
old_state=current_state;
}
}
void lock()
{
#if defined BOOST_THREAD_USES_DATETIME
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
#else
BOOST_VERIFY(try_lock_until(chrono::steady_clock::now()));
#endif
}
#if defined BOOST_THREAD_USES_DATETIME
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
}
#endif
bool try_lock()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
return false;
}
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;
}
return true;
}
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(boost::system_time const& wait_until)
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
++new_state.exclusive_waiting;
if(!new_state.exclusive_waiting)
{
boost::throw_exception(boost::lock_error());
}
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;
}
if(!old_state.shared_count && !old_state.exclusive)
{
return true;
}
#ifndef UNDER_CE
const bool wait_all = true;
#else
const bool wait_all = false;
#endif
unsigned long const wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0);
if(wait_res==detail::win32::timeout)
{
for(;;)
{
bool must_notify = false;
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
if(new_state.exclusive_waiting)
{
if(!--new_state.exclusive_waiting)
{
new_state.exclusive_waiting_blocked=false;
must_notify = true;
}
}
}
else
{
new_state.exclusive=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if (must_notify)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
}
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!old_state.shared_count && !old_state.exclusive)
{
return true;
}
return false;
}
BOOST_ASSERT(wait_res<2);
}
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
typename Clock::time_point c_now = Clock::now();
return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now));
}
template <class Duration>
bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
{
using namespace chrono;
typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
}
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
++new_state.exclusive_waiting;
if(!new_state.exclusive_waiting)
{
boost::throw_exception(boost::lock_error());
}
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;
}
if(!old_state.shared_count && !old_state.exclusive)
{
return true;
}
#ifndef UNDER_CE
const bool wait_all = true;
#else
const bool wait_all = false;
#endif
chrono::system_clock::time_point n = chrono::system_clock::now();
unsigned long wait_res;
if (tp>n) {
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,
static_cast<unsigned long>(rel_time.count()), 0);
} else {
wait_res=detail::win32::timeout;
}
if(wait_res==detail::win32::timeout)
{
for(;;)
{
bool must_notify = false;
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
if(new_state.exclusive_waiting)
{
if(!--new_state.exclusive_waiting)
{
new_state.exclusive_waiting_blocked=false;
must_notify = true;
}
}
}
else
{
new_state.exclusive=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if (must_notify)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
}
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!old_state.shared_count && !old_state.exclusive)
{
return true;
}
return false;
}
BOOST_ASSERT(wait_res<2);
}
}
#endif
void unlock()
{
state_data old_state=state;
for(;;)
{
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;
}
release_waiters(old_state);
}
void lock_upgrade()
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
{
++new_state.shared_waiting;
if(!new_state.shared_waiting)
{
boost::throw_exception(boost::lock_error());
}
}
else
{
++new_state.shared_count;
if(!new_state.shared_count)
{
boost::throw_exception(boost::lock_error());
}
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;
}
if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
{
return;
}
BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],detail::win32::infinite, 0));
}
}
bool try_lock_upgrade()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
{
return false;
}
else
{
++new_state.shared_count;
if(!new_state.shared_count)
{
return false;
}
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;
}
return true;
}
void unlock_upgrade()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
new_state.upgrade=false;
bool const last_reader=!--new_state.shared_count;
new_state.shared_waiting=0;
if(last_reader)
{
if(new_state.exclusive_waiting)
{
--new_state.exclusive_waiting;
new_state.exclusive_waiting_blocked=false;
}
}
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);
}
else {
release_shared_waiters(old_state);
}
// #7720
//else {
// release_waiters(old_state);
//}
break;
}
old_state=current_state;
}
}
void unlock_upgrade_and_lock()
{
state_data old_state=state;
for(;;)
{
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)
{
BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0));
}
break;
}
old_state=current_state;
}
}
void unlock_and_lock_upgrade()
{
state_data old_state=state;
for(;;)
{
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;
}
release_waiters(old_state);
}
// bool try_unlock_upgrade_and_lock()
// {
// return false;
// }
//#ifdef BOOST_THREAD_USES_CHRONO
// template <class Rep, class Period>
// bool
// try_unlock_upgrade_and_lock_for(
// const chrono::duration<Rep, Period>& rel_time)
// {
// return try_unlock_upgrade_and_lock_until(
// chrono::steady_clock::now() + rel_time);
// }
// template <class Clock, class Duration>
// bool
// try_unlock_upgrade_and_lock_until(
// const chrono::time_point<Clock, Duration>& abs_time)
// {
// return false;
// }
//#endif
void unlock_and_lock_shared()
{
state_data old_state=state;
for(;;)
{
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;
}
release_waiters(old_state);
}
void unlock_upgrade_and_lock_shared()
{
state_data old_state=state;
for(;;)
{
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;
}
release_waiters(old_state);
}
};
typedef shared_mutex upgrade_mutex;
}
#include <boost/config/abi_suffix.hpp>
#endif