diff options
Diffstat (limited to 'boost/interprocess/sync/windows')
-rw-r--r-- | boost/interprocess/sync/windows/condition.hpp | 383 | ||||
-rw-r--r-- | boost/interprocess/sync/windows/mutex.hpp | 137 | ||||
-rw-r--r-- | boost/interprocess/sync/windows/recursive_mutex.hpp | 43 | ||||
-rw-r--r-- | boost/interprocess/sync/windows/semaphore.hpp | 137 | ||||
-rw-r--r-- | boost/interprocess/sync/windows/sync_utils.hpp | 173 |
5 files changed, 873 insertions, 0 deletions
diff --git a/boost/interprocess/sync/windows/condition.hpp b/boost/interprocess/sync/windows/condition.hpp new file mode 100644 index 0000000000..167b8730c3 --- /dev/null +++ b/boost/interprocess/sync/windows/condition.hpp @@ -0,0 +1,383 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_CONDITION_HPP +#define BOOST_INTERPROCESS_DETAIL_WINDOWS_CONDITION_HPP + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/detail/posix_time_types_wrk.hpp> + +#include <boost/interprocess/sync/interprocess_mutex.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/interprocess/exceptions.hpp> +#include <boost/interprocess/sync/windows/semaphore.hpp> +#include <boost/interprocess/sync/windows/mutex.hpp> +#include <boost/cstdint.hpp> +#include <limits> + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// +// Condition variable algorithm taken from pthreads-win32 discussion. +// +// The algorithm was developed by Alexander Terekhov in colaboration with +// Louis Thomas. +// +// Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL +// +// semBlockLock - bin.semaphore +// semBlockQueue - semaphore +// mtxExternal - mutex or CS +// mtxUnblockLock - mutex or CS +// nWaitersGone - int +// nWaitersBlocked - int +// nWaitersToUnblock - int +// +// wait( timeout ) { +// +// [auto: register int result ] // error checking omitted +// [auto: register int nSignalsWasLeft ] +// [auto: register int nWaitersWasGone ] +// +// sem_wait( semBlockLock ); +// nWaitersBlocked++; +// sem_post( semBlockLock ); +// +// unlock( mtxExternal ); +// bTimedOut = sem_wait( semBlockQueue,timeout ); +// +// lock( mtxUnblockLock ); +// if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { +// if ( bTimedOut ) { // timeout (or canceled) +// if ( 0 != nWaitersBlocked ) { +// nWaitersBlocked--; +// } +// else { +// nWaitersGone++; // count spurious wakeups. +// } +// } +// if ( 0 == --nWaitersToUnblock ) { +// if ( 0 != nWaitersBlocked ) { +// sem_post( semBlockLock ); // open the gate. +// nSignalsWasLeft = 0; // do not open the gate +// // below again. +// } +// else if ( 0 != (nWaitersWasGone = nWaitersGone) ) { +// nWaitersGone = 0; +// } +// } +// } +// else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or +// // spurious semaphore :-) +// sem_wait( semBlockLock ); +// nWaitersBlocked -= nWaitersGone; // something is going on here +// // - test of timeouts? :-) +// sem_post( semBlockLock ); +// nWaitersGone = 0; +// } +// unlock( mtxUnblockLock ); +// +// if ( 1 == nSignalsWasLeft ) { +// if ( 0 != nWaitersWasGone ) { +// // sem_adjust( semBlockQueue,-nWaitersWasGone ); +// while ( nWaitersWasGone-- ) { +// sem_wait( semBlockQueue ); // better now than spurious later +// } +// } sem_post( semBlockLock ); // open the gate +// } +// +// lock( mtxExternal ); +// +// return ( bTimedOut ) ? ETIMEOUT : 0; +// } +// +// signal(bAll) { +// +// [auto: register int result ] +// [auto: register int nSignalsToIssue] +// +// lock( mtxUnblockLock ); +// +// if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! +// if ( 0 == nWaitersBlocked ) { // NO-OP +// return unlock( mtxUnblockLock ); +// } +// if (bAll) { +// nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; +// nWaitersBlocked = 0; +// } +// else { +// nSignalsToIssue = 1; +// nWaitersToUnblock++; +// nWaitersBlocked--; +// } +// } +// else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! +// sem_wait( semBlockLock ); // close the gate +// if ( 0 != nWaitersGone ) { +// nWaitersBlocked -= nWaitersGone; +// nWaitersGone = 0; +// } +// if (bAll) { +// nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; +// nWaitersBlocked = 0; +// } +// else { +// nSignalsToIssue = nWaitersToUnblock = 1; +// nWaitersBlocked--; +// } +// } +// else { // NO-OP +// return unlock( mtxUnblockLock ); +// } +// +// unlock( mtxUnblockLock ); +// sem_post( semBlockQueue,nSignalsToIssue ); +// return result; +// } +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class windows_condition +{ + windows_condition(const windows_condition &); + windows_condition &operator=(const windows_condition &); + public: + windows_condition(); + ~windows_condition(); + + void notify_one(); + void notify_all(); + + template <typename L> + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { + if(abs_time == boost::posix_time::pos_infin){ + this->wait(lock); + return true; + } + if (!lock) + throw lock_exception(); + return this->do_timed_wait(abs_time, *lock.mutex()); + } + + template <typename L, typename Pr> + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { + if(abs_time == boost::posix_time::pos_infin){ + this->wait(lock, pred); + return true; + } + if (!lock) + throw lock_exception(); + while (!pred()){ + if (!this->do_timed_wait(abs_time, *lock.mutex())) + return pred(); + } + return true; + } + + template <typename L> + void wait(L& lock) + { + if (!lock) + throw lock_exception(); + do_wait(*lock.mutex()); + } + + template <typename L, typename Pr> + void wait(L& lock, Pr pred) + { + if (!lock) + throw lock_exception(); + + while (!pred()) + do_wait(*lock.mutex()); + } + + template<class InterprocessMutex> + void do_wait(InterprocessMutex &mut); + + template<class InterprocessMutex> + bool do_timed_wait(const boost::posix_time::ptime &abs_time, InterprocessMutex &mut); + + private: + + template<class InterprocessMutex> + bool do_timed_wait(bool timeout_enabled, const boost::posix_time::ptime &abs_time, InterprocessMutex &mut); + void do_signal (bool broadcast); + + boost::int32_t m_nwaiters_blocked; + boost::int32_t m_nwaiters_gone; + boost::int32_t m_nwaiters_to_unblock; + windows_semaphore m_sem_block_queue; + windows_semaphore m_sem_block_lock; + windows_mutex m_mtx_unblock_lock; +}; + +inline windows_condition::windows_condition() + : m_nwaiters_blocked(0) + , m_nwaiters_gone(0) + , m_nwaiters_to_unblock(0) + , m_sem_block_queue(0) + , m_sem_block_lock(1) + , m_mtx_unblock_lock() +{} + +inline windows_condition::~windows_condition() +{} + +inline void windows_condition::notify_one() +{ this->do_signal(false); } + +inline void windows_condition::notify_all() +{ this->do_signal(true); } + +inline void windows_condition::do_signal(bool broadcast) +{ + boost::int32_t nsignals_to_issue; + + { + scoped_lock<windows_mutex> locker(m_mtx_unblock_lock); + + if ( 0 != m_nwaiters_to_unblock ) { // the gate is closed!!! + if ( 0 == m_nwaiters_blocked ) { // NO-OP + //locker's destructor triggers m_mtx_unblock_lock.unlock() + return; + } + if (broadcast) { + m_nwaiters_to_unblock += nsignals_to_issue = m_nwaiters_blocked; + m_nwaiters_blocked = 0; + } + else { + nsignals_to_issue = 1; + m_nwaiters_to_unblock++; + m_nwaiters_blocked--; + } + } + else if ( m_nwaiters_blocked > m_nwaiters_gone ) { // HARMLESS RACE CONDITION! + m_sem_block_lock.wait(); // close the gate + if ( 0 != m_nwaiters_gone ) { + m_nwaiters_blocked -= m_nwaiters_gone; + m_nwaiters_gone = 0; + } + if (broadcast) { + nsignals_to_issue = m_nwaiters_to_unblock = m_nwaiters_blocked; + m_nwaiters_blocked = 0; + } + else { + nsignals_to_issue = m_nwaiters_to_unblock = 1; + m_nwaiters_blocked--; + } + } + else { // NO-OP + //locker's destructor triggers m_mtx_unblock_lock.unlock() + return; + } + //locker's destructor triggers m_mtx_unblock_lock.unlock() + } + m_sem_block_queue.post(nsignals_to_issue); +} + +template<class InterprocessMutex> +inline void windows_condition::do_wait(InterprocessMutex &mut) +{ this->do_timed_wait(false, boost::posix_time::ptime(), mut); } + +template<class InterprocessMutex> +inline bool windows_condition::do_timed_wait + (const boost::posix_time::ptime &abs_time, InterprocessMutex &mut) +{ return this->do_timed_wait(true, abs_time, mut); } + +template<class InterprocessMutex> +inline bool windows_condition::do_timed_wait + (bool tout_enabled, const boost::posix_time::ptime &abs_time, InterprocessMutex &mtxExternal) +{ + //Initialize to avoid warnings + boost::int32_t nsignals_was_left = 0; + boost::int32_t nwaiters_was_gone = 0; + + m_sem_block_lock.wait(); + ++m_nwaiters_blocked; + m_sem_block_lock.post(); + + struct scoped_unlock + { + InterprocessMutex & mut; + scoped_unlock(InterprocessMutex & m) + : mut(m) + { m.unlock(); } + + ~scoped_unlock() + { mut.lock(); } + } unlocker(mtxExternal); + + + bool bTimedOut = tout_enabled ? !m_sem_block_queue.timed_wait(abs_time) : (m_sem_block_queue.wait(), false); + + { + scoped_lock<windows_mutex> locker(m_mtx_unblock_lock); + if ( 0 != (nsignals_was_left = m_nwaiters_to_unblock) ) { + if ( bTimedOut ) { // timeout (or canceled) + if ( 0 != m_nwaiters_blocked ) { + m_nwaiters_blocked--; + } + else { + m_nwaiters_gone++; // count spurious wakeups. + } + } + if ( 0 == --m_nwaiters_to_unblock ) { + if ( 0 != m_nwaiters_blocked ) { + m_sem_block_lock.post(); // open the gate. + nsignals_was_left = 0; // do not open the gate below again. + } + else if ( 0 != (nwaiters_was_gone = m_nwaiters_gone) ) { + m_nwaiters_gone = 0; + } + } + } + else if ( (std::numeric_limits<boost::int32_t>::max)()/2 + == ++m_nwaiters_gone ) { // timeout/canceled or spurious semaphore :-) + m_sem_block_lock.wait(); + m_nwaiters_blocked -= m_nwaiters_gone; // something is going on here - test of timeouts? :-) + m_sem_block_lock.post(); + m_nwaiters_gone = 0; + } + //locker's destructor triggers m_mtx_unblock_lock.unlock() + } + + if ( 1 == nsignals_was_left ) { + if ( 0 != nwaiters_was_gone ) { + // sem_adjust( m_sem_block_queue,-nwaiters_was_gone ); + while ( nwaiters_was_gone-- ) { + m_sem_block_queue.wait(); // better now than spurious later + } + } + m_sem_block_lock.post(); // open the gate + } + + //mtxExternal.lock(); called from unlocker + + return ( bTimedOut ) ? false : true; +} + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_CONDITION_HPP diff --git a/boost/interprocess/sync/windows/mutex.hpp b/boost/interprocess/sync/windows/mutex.hpp new file mode 100644 index 0000000000..5eca522339 --- /dev/null +++ b/boost/interprocess/sync/windows/mutex.hpp @@ -0,0 +1,137 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/detail/posix_time_types_wrk.hpp> +#include <boost/interprocess/detail/win32_api.hpp> +#include <boost/interprocess/detail/intermodule_singleton.hpp> +#include <boost/interprocess/sync/windows/sync_utils.hpp> +#include <boost/interprocess/exceptions.hpp> + + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class windows_mutex +{ + windows_mutex(const windows_mutex &); + windows_mutex &operator=(const windows_mutex &); + public: + + windows_mutex(); + ~windows_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + void take_ownership(){}; + + private: + const sync_id id_; +}; + +inline windows_mutex::windows_mutex() + : id_() +{ + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + //Create mutex with the initial count + bool open_or_created; + handles.obtain_mutex(this->id_, &open_or_created); + //The mutex must be created, never opened + assert(open_or_created); + assert(open_or_created && winapi::get_last_error() != winapi::error_already_exists); + (void)open_or_created; +} + +inline windows_mutex::~windows_mutex() +{ + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + handles.destroy_handle(this->id_); +} + +inline void windows_mutex::lock(void) +{ + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + //This can throw + void *hnd = handles.obtain_mutex(this->id_); + unsigned long ret = winapi::wait_for_single_object(hnd, winapi::infinite_time); + if(ret == winapi::wait_failed){ + error_info err(winapi::get_last_error()); + throw interprocess_exception(err); + } +} + +inline bool windows_mutex::try_lock(void) +{ + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + //This can throw + void *hnd = handles.obtain_mutex(this->id_); + unsigned long ret = winapi::wait_for_single_object(hnd, 0); + if(ret == winapi::wait_failed){ + error_info err(winapi::get_last_error()); + throw interprocess_exception(err); + } + return ret != winapi::wait_timeout; +} + +inline bool windows_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + if(abs_time == boost::posix_time::pos_infin){ + this->lock(); + return true; + } + boost::posix_time::ptime now + = boost::posix_time::microsec_clock::universal_time(); + + unsigned long ms = (unsigned long)(abs_time-now).total_milliseconds(); + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + //This can throw + void *hnd = handles.obtain_mutex(this->id_); + unsigned long ret = winapi::wait_for_single_object(hnd, ms); + if(ret == winapi::wait_failed){ + error_info err(winapi::get_last_error()); + throw interprocess_exception(err); + } + return ret != winapi::wait_timeout; +} + +inline void windows_mutex::unlock(void) +{ + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + //This can throw + void *hnd = handles.obtain_mutex(this->id_); + int ret = winapi::release_mutex(hnd); + (void)ret; + assert(ret); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP diff --git a/boost/interprocess/sync/windows/recursive_mutex.hpp b/boost/interprocess/sync/windows/recursive_mutex.hpp new file mode 100644 index 0000000000..9565cb6fb4 --- /dev/null +++ b/boost/interprocess/sync/windows/recursive_mutex.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/sync/windows/mutex.hpp> + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +//Windows mutex is already recursive +class windows_recursive_mutex + : public windows_mutex +{ + windows_recursive_mutex(const windows_recursive_mutex &); + windows_recursive_mutex &operator=(const windows_recursive_mutex &); + public: + windows_recursive_mutex() : windows_mutex() {} +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP diff --git a/boost/interprocess/sync/windows/semaphore.hpp b/boost/interprocess/sync/windows/semaphore.hpp new file mode 100644 index 0000000000..d5835ceec7 --- /dev/null +++ b/boost/interprocess/sync/windows/semaphore.hpp @@ -0,0 +1,137 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_SEMAPHORE_HPP +#define BOOST_INTERPROCESS_DETAIL_WINDOWS_SEMAPHORE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/detail/posix_time_types_wrk.hpp> +#include <boost/interprocess/detail/win32_api.hpp> +#include <boost/interprocess/detail/intermodule_singleton.hpp> +#include <boost/interprocess/sync/windows/sync_utils.hpp> +#include <boost/interprocess/exceptions.hpp> + + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class windows_semaphore +{ + windows_semaphore(const windows_semaphore &); + windows_semaphore &operator=(const windows_semaphore &); + public: + + windows_semaphore(unsigned int initialCount); + ~windows_semaphore(); + + void post(long release_count = 1); + void wait(); + bool try_wait(); + bool timed_wait(const boost::posix_time::ptime &abs_time); + + private: + const sync_id id_; +}; + +inline windows_semaphore::windows_semaphore(unsigned int initialCount) + : id_() +{ + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + //Force smeaphore creation with the initial count + bool open_or_created; + handles.obtain_semaphore(this->id_, initialCount, &open_or_created); + //The semaphore must be created, never opened + assert(open_or_created); + assert(open_or_created && winapi::get_last_error() != winapi::error_already_exists); + (void)open_or_created; +} + +inline windows_semaphore::~windows_semaphore() +{ + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + handles.destroy_handle(this->id_); +} + +inline void windows_semaphore::wait(void) +{ + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + //This can throw + void *hnd = handles.obtain_semaphore(this->id_, 0); + unsigned long ret = winapi::wait_for_single_object(hnd, winapi::infinite_time); + if(ret == winapi::wait_failed){ + error_info err(winapi::get_last_error()); + throw interprocess_exception(err); + } +} + +inline bool windows_semaphore::try_wait(void) +{ + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + //This can throw + void *hnd = handles.obtain_semaphore(this->id_, 0); + unsigned long ret = winapi::wait_for_single_object(hnd, 0); + if(ret == winapi::wait_failed){ + error_info err(winapi::get_last_error()); + throw interprocess_exception(err); + } + return ret != winapi::wait_timeout; +} + +inline bool windows_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +{ + if(abs_time == boost::posix_time::pos_infin){ + this->wait(); + return true; + } + boost::posix_time::ptime now + = boost::posix_time::microsec_clock::universal_time(); + + unsigned long ms = (unsigned long)(abs_time-now).total_milliseconds(); + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + //This can throw + void *hnd = handles.obtain_semaphore(this->id_, 0); + unsigned long ret = winapi::wait_for_single_object(hnd, ms); + if(ret == winapi::wait_failed){ + error_info err(winapi::get_last_error()); + throw interprocess_exception(err); + } + return ret != winapi::wait_timeout; +} + +inline void windows_semaphore::post(long release_count) +{ + sync_handles &handles = + intermodule_singleton<sync_handles>::get(); + //This can throw + void *hnd = handles.obtain_semaphore(this->id_, 0); + long prev_count; + int ret = winapi::release_semaphore(hnd, release_count, &prev_count); + (void)ret; + assert(ret); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_SEMAPHORE_HPP diff --git a/boost/interprocess/sync/windows/sync_utils.hpp b/boost/interprocess/sync/windows/sync_utils.hpp new file mode 100644 index 0000000000..89c4aeda0b --- /dev/null +++ b/boost/interprocess/sync/windows/sync_utils.hpp @@ -0,0 +1,173 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP +#define BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/detail/win32_api.hpp> +#include <boost/interprocess/sync/spin/mutex.hpp> +#include <boost/interprocess/exceptions.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/unordered/unordered_map.hpp> +#include <cstddef> + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +inline bool bytes_to_str(const void *mem, const std::size_t mem_length, char *out_str, std::size_t &out_length) +{ + const std::size_t need_mem = mem_length*2+1; + if(out_length < need_mem){ + return false; + } + + const char Characters [] = + { '0', '1', '2', '3', '4', '5', '6', '7' + , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + std::size_t char_counter = 0; + const char *buf = (const char *)mem; + for(std::size_t i = 0; i != mem_length; ++i){ + out_str[char_counter++] = Characters[(buf[i]&0xF0)>>4]; + out_str[char_counter++] = Characters[(buf[i]&0x0F)]; + } + out_str[char_counter] = 0; + return true; +} + +struct sync_id +{ + sync_id() + { winapi::query_performance_counter(&rand); } + + __int64 rand; + + friend std::size_t hash_value(const sync_id &m) + { return boost::hash_value(m.rand); } + + friend bool operator==(const sync_id &l, const sync_id &r) + { return l.rand == r.rand; } +}; +/* +#define BOOST_NO_LONG_LONG ss + +#if defined(BOOST_NO_LONG_LONG) + +#error "defined(BOOST_NO_LONG_LONG)" +#else +#error "NOT defined(BOOST_NO_LONG_LONG)" +#endif +*/ +class sync_handles +{ + public: + enum type { MUTEX, SEMAPHORE }; + + private: + typedef boost::unordered_map<sync_id, void*> map_type; + static const std::size_t LengthOfGlobal = sizeof("Global\\boost.ipc")-1; + static const std::size_t StrSize = LengthOfGlobal + (sizeof(sync_id)*2+1); + typedef char NameBuf[StrSize]; + + void fill_name(NameBuf &name, const sync_id &id) + { + const char *n = "Global\\boost.ipc"; + std::size_t i = 0; + do{ + name[i] = n[i]; + ++i; + } while(n[i]); + std::size_t len = sizeof(NameBuf) - LengthOfGlobal; + bytes_to_str(&id.rand, sizeof(id.rand), &name[LengthOfGlobal], len); + } + + void erase_and_throw_if_error(void *hnd_val, const sync_id &id) + { + if(!hnd_val){ + map_.erase(id); + error_info err(winapi::get_last_error()); + throw interprocess_exception(err); + } + } + + void* open_or_create_semaphore(const sync_id &id, unsigned int initial_count) + { + NameBuf name; + fill_name(name, id); + void *hnd_val = winapi::open_or_create_semaphore + (name, (long)initial_count, (long)(((unsigned long)(-1))>>1), unrestricted_security.get_attributes()); + erase_and_throw_if_error(hnd_val, id); + return hnd_val; + } + + void* open_or_create_mutex(const sync_id &id) + { + NameBuf name; + fill_name(name, id); + void *hnd_val = winapi::open_or_create_mutex + (name, false, unrestricted_security.get_attributes()); + erase_and_throw_if_error(hnd_val, id); + return hnd_val; + } + + public: + void *obtain_mutex(const sync_id &id, bool *popen_created = 0) + { + scoped_lock<spin_mutex> lock(mtx_); + void *&hnd_val = map_[id]; + if(!hnd_val){ + hnd_val = open_or_create_mutex(id); + if(popen_created) *popen_created = true; + } + return hnd_val; + } + + void *obtain_semaphore(const sync_id &id, unsigned int initial_count, bool *popen_created = 0) + { + scoped_lock<spin_mutex> lock(mtx_); + void *&hnd_val = map_[id]; + if(!hnd_val){ + hnd_val = open_or_create_semaphore(id, initial_count); + if(popen_created) *popen_created = true; + } + return hnd_val; + } + + void destroy_handle(const sync_id &id) + { + scoped_lock<spin_mutex> lock(mtx_); + map_type::iterator it = map_.find(id); + if(it != map_.end()){ + winapi::close_handle(it->second); + map_.erase(it); + } + } + + private: + winapi::interprocess_all_access_security unrestricted_security; + spin_mutex mtx_; + map_type map_; +}; + + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP |