Squashed 'boost/' content from commit b4feb19f2

git-subtree-dir: boost
git-subtree-split: b4feb19f287ee92d87a9624b5d36b7cf46aeadeb
This commit is contained in:
Bill Somerville
2018-06-09 21:48:32 +01:00
commit 4ebe6417a5
12444 changed files with 2327021 additions and 0 deletions
@@ -0,0 +1,81 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP
#define BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/spin/wait.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class MutexType>
bool try_based_timed_lock(MutexType &m, const boost::posix_time::ptime &abs_time)
{
//Same as lock()
if(abs_time == boost::posix_time::pos_infin){
m.lock();
return true;
}
//Always try to lock to achieve POSIX guarantees:
// "Under no circumstance shall the function fail with a timeout if the mutex
// can be locked immediately. The validity of the abs_timeout parameter need not
// be checked if the mutex can be locked immediately."
else if(m.try_lock()){
return true;
}
else{
spin_wait swait;
while(microsec_clock::universal_time() < abs_time){
if(m.try_lock()){
return true;
}
swait.yield();
}
return false;
}
}
template<class MutexType>
void try_based_lock(MutexType &m)
{
if(!m.try_lock()){
spin_wait swait;
do{
if(m.try_lock()){
break;
}
else{
swait.yield();
}
}
while(1);
}
}
} //namespace ipcdetail
} //namespace interprocess
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP
+101
View File
@@ -0,0 +1,101 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2012-2012. 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_LOCKS_HPP
#define BOOST_INTERPROCESS_DETAIL_LOCKS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class Lock>
class internal_mutex_lock
{
typedef void (internal_mutex_lock::*unspecified_bool_type)();
public:
typedef typename Lock::mutex_type::internal_mutex_type mutex_type;
internal_mutex_lock(Lock &l)
: l_(l)
{}
mutex_type* mutex() const
{ return l_ ? &l_.mutex()->internal_mutex() : 0; }
void lock() { l_.lock(); }
void unlock() { l_.unlock(); }
operator unspecified_bool_type() const
{ return l_ ? &internal_mutex_lock::lock : 0; }
private:
Lock &l_;
};
template <class Lock>
class lock_inverter
{
Lock &l_;
public:
lock_inverter(Lock &l)
: l_(l)
{}
void lock() { l_.unlock(); }
void unlock() { l_.lock(); }
};
template <class Lock>
class lock_to_sharable
{
Lock &l_;
public:
explicit lock_to_sharable(Lock &l)
: l_(l)
{}
void lock() { l_.lock_sharable(); }
bool try_lock(){ return l_.try_lock_sharable(); }
void unlock() { l_.unlock_sharable(); }
};
template <class Lock>
class lock_to_wait
{
Lock &l_;
public:
explicit lock_to_wait(Lock &l)
: l_(l)
{}
void lock() { l_.wait(); }
bool try_lock(){ return l_.try_wait(); }
};
} //namespace ipcdetail
} //namespace interprocess
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_LOCKS_HPP
@@ -0,0 +1,188 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// Parts of the pthread code come from Boost Threads code.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_MUTEX_HPP
#define BOOST_INTERPROCESS_MUTEX_HPP
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/assert.hpp>
#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
#include <boost/interprocess/sync/posix/mutex.hpp>
#define BOOST_INTERPROCESS_USE_POSIX
//Experimental...
#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS)
#include <boost/interprocess/sync/windows/mutex.hpp>
#define BOOST_INTERPROCESS_USE_WINDOWS
#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#include <boost/interprocess/sync/spin/mutex.hpp>
#define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
namespace boost {
namespace interprocess {
namespace ipcdetail{
namespace robust_emulation_helpers {
template<class T>
class mutex_traits;
}}}}
#endif
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!\file
//!Describes a mutex class that can be placed in memory shared by
//!several processes.
namespace boost {
namespace interprocess {
class interprocess_condition;
//!Wraps a interprocess_mutex that can be placed in shared memory and can be
//!shared between processes. Allows timed lock tries
class interprocess_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
interprocess_mutex(const interprocess_mutex &);
interprocess_mutex &operator=(const interprocess_mutex &);
friend class interprocess_condition;
public:
#if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
#undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
typedef ipcdetail::spin_mutex internal_mutex_type;
private:
friend class ipcdetail::robust_emulation_helpers::mutex_traits<interprocess_mutex>;
void take_ownership(){ m_mutex.take_ownership(); }
public:
#elif defined(BOOST_INTERPROCESS_USE_POSIX)
#undef BOOST_INTERPROCESS_USE_POSIX
typedef ipcdetail::posix_mutex internal_mutex_type;
#elif defined(BOOST_INTERPROCESS_USE_WINDOWS)
#undef BOOST_INTERPROCESS_USE_WINDOWS
typedef ipcdetail::windows_mutex internal_mutex_type;
#else
#error "Unknown platform for interprocess_mutex"
#endif
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Constructor.
//!Throws interprocess_exception on error.
interprocess_mutex();
//!Destructor. If any process uses the mutex after the destructor is called
//!the result is undefined. Does not throw.
~interprocess_mutex();
//!Effects: The calling thread tries to obtain ownership of the mutex, and
//! if another thread has ownership of the mutex, it waits until it can
//! obtain the ownership. If a thread takes ownership of the mutex the
//! mutex must be unlocked by the same mutex.
//!Throws: interprocess_exception on error.
void lock();
//!Effects: The calling thread tries to obtain ownership of the mutex, and
//! if another thread has ownership of the mutex returns immediately.
//!Returns: If the thread acquires ownership of the mutex, returns true, if
//! the another thread has ownership of the mutex, returns false.
//!Throws: interprocess_exception on error.
bool try_lock();
//!Effects: The calling thread will try to obtain exclusive ownership of the
//! mutex if it can do so in until the specified time is reached. If the
//! mutex supports recursive locking, the mutex must be unlocked the same
//! number of times it is locked.
//!Returns: If the thread acquires ownership of the mutex, returns true, if
//! the timeout expires returns false.
//!Throws: interprocess_exception on error.
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Effects: The calling thread releases the exclusive ownership of the mutex.
//!Throws: interprocess_exception on error.
void unlock();
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
internal_mutex_type &internal_mutex()
{ return m_mutex; }
const internal_mutex_type &internal_mutex() const
{ return m_mutex; }
private:
internal_mutex_type m_mutex;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
} //namespace interprocess {
} //namespace boost {
namespace boost {
namespace interprocess {
inline interprocess_mutex::interprocess_mutex(){}
inline interprocess_mutex::~interprocess_mutex(){}
inline void interprocess_mutex::lock()
{
#ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING
boost::posix_time::ptime wait_time
= microsec_clock::universal_time()
+ boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS);
if (!m_mutex.timed_lock(wait_time))
{
throw interprocess_exception(timeout_when_locking_error
, "Interprocess mutex timeout when locking. Possible deadlock: "
"owner died without unlocking?");
}
#else
m_mutex.lock();
#endif
}
inline bool interprocess_mutex::try_lock()
{ return m_mutex.try_lock(); }
inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return m_mutex.timed_lock(abs_time); }
inline void interprocess_mutex::unlock()
{ m_mutex.unlock(); }
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MUTEX_HPP
+63
View File
@@ -0,0 +1,63 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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_LOCK_OPTIONS_HPP
#define BOOST_INTERPROCESS_LOCK_OPTIONS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
//!\file
//!Describes the lock options with associated with interprocess_mutex lock constructors.
namespace boost {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace posix_time
{ class ptime; }
#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace interprocess {
//!Type to indicate to a mutex lock constructor that must not lock the mutex.
struct defer_lock_type{};
//!Type to indicate to a mutex lock constructor that must try to lock the mutex.
struct try_to_lock_type {};
//!Type to indicate to a mutex lock constructor that the mutex is already locked.
struct accept_ownership_type{};
//!An object indicating that the locking
//!must be deferred.
static const defer_lock_type defer_lock = defer_lock_type();
//!An object indicating that a try_lock()
//!operation must be executed.
static const try_to_lock_type try_to_lock = try_to_lock_type();
//!An object indicating that the ownership of lockable
//!object must be accepted by the new owner.
static const accept_ownership_type accept_ownership = accept_ownership_type();
} // namespace interprocess {
} // namespace boost{
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_LOCK_OPTIONS_HPP
+175
View File
@@ -0,0 +1,175 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_NAMED_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/permissions.hpp>
#if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
#include <boost/interprocess/sync/posix/named_mutex.hpp>
#define BOOST_INTERPROCESS_USE_POSIX_SEMAPHORES
#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS)
#include <boost/interprocess/sync/windows/named_mutex.hpp>
#define BOOST_INTERPROCESS_USE_WINDOWS
#else
#include <boost/interprocess/sync/shm/named_mutex.hpp>
#endif
//!\file
//!Describes a named mutex class for inter-process synchronization
namespace boost {
namespace interprocess {
class named_condition;
//!A mutex with a global name, so it can be found from different
//!processes. This mutex can't be placed in shared memory, and
//!each process should have it's own named_mutex.
class named_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
named_mutex();
named_mutex(const named_mutex &);
named_mutex &operator=(const named_mutex &);
friend class named_condition;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Creates a global mutex with a name.
//!Throws interprocess_exception on error.
named_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions());
//!Opens or creates a global mutex with a name.
//!If the mutex is created, this call is equivalent to
//!named_mutex(create_only_t, ... )
//!If the mutex is already created, this call is equivalent
//!named_mutex(open_only_t, ... )
//!Does not throw
named_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions());
//!Opens a global mutex with a name if that mutex is previously
//!created. If it is not previously created this function throws
//!interprocess_exception.
named_mutex(open_only_t open_only, const char *name);
//!Destroys *this and indicates that the calling process is finished using
//!the resource. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~named_mutex();
//!Unlocks a previously locked
//!mutex.
void unlock();
//!Locks the mutex, sleeps when the mutex is already locked.
//!Throws interprocess_exception if a severe error is found
void lock();
//!Tries to lock the mutex, returns false when the mutex
//!is already locked, returns true when success.
//!Throws interprocess_exception if a severe error is found
bool try_lock();
//!Tries to lock the the mutex until time abs_time,
//!Returns false when timeout expires, returns true when locks.
//!Throws interprocess_exception if a severe error is found
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Erases a named mutex from the system.
//!Returns false on error. Never throws.
static bool remove(const char *name);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction();
public:
#if defined(BOOST_INTERPROCESS_USE_POSIX_SEMAPHORES)
typedef ipcdetail::posix_named_mutex internal_mutex_type;
#undef BOOST_INTERPROCESS_USE_POSIX_SEMAPHORES
#elif defined(BOOST_INTERPROCESS_USE_WINDOWS)
typedef ipcdetail::windows_named_mutex internal_mutex_type;
#undef BOOST_INTERPROCESS_USE_WINDOWS
#else
typedef ipcdetail::shm_named_mutex internal_mutex_type;
#endif
internal_mutex_type &internal_mutex()
{ return m_mut; }
internal_mutex_type m_mut;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inline named_mutex::named_mutex(create_only_t, const char *name, const permissions &perm)
: m_mut(create_only_t(), name, perm)
{}
inline named_mutex::named_mutex(open_or_create_t, const char *name, const permissions &perm)
: m_mut(open_or_create_t(), name, perm)
{}
inline named_mutex::named_mutex(open_only_t, const char *name)
: m_mut(open_only_t(), name)
{}
inline void named_mutex::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_mut); }
inline named_mutex::~named_mutex()
{}
inline void named_mutex::lock()
{ m_mut.lock(); }
inline void named_mutex::unlock()
{ m_mut.unlock(); }
inline bool named_mutex::try_lock()
{ return m_mut.try_lock(); }
inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return m_mut.timed_lock(abs_time); }
inline bool named_mutex::remove(const char *name)
{ return internal_mutex_type::remove(name); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NAMED_MUTEX_HPP
+143
View File
@@ -0,0 +1,143 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// Parts of the pthread code come from Boost Threads code:
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP
#define BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <pthread.h>
#include <errno.h>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
# include <boost/interprocess/detail/os_thread_functions.hpp>
# include <boost/interprocess/sync/detail/common_algorithms.hpp>
#endif
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class posix_condition;
class posix_mutex
{
posix_mutex(const posix_mutex &);
posix_mutex &operator=(const posix_mutex &);
public:
posix_mutex();
~posix_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
friend class posix_condition;
private:
pthread_mutex_t m_mut;
};
inline posix_mutex::posix_mutex()
{
mutexattr_wrapper mut_attr;
mutex_initializer mut(m_mut, mut_attr);
mut.release();
}
inline posix_mutex::~posix_mutex()
{
int res = pthread_mutex_destroy(&m_mut);
BOOST_ASSERT(res == 0);(void)res;
}
inline void posix_mutex::lock()
{
if (pthread_mutex_lock(&m_mut) != 0)
throw lock_exception();
}
inline bool posix_mutex::try_lock()
{
int res = pthread_mutex_trylock(&m_mut);
if (!(res == 0 || res == EBUSY))
throw lock_exception();
return res == 0;
}
inline bool posix_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
//Posix does not support infinity absolute time so handle it here
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
timespec ts = ptime_to_timespec(abs_time);
int res = pthread_mutex_timedlock(&m_mut, &ts);
if (res != 0 && res != ETIMEDOUT)
throw lock_exception();
return res == 0;
#else //BOOST_INTERPROCESS_POSIX_TIMEOUTS
return ipcdetail::try_based_timed_lock(*this, abs_time);
#endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS
}
inline void posix_mutex::unlock()
{
int res = 0;
res = pthread_mutex_unlock(&m_mut);
(void)res;
BOOST_ASSERT(res == 0);
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP
@@ -0,0 +1,114 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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_POSIX_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_POSIX_NAMED_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/sync/posix/named_semaphore.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class named_condition;
class posix_named_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
posix_named_mutex();
posix_named_mutex(const posix_named_mutex &);
posix_named_mutex &operator=(const posix_named_mutex &);
friend class named_condition;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
posix_named_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions());
posix_named_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions());
posix_named_mutex(open_only_t open_only, const char *name);
~posix_named_mutex();
void unlock();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
static bool remove(const char *name);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
friend class interprocess_tester;
void dont_close_on_destruction();
posix_named_semaphore m_sem;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inline posix_named_mutex::posix_named_mutex(create_only_t, const char *name, const permissions &perm)
: m_sem(create_only, name, 1, perm)
{}
inline posix_named_mutex::posix_named_mutex(open_or_create_t, const char *name, const permissions &perm)
: m_sem(open_or_create, name, 1, perm)
{}
inline posix_named_mutex::posix_named_mutex(open_only_t, const char *name)
: m_sem(open_only, name)
{}
inline void posix_named_mutex::dont_close_on_destruction()
{ interprocess_tester::dont_close_on_destruction(m_sem); }
inline posix_named_mutex::~posix_named_mutex()
{}
inline void posix_named_mutex::lock()
{ m_sem.wait(); }
inline void posix_named_mutex::unlock()
{ m_sem.post(); }
inline bool posix_named_mutex::try_lock()
{ return m_sem.try_wait(); }
inline bool posix_named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return m_sem.timed_wait(abs_time); }
inline bool posix_named_mutex::remove(const char *name)
{ return posix_named_semaphore::remove(name); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_POSIX_NAMED_MUTEX_HPP
@@ -0,0 +1,88 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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_POSIX_NAMED_CONDITION_HPP
#define BOOST_INTERPROCESS_POSIX_NAMED_CONDITION_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/posix/semaphore_wrapper.hpp>
namespace boost {
namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace ipcdetail{ class interprocess_tester; }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
namespace ipcdetail {
class posix_named_semaphore
{
posix_named_semaphore();
posix_named_semaphore(const posix_named_semaphore&);
posix_named_semaphore &operator= (const posix_named_semaphore &);
public:
posix_named_semaphore
(create_only_t, const char *name, unsigned int initialCount, const permissions &perm = permissions())
{ semaphore_open(mp_sem, DoCreate, name, initialCount, perm); }
posix_named_semaphore(open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm = permissions())
{ semaphore_open(mp_sem, DoOpenOrCreate, name, initialCount, perm); }
posix_named_semaphore(open_only_t, const char *name)
{ semaphore_open(mp_sem, DoOpen, name); }
~posix_named_semaphore()
{
if(mp_sem != BOOST_INTERPROCESS_POSIX_SEM_FAILED)
semaphore_close(mp_sem);
}
void post()
{ semaphore_post(mp_sem); }
void wait()
{ semaphore_wait(mp_sem); }
bool try_wait()
{ return semaphore_try_wait(mp_sem); }
bool timed_wait(const boost::posix_time::ptime &abs_time)
{ return semaphore_timed_wait(mp_sem, abs_time); }
static bool remove(const char *name)
{ return semaphore_unlink(name); }
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction()
{ mp_sem = BOOST_INTERPROCESS_POSIX_SEM_FAILED; }
sem_t *mp_sem;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_POSIX_NAMED_CONDITION_HPP
@@ -0,0 +1,172 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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_PTHREAD_HELPERS_HPP
#define BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <pthread.h>
#include <errno.h>
#include <boost/interprocess/exceptions.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail{
#if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED
//!Makes pthread_mutexattr_t cleanup easy when using exceptions
struct mutexattr_wrapper
{
//!Constructor
mutexattr_wrapper(bool recursive = false)
{
if(pthread_mutexattr_init(&m_attr)!=0 ||
pthread_mutexattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0 ||
(recursive &&
pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE)!= 0 ))
throw interprocess_exception("pthread_mutexattr_xxxx failed");
}
//!Destructor
~mutexattr_wrapper() { pthread_mutexattr_destroy(&m_attr); }
//!This allows using mutexattr_wrapper as pthread_mutexattr_t
operator pthread_mutexattr_t&() { return m_attr; }
pthread_mutexattr_t m_attr;
};
//!Makes pthread_condattr_t cleanup easy when using exceptions
struct condattr_wrapper
{
//!Constructor
condattr_wrapper()
{
if(pthread_condattr_init(&m_attr)!=0 ||
pthread_condattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0)
throw interprocess_exception("pthread_condattr_xxxx failed");
}
//!Destructor
~condattr_wrapper() { pthread_condattr_destroy(&m_attr); }
//!This allows using condattr_wrapper as pthread_condattr_t
operator pthread_condattr_t&(){ return m_attr; }
pthread_condattr_t m_attr;
};
//!Makes initialized pthread_mutex_t cleanup easy when using exceptions
class mutex_initializer
{
public:
//!Constructor. Takes interprocess_mutex attributes to initialize the interprocess_mutex
mutex_initializer(pthread_mutex_t &mut, pthread_mutexattr_t &mut_attr)
: mp_mut(&mut)
{
if(pthread_mutex_init(mp_mut, &mut_attr) != 0)
throw interprocess_exception("pthread_mutex_init failed");
}
~mutex_initializer() { if(mp_mut) pthread_mutex_destroy(mp_mut); }
void release() {mp_mut = 0; }
private:
pthread_mutex_t *mp_mut;
};
//!Makes initialized pthread_cond_t cleanup easy when using exceptions
class condition_initializer
{
public:
condition_initializer(pthread_cond_t &cond, pthread_condattr_t &cond_attr)
: mp_cond(&cond)
{
if(pthread_cond_init(mp_cond, &cond_attr)!= 0)
throw interprocess_exception("pthread_cond_init failed");
}
~condition_initializer() { if(mp_cond) pthread_cond_destroy(mp_cond); }
void release() { mp_cond = 0; }
private:
pthread_cond_t *mp_cond;
};
#endif // #if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED
#if defined(BOOST_INTERPROCESS_POSIX_BARRIERS) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
//!Makes pthread_barrierattr_t cleanup easy when using exceptions
struct barrierattr_wrapper
{
//!Constructor
barrierattr_wrapper()
{
if(pthread_barrierattr_init(&m_attr)!=0 ||
pthread_barrierattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0)
throw interprocess_exception("pthread_barrierattr_xxx failed");
}
//!Destructor
~barrierattr_wrapper() { pthread_barrierattr_destroy(&m_attr); }
//!This allows using mutexattr_wrapper as pthread_barrierattr_t
operator pthread_barrierattr_t&() { return m_attr; }
pthread_barrierattr_t m_attr;
};
//!Makes initialized pthread_barrier_t cleanup easy when using exceptions
class barrier_initializer
{
public:
//!Constructor. Takes barrier attributes to initialize the barrier
barrier_initializer(pthread_barrier_t &mut,
pthread_barrierattr_t &mut_attr,
int count)
: mp_barrier(&mut)
{
if(pthread_barrier_init(mp_barrier, &mut_attr, count) != 0)
throw interprocess_exception("pthread_barrier_init failed");
}
~barrier_initializer() { if(mp_barrier) pthread_barrier_destroy(mp_barrier); }
void release() {mp_barrier = 0; }
private:
pthread_barrier_t *mp_barrier;
};
#endif //#if defined(BOOST_INTERPROCESS_POSIX_BARRIERS) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
}//namespace ipcdetail
}//namespace interprocess
}//namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //ifdef BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP
@@ -0,0 +1,48 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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_PTIME_TO_TIMESPEC_HPP
#define BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
inline timespec ptime_to_timespec (const boost::posix_time::ptime &tm)
{
const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
//Avoid negative absolute times
boost::posix_time::time_duration duration = (tm <= epoch) ? boost::posix_time::time_duration(epoch - epoch)
: boost::posix_time::time_duration(tm - epoch);
timespec ts;
ts.tv_sec = duration.total_seconds();
ts.tv_nsec = duration.total_nanoseconds() % 1000000000;
return ts;
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#endif //ifndef BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP
@@ -0,0 +1,253 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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_POSIX_SEMAPHORE_WRAPPER_HPP
#define BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/shared_dir_helpers.hpp>
#include <boost/interprocess/permissions.hpp>
#include <fcntl.h> //O_CREAT, O_*...
#include <unistd.h> //close
#include <string> //std::string
#include <semaphore.h> //sem_* family, SEM_VALUE_MAX
#include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
#include <boost/assert.hpp>
#ifdef SEM_FAILED
#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(SEM_FAILED))
#else
#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(-1))
#endif
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
#else
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/sync/detail/locks.hpp>
#include <boost/interprocess/sync/detail/common_algorithms.hpp>
#endif
namespace boost {
namespace interprocess {
namespace ipcdetail {
#ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
inline bool semaphore_open
(sem_t *&handle, create_enum_t type, const char *origname,
unsigned int count = 0, const permissions &perm = permissions())
{
std::string name;
#ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
add_leading_slash(origname, name);
#else
create_shared_dir_cleaning_old_and_get_filepath(origname, name);
#endif
//Create new mapping
int oflag = 0;
switch(type){
case DoOpen:
{
//No addition
handle = ::sem_open(name.c_str(), oflag);
}
break;
case DoOpenOrCreate:
case DoCreate:
{
while(1){
oflag = (O_CREAT | O_EXCL);
handle = ::sem_open(name.c_str(), oflag, perm.get_permissions(), count);
if(handle != BOOST_INTERPROCESS_POSIX_SEM_FAILED){
//We can't change semaphore permissions!
//::fchmod(handle, perm.get_permissions());
break;
}
else if(errno == EEXIST && type == DoOpenOrCreate){
oflag = 0;
if( (handle = ::sem_open(name.c_str(), oflag)) != BOOST_INTERPROCESS_POSIX_SEM_FAILED
|| (errno != ENOENT) ){
break;
}
}
else{
break;
}
}
}
break;
default:
{
error_info err(other_error);
throw interprocess_exception(err);
}
}
//Check for error
if(handle == BOOST_INTERPROCESS_POSIX_SEM_FAILED){
throw interprocess_exception(error_info(errno));
}
return true;
}
inline void semaphore_close(sem_t *handle)
{
int ret = sem_close(handle);
if(ret != 0){
BOOST_ASSERT(0);
}
}
inline bool semaphore_unlink(const char *semname)
{
try{
std::string sem_str;
#ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
add_leading_slash(semname, sem_str);
#else
shared_filepath(semname, sem_str);
#endif
return 0 == sem_unlink(sem_str.c_str());
}
catch(...){
return false;
}
}
#endif //BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
#ifdef BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES
inline void semaphore_init(sem_t *handle, unsigned int initialCount)
{
int ret = sem_init(handle, 1, initialCount);
//According to SUSV3 version 2003 edition, the return value of a successful
//sem_init call is not defined, but -1 is returned on failure.
//In the future, a successful call might be required to return 0.
if(ret == -1){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline void semaphore_destroy(sem_t *handle)
{
int ret = sem_destroy(handle);
if(ret != 0){
BOOST_ASSERT(0);
}
}
#endif //BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES
inline void semaphore_post(sem_t *handle)
{
int ret = sem_post(handle);
if(ret != 0){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline void semaphore_wait(sem_t *handle)
{
int ret = sem_wait(handle);
if(ret != 0){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline bool semaphore_try_wait(sem_t *handle)
{
int res = sem_trywait(handle);
if(res == 0)
return true;
if(system_error_code() == EAGAIN){
return false;
}
error_info err = system_error_code();
throw interprocess_exception(err);
}
#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
struct semaphore_wrapper_try_wrapper
{
explicit semaphore_wrapper_try_wrapper(sem_t *handle)
: m_handle(handle)
{}
void wait()
{ semaphore_wait(m_handle); }
bool try_wait()
{ return semaphore_try_wait(m_handle); }
private:
sem_t *m_handle;
};
#endif
inline bool semaphore_timed_wait(sem_t *handle, const boost::posix_time::ptime &abs_time)
{
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
//Posix does not support infinity absolute time so handle it here
if(abs_time == boost::posix_time::pos_infin){
semaphore_wait(handle);
return true;
}
timespec tspec = ptime_to_timespec(abs_time);
for (;;){
int res = sem_timedwait(handle, &tspec);
if(res == 0)
return true;
if (res > 0){
//buggy glibc, copy the returned error code to errno
errno = res;
}
if(system_error_code() == ETIMEDOUT){
return false;
}
error_info err = system_error_code();
throw interprocess_exception(err);
}
return false;
#else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
semaphore_wrapper_try_wrapper swtw(handle);
ipcdetail::lock_to_wait<semaphore_wrapper_try_wrapper> lw(swtw);
return ipcdetail::try_based_timed_lock(lw, abs_time);
#endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP
+377
View File
@@ -0,0 +1,377 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This interface is inspired by Howard Hinnant's lock proposal.
// http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SCOPED_LOCK_HPP
#define BOOST_INTERPROCESS_SCOPED_LOCK_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/sync/lock_options.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/detail/simple_swap.hpp>
//!\file
//!Describes the scoped_lock class.
namespace boost {
namespace interprocess {
//!scoped_lock is meant to carry out the tasks for locking, unlocking, try-locking
//!and timed-locking (recursive or not) for the Mutex. The Mutex need not supply all
//!of this functionality. If the client of scoped_lock<Mutex> does not use
//!functionality which the Mutex does not supply, no harm is done. Mutex ownership
//!transfer is supported through the syntax of move semantics. Ownership transfer
//!is allowed both by construction and assignment. The scoped_lock does not support
//!copy semantics. A compile time error results if copy construction or copy
//!assignment is attempted. Mutex ownership can also be moved from an
//!upgradable_lock and sharable_lock via constructor. In this role, scoped_lock
//!shares the same functionality as a write_lock.
template <class Mutex>
class scoped_lock
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
typedef scoped_lock<Mutex> this_type;
BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_lock)
typedef bool this_type::*unspecified_bool_type;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef Mutex mutex_type;
//!Effects: Default constructs a scoped_lock.
//!Postconditions: owns() == false and mutex() == 0.
scoped_lock()
: mp_mutex(0), m_locked(false)
{}
//!Effects: m.lock().
//!Postconditions: owns() == true and mutex() == &m.
//!Notes: The constructor will take ownership of the mutex. If another thread
//! already owns the mutex, this thread will block until the mutex is released.
//! Whether or not this constructor handles recursive locking depends upon the mutex.
explicit scoped_lock(mutex_type& m)
: mp_mutex(&m), m_locked(false)
{ mp_mutex->lock(); m_locked = true; }
//!Postconditions: owns() == false, and mutex() == &m.
//!Notes: The constructor will not take ownership of the mutex. There is no effect
//! required on the referenced mutex.
scoped_lock(mutex_type& m, defer_lock_type)
: mp_mutex(&m), m_locked(false)
{}
//!Postconditions: owns() == true, and mutex() == &m.
//!Notes: The constructor will suppose that the mutex is already locked. There
//! is no effect required on the referenced mutex.
scoped_lock(mutex_type& m, accept_ownership_type)
: mp_mutex(&m), m_locked(true)
{}
//!Effects: m.try_lock().
//!Postconditions: mutex() == &m. owns() == the return value of the
//! m.try_lock() executed within the constructor.
//!Notes: The constructor will take ownership of the mutex if it can do
//! so without waiting. Whether or not this constructor handles recursive
//! locking depends upon the mutex. If the mutex_type does not support try_lock,
//! this constructor will fail at compile time if instantiated, but otherwise
//! have no effect.
scoped_lock(mutex_type& m, try_to_lock_type)
: mp_mutex(&m), m_locked(mp_mutex->try_lock())
{}
//!Effects: m.timed_lock(abs_time).
//!Postconditions: mutex() == &m. owns() == the return value of the
//! m.timed_lock(abs_time) executed within the constructor.
//!Notes: The constructor will take ownership of the mutex if it can do
//! it until abs_time is reached. Whether or not this constructor
//! handles recursive locking depends upon the mutex. If the mutex_type
//! does not support try_lock, this constructor will fail at compile
//! time if instantiated, but otherwise have no effect.
scoped_lock(mutex_type& m, const boost::posix_time::ptime& abs_time)
: mp_mutex(&m), m_locked(mp_mutex->timed_lock(abs_time))
{}
//!Postconditions: mutex() == the value scop.mutex() had before the
//! constructor executes. s1.mutex() == 0. owns() == the value of
//! scop.owns() before the constructor executes. scop.owns().
//!Notes: If the scop scoped_lock owns the mutex, ownership is moved
//! to thisscoped_lock with no blocking. If the scop scoped_lock does not
//! own the mutex, then neither will this scoped_lock. Only a moved
//! scoped_lock's will match this signature. An non-moved scoped_lock
//! can be moved with the expression: "boost::move(lock);". This
//! constructor does not alter the state of the mutex, only potentially
//! who owns it.
scoped_lock(BOOST_RV_REF(scoped_lock) scop)
: mp_mutex(0), m_locked(scop.owns())
{ mp_mutex = scop.release(); }
//!Effects: If upgr.owns() then calls unlock_upgradable_and_lock() on the
//! referenced mutex. upgr.release() is called.
//!Postconditions: mutex() == the value upgr.mutex() had before the construction.
//! upgr.mutex() == 0. owns() == upgr.owns() before the construction.
//! upgr.owns() == false after the construction.
//!Notes: If upgr is locked, this constructor will lock this scoped_lock while
//! unlocking upgr. If upgr is unlocked, then this scoped_lock will be
//! unlocked as well. Only a moved upgradable_lock's will match this
//! signature. An non-moved upgradable_lock can be moved with
//! the expression: "boost::move(lock);" This constructor may block if
//! other threads hold a sharable_lock on this mutex (sharable_lock's can
//! share ownership with an upgradable_lock).
template<class T>
explicit scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr
, typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
: mp_mutex(0), m_locked(false)
{
upgradable_lock<mutex_type> &u_lock = upgr;
if(u_lock.owns()){
u_lock.mutex()->unlock_upgradable_and_lock();
m_locked = true;
}
mp_mutex = u_lock.release();
}
//!Effects: If upgr.owns() then calls try_unlock_upgradable_and_lock() on the
//!referenced mutex:
//! a)if try_unlock_upgradable_and_lock() returns true then mutex() obtains
//! the value from upgr.release() and owns() is set to true.
//! b)if try_unlock_upgradable_and_lock() returns false then upgr is
//! unaffected and this scoped_lock construction as the same effects as
//! a default construction.
//! c)Else upgr.owns() is false. mutex() obtains the value from upgr.release()
//! and owns() is set to false
//!Notes: This construction will not block. It will try to obtain mutex
//! ownership from upgr immediately, while changing the lock type from a
//! "read lock" to a "write lock". If the "read lock" isn't held in the
//! first place, the mutex merely changes type to an unlocked "write lock".
//! If the "read lock" is held, then mutex transfer occurs only if it can
//! do so in a non-blocking manner.
template<class T>
scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr, try_to_lock_type
, typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
: mp_mutex(0), m_locked(false)
{
upgradable_lock<mutex_type> &u_lock = upgr;
if(u_lock.owns()){
if((m_locked = u_lock.mutex()->try_unlock_upgradable_and_lock()) == true){
mp_mutex = u_lock.release();
}
}
else{
u_lock.release();
}
}
//!Effects: If upgr.owns() then calls timed_unlock_upgradable_and_lock(abs_time)
//! on the referenced mutex:
//! a)if timed_unlock_upgradable_and_lock(abs_time) returns true then mutex()
//! obtains the value from upgr.release() and owns() is set to true.
//! b)if timed_unlock_upgradable_and_lock(abs_time) returns false then upgr
//! is unaffected and this scoped_lock construction as the same effects
//! as a default construction.
//! c)Else upgr.owns() is false. mutex() obtains the value from upgr.release()
//! and owns() is set to false
//!Notes: This construction will not block. It will try to obtain mutex ownership
//! from upgr immediately, while changing the lock type from a "read lock" to a
//! "write lock". If the "read lock" isn't held in the first place, the mutex
//! merely changes type to an unlocked "write lock". If the "read lock" is held,
//! then mutex transfer occurs only if it can do so in a non-blocking manner.
template<class T>
scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr, boost::posix_time::ptime &abs_time
, typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
: mp_mutex(0), m_locked(false)
{
upgradable_lock<mutex_type> &u_lock = upgr;
if(u_lock.owns()){
if((m_locked = u_lock.mutex()->timed_unlock_upgradable_and_lock(abs_time)) == true){
mp_mutex = u_lock.release();
}
}
else{
u_lock.release();
}
}
//!Effects: If shar.owns() then calls try_unlock_sharable_and_lock() on the
//!referenced mutex.
//! a)if try_unlock_sharable_and_lock() returns true then mutex() obtains
//! the value from shar.release() and owns() is set to true.
//! b)if try_unlock_sharable_and_lock() returns false then shar is
//! unaffected and this scoped_lock construction has the same
//! effects as a default construction.
//! c)Else shar.owns() is false. mutex() obtains the value from
//! shar.release() and owns() is set to false
//!Notes: This construction will not block. It will try to obtain mutex
//! ownership from shar immediately, while changing the lock type from a
//! "read lock" to a "write lock". If the "read lock" isn't held in the
//! first place, the mutex merely changes type to an unlocked "write lock".
//! If the "read lock" is held, then mutex transfer occurs only if it can
//! do so in a non-blocking manner.
template<class T>
scoped_lock(BOOST_RV_REF(sharable_lock<T>) shar, try_to_lock_type
, typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
: mp_mutex(0), m_locked(false)
{
sharable_lock<mutex_type> &s_lock = shar;
if(s_lock.owns()){
if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock()) == true){
mp_mutex = s_lock.release();
}
}
else{
s_lock.release();
}
}
//!Effects: if (owns()) mp_mutex->unlock().
//!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/
~scoped_lock()
{
try{ if(m_locked && mp_mutex) mp_mutex->unlock(); }
catch(...){}
}
//!Effects: If owns() before the call, then unlock() is called on mutex().
//! *this gets the state of scop and scop gets set to a default constructed state.
//!Notes: With a recursive mutex it is possible that both this and scop own
//! the same mutex before the assignment. In this case, this will own the
//! mutex after the assignment (and scop will not), but the mutex's lock
//! count will be decremented by one.
scoped_lock &operator=(BOOST_RV_REF(scoped_lock) scop)
{
if(this->owns())
this->unlock();
m_locked = scop.owns();
mp_mutex = scop.release();
return *this;
}
//!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
//! exception. Calls lock() on the referenced mutex.
//!Postconditions: owns() == true.
//!Notes: The scoped_lock changes from a state of not owning the mutex, to
//! owning the mutex, blocking if necessary.
void lock()
{
if(!mp_mutex || m_locked)
throw lock_exception();
mp_mutex->lock();
m_locked = true;
}
//!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
//! exception. Calls try_lock() on the referenced mutex.
//!Postconditions: owns() == the value returned from mutex()->try_lock().
//!Notes: The scoped_lock changes from a state of not owning the mutex, to
//! owning the mutex, but only if blocking was not required. If the
//! mutex_type does not support try_lock(), this function will fail at
//! compile time if instantiated, but otherwise have no effect.*/
bool try_lock()
{
if(!mp_mutex || m_locked)
throw lock_exception();
m_locked = mp_mutex->try_lock();
return m_locked;
}
//!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
//! exception. Calls timed_lock(abs_time) on the referenced mutex.
//!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time).
//!Notes: The scoped_lock changes from a state of not owning the mutex, to
//! owning the mutex, but only if it can obtain ownership by the specified
//! time. If the mutex_type does not support timed_lock (), this function
//! will fail at compile time if instantiated, but otherwise have no effect.*/
bool timed_lock(const boost::posix_time::ptime& abs_time)
{
if(!mp_mutex || m_locked)
throw lock_exception();
m_locked = mp_mutex->timed_lock(abs_time);
return m_locked;
}
//!Effects: If mutex() == 0 or if not locked, throws a lock_exception()
//! exception. Calls unlock() on the referenced mutex.
//!Postconditions: owns() == false.
//!Notes: The scoped_lock changes from a state of owning the mutex, to not
//! owning the mutex.*/
void unlock()
{
if(!mp_mutex || !m_locked)
throw lock_exception();
mp_mutex->unlock();
m_locked = false;
}
//!Effects: Returns true if this scoped_lock has acquired
//!the referenced mutex.
bool owns() const
{ return m_locked && mp_mutex; }
//!Conversion to bool.
//!Returns owns().
operator unspecified_bool_type() const
{ return m_locked? &this_type::m_locked : 0; }
//!Effects: Returns a pointer to the referenced mutex, or 0 if
//!there is no mutex to reference.
mutex_type* mutex() const
{ return mp_mutex; }
//!Effects: Returns a pointer to the referenced mutex, or 0 if there is no
//! mutex to reference.
//!Postconditions: mutex() == 0 and owns() == false.
mutex_type* release()
{
mutex_type *mut = mp_mutex;
mp_mutex = 0;
m_locked = false;
return mut;
}
//!Effects: Swaps state with moved lock.
//!Throws: Nothing.
void swap( scoped_lock<mutex_type> &other)
{
(simple_swap)(mp_mutex, other.mp_mutex);
(simple_swap)(m_locked, other.m_locked);
}
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
mutex_type *mp_mutex;
bool m_locked;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_SCOPED_LOCK_HPP
@@ -0,0 +1,81 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2012. 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_SYNC_NAMED_CREATION_FUNCTOR_HPP
#define BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/container/detail/placement_new.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
struct named_creation_functor_no_arg{};
template <class T, class Arg = named_creation_functor_no_arg>
class named_creation_functor
{
typedef named_creation_functor_no_arg no_arg_t;
public:
named_creation_functor(create_enum_t type, Arg arg = Arg())
: m_creation_type(type), m_arg(arg){}
template<class ArgType>
void construct(void *address, typename enable_if_c<is_same<ArgType, no_arg_t>::value>::type * = 0) const
{ ::new(address, boost_container_new_t())T; }
template<class ArgType>
void construct(void *address, typename enable_if_c<!is_same<ArgType, no_arg_t>::value>::type * = 0) const
{ ::new(address, boost_container_new_t())T(m_arg); }
bool operator()(void *address, std::size_t, bool created) const
{
switch(m_creation_type){
case DoOpen:
return true;
break;
case DoCreate:
case DoOpenOrCreate:
if(created){
construct<Arg>(address);
}
return true;
break;
default:
return false;
break;
}
}
static std::size_t get_min_size()
{ return sizeof(T); }
private:
create_enum_t m_creation_type;
Arg m_arg;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#endif //BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP
+181
View File
@@ -0,0 +1,181 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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_SHM_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_SHM_NAMED_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/sync/shm/named_creation_functor.hpp>
//!\file
//!Describes a named mutex class for inter-process synchronization
namespace boost {
namespace interprocess {
namespace ipcdetail {
class named_condition;
//!A mutex with a global name, so it can be found from different
//!processes. This mutex can't be placed in shared memory, and
//!each process should have it's own named mutex.
class shm_named_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
shm_named_mutex();
shm_named_mutex(const shm_named_mutex &);
shm_named_mutex &operator=(const shm_named_mutex &);
friend class named_condition;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Creates a global interprocess_mutex with a name.
//!Throws interprocess_exception on error.
shm_named_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions());
//!Opens or creates a global mutex with a name.
//!If the mutex is created, this call is equivalent to
//!shm_named_mutex(create_only_t, ... )
//!If the mutex is already created, this call is equivalent
//!shm_named_mutex(open_only_t, ... )
//!Does not throw
shm_named_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions());
//!Opens a global mutex with a name if that mutex is previously
//!created. If it is not previously created this function throws
//!interprocess_exception.
shm_named_mutex(open_only_t open_only, const char *name);
//!Destroys *this and indicates that the calling process is finished using
//!the resource. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~shm_named_mutex();
//!Unlocks a previously locked
//!interprocess_mutex.
void unlock();
//!Locks interprocess_mutex, sleeps when interprocess_mutex is already locked.
//!Throws interprocess_exception if a severe error is found
void lock();
//!Tries to lock the interprocess_mutex, returns false when interprocess_mutex
//!is already locked, returns true when success.
//!Throws interprocess_exception if a severe error is found
bool try_lock();
//!Tries to lock the interprocess_mutex until time abs_time,
//!Returns false when timeout expires, returns true when locks.
//!Throws interprocess_exception if a severe error is found
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Erases a named mutex from the system.
//!Returns false on error. Never throws.
static bool remove(const char *name);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
typedef interprocess_mutex internal_mutex_type;
interprocess_mutex &internal_mutex()
{ return *static_cast<interprocess_mutex*>(m_shmem.get_user_address()); }
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction();
typedef ipcdetail::managed_open_or_create_impl<shared_memory_object, 0, true, false> open_create_impl_t;
open_create_impl_t m_shmem;
typedef ipcdetail::named_creation_functor<interprocess_mutex> construct_func_t;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inline void shm_named_mutex::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); }
inline shm_named_mutex::~shm_named_mutex()
{}
inline shm_named_mutex::shm_named_mutex(create_only_t, const char *name, const permissions &perm)
: m_shmem (create_only
,name
,sizeof(interprocess_mutex) +
open_create_impl_t::ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoCreate)
,perm)
{}
inline shm_named_mutex::shm_named_mutex(open_or_create_t, const char *name, const permissions &perm)
: m_shmem (open_or_create
,name
,sizeof(interprocess_mutex) +
open_create_impl_t::ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoOpenOrCreate)
,perm)
{}
inline shm_named_mutex::shm_named_mutex(open_only_t, const char *name)
: m_shmem (open_only
,name
,read_write
,0
,construct_func_t(ipcdetail::DoOpen))
{}
inline void shm_named_mutex::lock()
{ this->internal_mutex().lock(); }
inline void shm_named_mutex::unlock()
{ this->internal_mutex().unlock(); }
inline bool shm_named_mutex::try_lock()
{ return this->internal_mutex().try_lock(); }
inline bool shm_named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return this->internal_mutex().timed_lock(abs_time); }
inline bool shm_named_mutex::remove(const char *name)
{ return shared_memory_object::remove(name); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_SHM_NAMED_MUTEX_HPP
+87
View File
@@ -0,0 +1,87 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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_SPIN_MUTEX_HPP
#define BOOST_INTERPROCESS_DETAIL_SPIN_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# 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/assert.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/cstdint.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/sync/detail/common_algorithms.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class spin_mutex
{
spin_mutex(const spin_mutex &);
spin_mutex &operator=(const spin_mutex &);
public:
spin_mutex();
~spin_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
void take_ownership(){};
private:
volatile boost::uint32_t m_s;
};
inline spin_mutex::spin_mutex()
: m_s(0)
{
//Note that this class is initialized to zero.
//So zeroed memory can be interpreted as an
//initialized mutex
}
inline spin_mutex::~spin_mutex()
{
//Trivial destructor
}
inline void spin_mutex::lock(void)
{ return ipcdetail::try_based_lock(*this); }
inline bool spin_mutex::try_lock(void)
{
boost::uint32_t prev_s = ipcdetail::atomic_cas32(const_cast<boost::uint32_t*>(&m_s), 1, 0);
return m_s == 1 && prev_s == 0;
}
inline bool spin_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return ipcdetail::try_based_timed_lock(*this, abs_time); }
inline void spin_mutex::unlock(void)
{ ipcdetail::atomic_cas32(const_cast<boost::uint32_t*>(&m_s), 0, 1); }
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_SPIN_MUTEX_HPP
+185
View File
@@ -0,0 +1,185 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Peter Dimov 2008.
// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//Parts of this file come from boost/smart_ptr/detail/yield_k.hpp
//Many thanks to Peter Dimov.
#ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED
#define BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
//#define BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
#ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
#include <iostream>
#endif
// BOOST_INTERPROCESS_SMT_PAUSE
#if defined(_MSC_VER) && ( defined(_M_IX86) || defined(_M_X64) )
extern "C" void _mm_pause();
#pragma intrinsic( _mm_pause )
#define BOOST_INTERPROCESS_SMT_PAUSE _mm_pause();
#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) && !defined(_CRAYC)
#define BOOST_INTERPROCESS_SMT_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" );
#endif
namespace boost{
namespace interprocess{
namespace ipcdetail {
template<int Dummy = 0>
class num_core_holder
{
public:
static unsigned int get()
{
if(!num_cores){
return ipcdetail::get_num_cores();
}
else{
return num_cores;
}
}
private:
static unsigned int num_cores;
};
template<int Dummy>
unsigned int num_core_holder<Dummy>::num_cores = ipcdetail::get_num_cores();
} //namespace ipcdetail {
class spin_wait
{
public:
static const unsigned int nop_pause_limit = 32u;
spin_wait()
: m_count_start(), m_ul_yield_only_counts(), m_k()
{}
#ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
~spin_wait()
{
if(m_k){
std::cout << "final m_k: " << m_k
<< " system tick(us): " << ipcdetail::get_system_tick_us() << std::endl;
}
}
#endif
unsigned int count() const
{ return m_k; }
void yield()
{
//Lazy initialization of limits
if( !m_k){
this->init_limits();
}
//Nop tries
if( m_k < (nop_pause_limit >> 2) ){
}
//Pause tries if the processor supports it
#if defined(BOOST_INTERPROCESS_SMT_PAUSE)
else if( m_k < nop_pause_limit ){
BOOST_INTERPROCESS_SMT_PAUSE
}
#endif
//Yield/Sleep strategy
else{
//Lazy initialization of tick information
if(m_k == nop_pause_limit){
this->init_tick_info();
}
else if( this->yield_or_sleep() ){
ipcdetail::thread_yield();
}
else{
ipcdetail::thread_sleep_tick();
}
}
++m_k;
}
void reset()
{
m_k = 0u;
}
private:
void init_limits()
{
unsigned int num_cores = ipcdetail::num_core_holder<0>::get();
m_k = num_cores > 1u ? 0u : nop_pause_limit;
}
void init_tick_info()
{
m_ul_yield_only_counts = ipcdetail::get_system_tick_in_highres_counts();
m_count_start = ipcdetail::get_current_system_highres_count();
}
//Returns true if yield must be called, false is sleep must be called
bool yield_or_sleep()
{
if(!m_ul_yield_only_counts){ //If yield-only limit was reached then yield one in every two tries
return (m_k & 1u) != 0;
}
else{ //Try to see if we've reched yield-only time limit
const ipcdetail::OS_highres_count_t now = ipcdetail::get_current_system_highres_count();
const ipcdetail::OS_highres_count_t elapsed = ipcdetail::system_highres_count_subtract(now, m_count_start);
if(!ipcdetail::system_highres_count_less_ul(elapsed, m_ul_yield_only_counts)){
#ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
std::cout << "elapsed!\n"
<< " m_ul_yield_only_counts: " << m_ul_yield_only_counts
<< " system tick(us): " << ipcdetail::get_system_tick_us() << '\n'
<< " m_k: " << m_k << " elapsed counts: ";
ipcdetail::ostream_highres_count(std::cout, elapsed) << std::endl;
#endif
//Yield-only time reached, now it's time to sleep
m_ul_yield_only_counts = 0ul;
return false;
}
}
return true; //Otherwise yield
}
ipcdetail::OS_highres_count_t m_count_start;
unsigned long m_ul_yield_only_counts;
unsigned int m_k;
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED
+118
View File
@@ -0,0 +1,118 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# 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/windows_intermodule_singleton.hpp>
#include <boost/interprocess/sync/windows/sync_utils.hpp>
#include <boost/interprocess/sync/windows/winapi_mutex_wrapper.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_(this)
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
//Create mutex with the initial count
bool open_or_created;
(void)handles.obtain_mutex(this->id_, &open_or_created);
//The mutex must be created, never opened
BOOST_ASSERT(open_or_created);
BOOST_ASSERT(open_or_created && winapi::get_last_error() != winapi::error_already_exists);
(void)open_or_created;
}
inline windows_mutex::~windows_mutex()
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
handles.destroy_handle(this->id_);
}
inline void windows_mutex::lock(void)
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
//This can throw
winapi_mutex_functions mut(handles.obtain_mutex(this->id_));
mut.lock();
}
inline bool windows_mutex::try_lock(void)
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
//This can throw
winapi_mutex_functions mut(handles.obtain_mutex(this->id_));
return mut.try_lock();
}
inline bool windows_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
//This can throw
winapi_mutex_functions mut(handles.obtain_mutex(this->id_));
return mut.timed_lock(abs_time);
}
inline void windows_mutex::unlock(void)
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
//This can throw
winapi_mutex_functions mut(handles.obtain_mutex(this->id_));
return mut.unlock();
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP
@@ -0,0 +1,179 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2012. 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_WINDOWS_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_WINDOWS_NAMED_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/windows/sync_utils.hpp>
#include <boost/interprocess/sync/windows/named_sync.hpp>
#include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <limits>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class windows_named_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
windows_named_mutex();
windows_named_mutex(const windows_named_mutex &);
windows_named_mutex &operator=(const windows_named_mutex &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
windows_named_mutex(create_only_t, const char *name, const permissions &perm = permissions());
windows_named_mutex(open_or_create_t, const char *name, const permissions &perm = permissions());
windows_named_mutex(open_only_t, const char *name);
~windows_named_mutex();
void unlock();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
static bool remove(const char *name);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
friend class interprocess_tester;
void dont_close_on_destruction();
winapi_mutex_wrapper m_mtx_wrapper;
windows_named_sync m_named_sync;
class named_mut_callbacks : public windows_named_sync_interface
{
public:
named_mut_callbacks(winapi_mutex_wrapper &mtx_wrapper)
: m_mtx_wrapper(mtx_wrapper)
{}
virtual std::size_t get_data_size() const
{ return 0u; }
virtual const void *buffer_with_init_data_to_file()
{ return 0; }
virtual const void *buffer_with_final_data_to_file()
{ return 0; }
virtual void *buffer_to_store_init_data_from_file()
{ return 0; }
virtual bool open(create_enum_t, const char *id_name)
{
std::string aux_str = "Global\\bipc.mut.";
aux_str += id_name;
//
permissions mut_perm;
mut_perm.set_unrestricted();
return m_mtx_wrapper.open_or_create(aux_str.c_str(), mut_perm);
}
virtual void close()
{
m_mtx_wrapper.close();
}
virtual ~named_mut_callbacks()
{}
private:
winapi_mutex_wrapper& m_mtx_wrapper;
};
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
inline windows_named_mutex::~windows_named_mutex()
{
named_mut_callbacks callbacks(m_mtx_wrapper);
m_named_sync.close(callbacks);
}
inline void windows_named_mutex::dont_close_on_destruction()
{}
inline windows_named_mutex::windows_named_mutex
(create_only_t, const char *name, const permissions &perm)
: m_mtx_wrapper()
{
named_mut_callbacks callbacks(m_mtx_wrapper);
m_named_sync.open_or_create(DoCreate, name, perm, callbacks);
}
inline windows_named_mutex::windows_named_mutex
(open_or_create_t, const char *name, const permissions &perm)
: m_mtx_wrapper()
{
named_mut_callbacks callbacks(m_mtx_wrapper);
m_named_sync.open_or_create(DoOpenOrCreate, name, perm, callbacks);
}
inline windows_named_mutex::windows_named_mutex(open_only_t, const char *name)
: m_mtx_wrapper()
{
named_mut_callbacks callbacks(m_mtx_wrapper);
m_named_sync.open_or_create(DoOpen, name, permissions(), callbacks);
}
inline void windows_named_mutex::unlock()
{
m_mtx_wrapper.unlock();
}
inline void windows_named_mutex::lock()
{
m_mtx_wrapper.lock();
}
inline bool windows_named_mutex::try_lock()
{
return m_mtx_wrapper.try_lock();
}
inline bool windows_named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
return m_mtx_wrapper.timed_lock(abs_time);
}
inline bool windows_named_mutex::remove(const char *name)
{
return windows_named_sync::remove(name);
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_WINDOWS_NAMED_MUTEX_HPP
@@ -0,0 +1,219 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2012. 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_WINDOWS_NAMED_SYNC_HPP
#define BOOST_INTERPROCESS_WINDOWS_NAMED_SYNC_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/shared_dir_helpers.hpp>
#include <boost/interprocess/sync/windows/sync_utils.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <string>
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class windows_named_sync_interface
{
public:
virtual std::size_t get_data_size() const = 0;
virtual const void *buffer_with_final_data_to_file() = 0;
virtual const void *buffer_with_init_data_to_file() = 0;
virtual void *buffer_to_store_init_data_from_file() = 0;
virtual bool open(create_enum_t creation_type, const char *id_name) = 0;
virtual void close() = 0;
virtual ~windows_named_sync_interface() = 0;
};
inline windows_named_sync_interface::~windows_named_sync_interface()
{}
class windows_named_sync
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
windows_named_sync(const windows_named_sync &);
windows_named_sync &operator=(const windows_named_sync &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
windows_named_sync();
void open_or_create(create_enum_t creation_type, const char *name, const permissions &perm, windows_named_sync_interface &sync_interface);
void close(windows_named_sync_interface &sync_interface);
static bool remove(const char *name);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
void *m_file_hnd;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
inline windows_named_sync::windows_named_sync()
: m_file_hnd(winapi::invalid_handle_value)
{}
inline void windows_named_sync::close(windows_named_sync_interface &sync_interface)
{
const std::size_t buflen = sync_interface.get_data_size();
const std::size_t sizeof_file_info = sizeof(sync_id::internal_type) + buflen;
winapi::interprocess_overlapped overlapped;
if(winapi::lock_file_ex
(m_file_hnd, winapi::lockfile_exclusive_lock, 0, sizeof_file_info, 0, &overlapped)){
if(winapi::set_file_pointer_ex(m_file_hnd, sizeof(sync_id::internal_type), 0, winapi::file_begin)){
const void *buf = sync_interface.buffer_with_final_data_to_file();
unsigned long written_or_read = 0;
if(winapi::write_file(m_file_hnd, buf, buflen, &written_or_read, 0)){
//...
}
}
}
sync_interface.close();
if(m_file_hnd != winapi::invalid_handle_value){
winapi::close_handle(m_file_hnd);
m_file_hnd = winapi::invalid_handle_value;
}
}
inline void windows_named_sync::open_or_create
( create_enum_t creation_type
, const char *name
, const permissions &perm
, windows_named_sync_interface &sync_interface)
{
std::string aux_str(name);
m_file_hnd = winapi::invalid_handle_value;
//Use a file to emulate POSIX lifetime semantics. After this logic
//we'll obtain the ID of the native handle to open in aux_str
{
create_shared_dir_cleaning_old_and_get_filepath(name, aux_str);
//Create a file with required permissions.
m_file_hnd = winapi::create_file
( aux_str.c_str()
, winapi::generic_read | winapi::generic_write
, creation_type == DoOpen ? winapi::open_existing :
(creation_type == DoCreate ? winapi::create_new : winapi::open_always)
, 0
, (winapi::interprocess_security_attributes*)perm.get_permissions());
//Obtain OS error in case something has failed
error_info err;
bool success = false;
if(m_file_hnd != winapi::invalid_handle_value){
//Now lock the file
const std::size_t buflen = sync_interface.get_data_size();
typedef __int64 unique_id_type;
const std::size_t sizeof_file_info = sizeof(unique_id_type) + buflen;
winapi::interprocess_overlapped overlapped;
if(winapi::lock_file_ex
(m_file_hnd, winapi::lockfile_exclusive_lock, 0, sizeof_file_info, 0, &overlapped)){
__int64 filesize = 0;
//Obtain the unique id to open the native semaphore.
//If file size was created
if(winapi::get_file_size(m_file_hnd, filesize)){
unsigned long written_or_read = 0;
unique_id_type unique_id_val;
if(static_cast<std::size_t>(filesize) != sizeof_file_info){
winapi::set_end_of_file(m_file_hnd);
winapi::query_performance_counter(&unique_id_val);
const void *buf = sync_interface.buffer_with_init_data_to_file();
//Write unique ID in file. This ID will be used to calculate the semaphore name
if(winapi::write_file(m_file_hnd, &unique_id_val, sizeof(unique_id_val), &written_or_read, 0) &&
written_or_read == sizeof(unique_id_val) &&
winapi::write_file(m_file_hnd, buf, buflen, &written_or_read, 0) &&
written_or_read == buflen ){
success = true;
}
winapi::get_file_size(m_file_hnd, filesize);
BOOST_ASSERT(std::size_t(filesize) == sizeof_file_info);
}
else{
void *buf = sync_interface.buffer_to_store_init_data_from_file();
if(winapi::read_file(m_file_hnd, &unique_id_val, sizeof(unique_id_val), &written_or_read, 0) &&
written_or_read == sizeof(unique_id_val) &&
winapi::read_file(m_file_hnd, buf, buflen, &written_or_read, 0) &&
written_or_read == buflen ){
success = true;
}
}
if(success){
//Now create a global semaphore name based on the unique id
char unique_id_name[sizeof(unique_id_val)*2+1];
std::size_t name_suffix_length = sizeof(unique_id_name);
bytes_to_str(&unique_id_val, sizeof(unique_id_val), &unique_id_name[0], name_suffix_length);
success = sync_interface.open(creation_type, unique_id_name);
}
}
//Obtain OS error in case something has failed
err = system_error_code();
//If this fails we have no possible rollback so don't check the return
if(!winapi::unlock_file_ex(m_file_hnd, 0, sizeof_file_info, 0, &overlapped)){
err = system_error_code();
}
}
else{
//Obtain OS error in case something has failed
err = system_error_code();
}
}
else{
err = system_error_code();
}
if(!success){
if(m_file_hnd != winapi::invalid_handle_value){
winapi::close_handle(m_file_hnd);
m_file_hnd = winapi::invalid_handle_value;
}
//Throw as something went wrong
throw interprocess_exception(err);
}
}
}
inline bool windows_named_sync::remove(const char *name)
{
try{
//Make sure a temporary path is created for shared memory
std::string semfile;
ipcdetail::shared_filepath(name, semfile);
return winapi::unlink_file(semfile.c_str());
}
catch(...){
return false;
}
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_WINDOWS_NAMED_SYNC_HPP
@@ -0,0 +1,240 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# 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/interprocess/sync/windows/winapi_semaphore_wrapper.hpp>
#include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
//Shield against external warnings
#include <boost/interprocess/detail/config_external_begin.hpp>
#include <boost/unordered/unordered_map.hpp>
#include <boost/interprocess/detail/config_external_end.hpp>
#include <boost/container/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){
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;
}
class sync_id
{
public:
typedef __int64 internal_type;
sync_id(const void *map_addr)
: map_addr_(map_addr)
{ winapi::query_performance_counter(&rand_); }
explicit sync_id(internal_type val, const void *map_addr)
: map_addr_(map_addr)
{ rand_ = val; }
const internal_type &internal_pod() const
{ return rand_; }
internal_type &internal_pod()
{ return rand_; }
const void *map_address() const
{ return map_addr_; }
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_ && l.map_addr_ == r.map_addr_; }
private:
internal_type rand_;
const void * const map_addr_;
};
class sync_handles
{
public:
enum type { MUTEX, SEMAPHORE };
private:
struct address_less
{
bool operator()(sync_id const * const l, sync_id const * const r) const
{ return l->map_address() < r->map_address(); }
};
typedef boost::unordered_map<sync_id, void*> umap_type;
typedef boost::container::map<const sync_id*, umap_type::iterator, address_less> 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.internal_pod(), sizeof(id.internal_pod()), &name[LengthOfGlobal], len);
}
void throw_if_error(void *hnd_val)
{
if(!hnd_val){
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);
permissions unrestricted_security;
unrestricted_security.set_unrestricted();
winapi_semaphore_wrapper sem_wrapper;
bool created;
sem_wrapper.open_or_create
(name, (long)initial_count, winapi_semaphore_wrapper::MaxCount, unrestricted_security, created);
throw_if_error(sem_wrapper.handle());
return sem_wrapper.release();
}
void* open_or_create_mutex(const sync_id &id)
{
NameBuf name;
fill_name(name, id);
permissions unrestricted_security;
unrestricted_security.set_unrestricted();
winapi_mutex_wrapper mtx_wrapper;
mtx_wrapper.open_or_create(name, unrestricted_security);
throw_if_error(mtx_wrapper.handle());
return mtx_wrapper.release();
}
public:
void *obtain_mutex(const sync_id &id, bool *popen_created = 0)
{
umap_type::value_type v(id, (void*)0);
scoped_lock<spin_mutex> lock(mtx_);
umap_type::iterator it = umap_.insert(v).first;
void *&hnd_val = it->second;
if(!hnd_val){
map_[&it->first] = it;
hnd_val = open_or_create_mutex(id);
if(popen_created) *popen_created = true;
}
else if(popen_created){
*popen_created = false;
}
return hnd_val;
}
void *obtain_semaphore(const sync_id &id, unsigned int initial_count, bool *popen_created = 0)
{
umap_type::value_type v(id, (void*)0);
scoped_lock<spin_mutex> lock(mtx_);
umap_type::iterator it = umap_.insert(v).first;
void *&hnd_val = it->second;
if(!hnd_val){
map_[&it->first] = it;
hnd_val = open_or_create_semaphore(id, initial_count);
if(popen_created) *popen_created = true;
}
else if(popen_created){
*popen_created = false;
}
return hnd_val;
}
void destroy_handle(const sync_id &id)
{
scoped_lock<spin_mutex> lock(mtx_);
umap_type::iterator it = umap_.find(id);
umap_type::iterator itend = umap_.end();
if(it != itend){
winapi::close_handle(it->second);
const map_type::key_type &k = &it->first;
map_.erase(k);
umap_.erase(it);
}
}
void destroy_syncs_in_range(const void *addr, std::size_t size)
{
const sync_id low_id(addr);
const sync_id hig_id(static_cast<const char*>(addr)+size);
scoped_lock<spin_mutex> lock(mtx_);
map_type::iterator itlow(map_.lower_bound(&low_id)),
ithig(map_.lower_bound(&hig_id));
while(itlow != ithig){
void * const hnd = umap_[*itlow->first];
winapi::close_handle(hnd);
umap_.erase(*itlow->first);
itlow = map_.erase(itlow);
}
}
private:
spin_mutex mtx_;
umap_type umap_;
map_type map_;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP
@@ -0,0 +1,134 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2012. 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_WINAPI_MUTEX_WRAPPER_HPP
#define BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/win32_api.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/windows/winapi_wrapper_common.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <limits>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class winapi_mutex_functions
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
winapi_mutex_functions(const winapi_mutex_functions &);
winapi_mutex_functions &operator=(const winapi_mutex_functions &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
winapi_mutex_functions(void *mtx_hnd)
: m_mtx_hnd(mtx_hnd)
{}
void unlock()
{ winapi::release_mutex(m_mtx_hnd); }
void lock()
{ return winapi_wrapper_wait_for_single_object(m_mtx_hnd); }
bool try_lock()
{ return winapi_wrapper_try_wait_for_single_object(m_mtx_hnd); }
bool timed_lock(const boost::posix_time::ptime &abs_time)
{ return winapi_wrapper_timed_wait_for_single_object(m_mtx_hnd, abs_time); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
protected:
void *m_mtx_hnd;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
//Swappable mutex wrapper
class winapi_mutex_wrapper
: public winapi_mutex_functions
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
winapi_mutex_wrapper(const winapi_mutex_wrapper &);
winapi_mutex_wrapper &operator=(const winapi_mutex_wrapper &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//Note that Windows API does not return winapi::invalid_handle_value
//when failing to create/open a mutex, but a nullptr
public:
winapi_mutex_wrapper(void *mtx_hnd = 0)
: winapi_mutex_functions(mtx_hnd)
{}
~winapi_mutex_wrapper()
{ this->close(); }
void *release()
{
void *hnd = m_mtx_hnd;
m_mtx_hnd = 0;
return hnd;
}
void *handle() const
{ return m_mtx_hnd; }
bool open_or_create(const char *name, const permissions &perm)
{
if(m_mtx_hnd == 0){
m_mtx_hnd = winapi::open_or_create_mutex
( name
, false
, (winapi::interprocess_security_attributes*)perm.get_permissions()
);
return m_mtx_hnd != 0;
}
else{
return false;
}
}
void close()
{
if(m_mtx_hnd != 0){
winapi::close_handle(m_mtx_hnd);
m_mtx_hnd = 0;
}
}
void swap(winapi_mutex_wrapper &other)
{ void *tmp = m_mtx_hnd; m_mtx_hnd = other.m_mtx_hnd; other.m_mtx_hnd = tmp; }
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP
@@ -0,0 +1,168 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2012. 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_WINAPI_SEMAPHORE_WRAPPER_HPP
#define BOOST_INTERPROCESS_DETAIL_WINAPI_SEMAPHORE_WRAPPER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/win32_api.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/windows/winapi_wrapper_common.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <limits>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class winapi_semaphore_functions
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
winapi_semaphore_functions(const winapi_semaphore_functions &);
winapi_semaphore_functions &operator=(const winapi_semaphore_functions &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
winapi_semaphore_functions(void *hnd)
: m_sem_hnd(hnd)
{}
void post(long count = 1)
{
long prev_count;
winapi::release_semaphore(m_sem_hnd, count, &prev_count);
}
void wait()
{ return winapi_wrapper_wait_for_single_object(m_sem_hnd); }
bool try_wait()
{ return winapi_wrapper_try_wait_for_single_object(m_sem_hnd); }
bool timed_wait(const boost::posix_time::ptime &abs_time)
{ return winapi_wrapper_timed_wait_for_single_object(m_sem_hnd, abs_time); }
long value() const
{
long l_count, l_limit;
if(!winapi::get_semaphore_info(m_sem_hnd, l_count, l_limit))
return 0;
return l_count;
}
long limit() const
{
long l_count, l_limit;
if(!winapi::get_semaphore_info(m_sem_hnd, l_count, l_limit))
return 0;
return l_limit;
}
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
protected:
void *m_sem_hnd;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
//Swappable semaphore wrapper
class winapi_semaphore_wrapper
: public winapi_semaphore_functions
{
winapi_semaphore_wrapper(const winapi_semaphore_wrapper &);
winapi_semaphore_wrapper &operator=(const winapi_semaphore_wrapper &);
public:
//Long is 32 bits in windows
static const long MaxCount = long(0x7FFFFFFF);
winapi_semaphore_wrapper(void *hnd = winapi::invalid_handle_value)
: winapi_semaphore_functions(hnd)
{}
~winapi_semaphore_wrapper()
{ this->close(); }
void *release()
{
void *hnd = m_sem_hnd;
m_sem_hnd = winapi::invalid_handle_value;
return hnd;
}
void *handle() const
{ return m_sem_hnd; }
bool open_or_create( const char *name
, long sem_count
, long max_count
, const permissions &perm
, bool &created)
{
if(m_sem_hnd == winapi::invalid_handle_value){
m_sem_hnd = winapi::open_or_create_semaphore
( name
, sem_count
, max_count
, (winapi::interprocess_security_attributes*)perm.get_permissions()
);
created = winapi::get_last_error() != winapi::error_already_exists;
return m_sem_hnd != winapi::invalid_handle_value;
}
else{
return false;
}
}
bool open_semaphore(const char *name)
{
if(m_sem_hnd == winapi::invalid_handle_value){
m_sem_hnd = winapi::open_semaphore(name);
return m_sem_hnd != winapi::invalid_handle_value;
}
else{
return false;
}
}
void close()
{
if(m_sem_hnd != winapi::invalid_handle_value){
winapi::close_handle(m_sem_hnd);
m_sem_hnd = winapi::invalid_handle_value;
}
}
void swap(winapi_semaphore_wrapper &other)
{ void *tmp = m_sem_hnd; m_sem_hnd = other.m_sem_hnd; other.m_sem_hnd = tmp; }
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_SEMAPHORE_WRAPPER_HPP
@@ -0,0 +1,97 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2012. 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_WINAPI_WRAPPER_COMMON_HPP
#define BOOST_INTERPROCESS_DETAIL_WINAPI_WRAPPER_COMMON_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# 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/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <limits>
namespace boost {
namespace interprocess {
namespace ipcdetail {
inline void winapi_wrapper_wait_for_single_object(void *handle)
{
unsigned long ret = winapi::wait_for_single_object(handle, winapi::infinite_time);
if(ret != winapi::wait_object_0){
if(ret != winapi::wait_abandoned){
error_info err = system_error_code();
throw interprocess_exception(err);
}
else{ //Special case for orphaned mutexes
winapi::release_mutex(handle);
throw interprocess_exception(owner_dead_error);
}
}
}
inline bool winapi_wrapper_try_wait_for_single_object(void *handle)
{
unsigned long ret = winapi::wait_for_single_object(handle, 0);
if(ret == winapi::wait_object_0){
return true;
}
else if(ret == winapi::wait_timeout){
return false;
}
else{
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline bool winapi_wrapper_timed_wait_for_single_object(void *handle, const boost::posix_time::ptime &abs_time)
{
//Windows does not support infinity abs_time so check it
if(abs_time == boost::posix_time::pos_infin){
winapi_wrapper_wait_for_single_object(handle);
return true;
}
const boost::posix_time::ptime cur_time = microsec_clock::universal_time();
//Windows uses relative wait times so check for negative waits
//and implement as 0 wait to allow try-semantics as POSIX mandates.
unsigned long ret = winapi::wait_for_single_object
( handle
, (abs_time <= cur_time) ? 0u
: (abs_time - cur_time).total_milliseconds()
);
if(ret == winapi::wait_object_0){
return true;
}
else if(ret == winapi::wait_timeout){
return false;
}
else{
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP