Added boost header

This commit is contained in:
Christophe Riccio
2012-01-08 01:26:07 +00:00
parent 9c3faaca40
commit c7d752cdf8
8946 changed files with 1732316 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
#include<boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
namespace boost {
namespace interprocess {
inline barrier::barrier(unsigned int count)
: m_threshold(count), m_count(count), m_generation(0)
{
if (count == 0)
throw std::invalid_argument("count cannot be zero.");
}
inline barrier::~barrier(){}
inline bool barrier::wait()
{
scoped_lock<interprocess_mutex> lock(m_mutex);
unsigned int gen = m_generation;
if (--m_count == 0){
m_generation++;
m_count = m_threshold;
m_cond.notify_all();
return true;
}
while (gen == m_generation){
m_cond.wait(lock);
}
return false;
}
} //namespace interprocess {
} //namespace boost {

View File

@@ -0,0 +1,200 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/detail/move.hpp>
namespace boost {
namespace interprocess {
inline interprocess_condition::interprocess_condition()
{
//Note that this class is initialized to zero.
//So zeroed memory can be interpreted as an initialized
//condition variable
m_command = SLEEP;
m_num_waiters = 0;
}
inline interprocess_condition::~interprocess_condition()
{
//Trivial destructor
}
inline void interprocess_condition::notify_one()
{
this->notify(NOTIFY_ONE);
}
inline void interprocess_condition::notify_all()
{
this->notify(NOTIFY_ALL);
}
inline void interprocess_condition::notify(boost::uint32_t command)
{
//This interprocess_mutex guarantees that no other thread can enter to the
//do_timed_wait method logic, so that thread count will be
//constant until the function writes a NOTIFY_ALL command.
//It also guarantees that no other notification can be signaled
//on this interprocess_condition before this one ends
m_enter_mut.lock();
//Return if there are no waiters
if(!ipcdetail::atomic_read32(&m_num_waiters)) {
m_enter_mut.unlock();
return;
}
//Notify that all threads should execute wait logic
while(SLEEP != ipcdetail::atomic_cas32(const_cast<boost::uint32_t*>(&m_command), command, SLEEP)){
ipcdetail::thread_yield();
}
/*
//Wait until the threads are woken
while(SLEEP != ipcdetail::atomic_cas32(const_cast<boost::uint32_t*>(&m_command), 0)){
ipcdetail::thread_yield();
}
*/
//The enter interprocess_mutex will rest locked until the last waiting thread unlocks it
}
inline void interprocess_condition::do_wait(interprocess_mutex &mut)
{
this->do_timed_wait(false, boost::posix_time::ptime(), mut);
}
inline bool interprocess_condition::do_timed_wait
(const boost::posix_time::ptime &abs_time, interprocess_mutex &mut)
{
return this->do_timed_wait(true, abs_time, mut);
}
inline bool interprocess_condition::do_timed_wait(bool tout_enabled,
const boost::posix_time::ptime &abs_time,
interprocess_mutex &mut)
{
boost::posix_time::ptime now = microsec_clock::universal_time();
if(tout_enabled){
if(now >= abs_time) return false;
}
typedef boost::interprocess::scoped_lock<interprocess_mutex> InternalLock;
//The enter interprocess_mutex guarantees that while executing a notification,
//no other thread can execute the do_timed_wait method.
{
//---------------------------------------------------------------
InternalLock lock;
if(tout_enabled){
InternalLock dummy(m_enter_mut, abs_time);
lock = boost::interprocess::move(dummy);
}
else{
InternalLock dummy(m_enter_mut);
lock = boost::interprocess::move(dummy);
}
if(!lock)
return false;
//---------------------------------------------------------------
//We increment the waiting thread count protected so that it will be
//always constant when another thread enters the notification logic.
//The increment marks this thread as "waiting on interprocess_condition"
ipcdetail::atomic_inc32(const_cast<boost::uint32_t*>(&m_num_waiters));
//We unlock the external interprocess_mutex atomically with the increment
mut.unlock();
}
//By default, we suppose that no timeout has happened
bool timed_out = false, unlock_enter_mut= false;
//Loop until a notification indicates that the thread should
//exit or timeout occurs
while(1){
//The thread sleeps/spins until a interprocess_condition commands a notification
//Notification occurred, we will lock the checking interprocess_mutex so that
while(ipcdetail::atomic_read32(&m_command) == SLEEP){
ipcdetail::thread_yield();
//Check for timeout
if(tout_enabled){
now = microsec_clock::universal_time();
if(now >= abs_time){
//If we can lock the interprocess_mutex it means that no notification
//is being executed in this interprocess_condition variable
timed_out = m_enter_mut.try_lock();
//If locking fails, indicates that another thread is executing
//notification, so we play the notification game
if(!timed_out){
//There is an ongoing notification, we will try again later
continue;
}
//No notification in execution, since enter interprocess_mutex is locked.
//We will execute time-out logic, so we will decrement count,
//release the enter interprocess_mutex and return false.
break;
}
}
}
//If a timeout occurred, the interprocess_mutex will not execute checking logic
if(tout_enabled && timed_out){
//Decrement wait count
ipcdetail::atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
unlock_enter_mut = true;
break;
}
else{
boost::uint32_t result = ipcdetail::atomic_cas32
(const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ONE);
if(result == SLEEP){
//Other thread has been notified and since it was a NOTIFY one
//command, this thread must sleep again
continue;
}
else if(result == NOTIFY_ONE){
//If it was a NOTIFY_ONE command, only this thread should
//exit. This thread has atomically marked command as sleep before
//so no other thread will exit.
//Decrement wait count.
unlock_enter_mut = true;
ipcdetail::atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
break;
}
else{
//If it is a NOTIFY_ALL command, all threads should return
//from do_timed_wait function. Decrement wait count.
unlock_enter_mut = 1 == ipcdetail::atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
//Check if this is the last thread of notify_all waiters
//Only the last thread will release the interprocess_mutex
if(unlock_enter_mut){
ipcdetail::atomic_cas32(const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ALL);
}
break;
}
}
}
//Unlock the enter interprocess_mutex if it is a single notification, if this is
//the last notified thread in a notify_all or a timeout has occurred
if(unlock_enter_mut){
m_enter_mut.unlock();
}
//Lock external again before returning from the method
mut.lock();
return !timed_out;
}
} //namespace interprocess
} // namespace boost

View File

@@ -0,0 +1,75 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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.
//
//////////////////////////////////////////////////////////////////////////////
#include<boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
namespace boost {
namespace interprocess {
inline interprocess_semaphore::~interprocess_semaphore()
{}
inline interprocess_semaphore::interprocess_semaphore(unsigned int initialCount)
{ ipcdetail::atomic_write32(&this->m_count, boost::uint32_t(initialCount)); }
inline void interprocess_semaphore::post()
{
ipcdetail::atomic_inc32(&m_count);
}
inline void interprocess_semaphore::wait()
{
while(!ipcdetail::atomic_add_unless32(&m_count, boost::uint32_t(-1), boost::uint32_t(0))){
while(ipcdetail::atomic_read32(&m_count) == 0){
ipcdetail::thread_yield();
}
}
}
inline bool interprocess_semaphore::try_wait()
{
return ipcdetail::atomic_add_unless32(&m_count, boost::uint32_t(-1), boost::uint32_t(0));
}
inline bool interprocess_semaphore::timed_wait(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->wait();
return true;
}
//Obtain current count and target time
boost::posix_time::ptime now(microsec_clock::universal_time());
if(now >= abs_time)
return false;
do{
if(this->try_wait()){
break;
}
now = microsec_clock::universal_time();
if(now >= abs_time){
return this->try_wait();
}
// relinquish current time slice
ipcdetail::thread_yield();
}while (true);
return true;
}
/*
inline int interprocess_semaphore::get_count() const
{
return (int)ipcdetail::atomic_read32(&m_count);
}*/
} //namespace interprocess {
} //namespace boost {

View File

@@ -0,0 +1,116 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_EMULATION_MUTEX_HPP
#define BOOST_INTERPROCESS_DETAIL_EMULATION_MUTEX_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/cstdint.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class emulation_mutex
{
emulation_mutex(const emulation_mutex &);
emulation_mutex &operator=(const emulation_mutex &);
public:
emulation_mutex();
~emulation_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 emulation_mutex::emulation_mutex()
: m_s(0)
{
//Note that this class is initialized to zero.
//So zeroed memory can be interpreted as an
//initialized mutex
}
inline emulation_mutex::~emulation_mutex()
{
//Trivial destructor
}
inline void emulation_mutex::lock(void)
{
do{
boost::uint32_t prev_s = ipcdetail::atomic_cas32(const_cast<boost::uint32_t*>(&m_s), 1, 0);
if (m_s == 1 && prev_s == 0){
break;
}
// relinquish current timeslice
ipcdetail::thread_yield();
}while (true);
}
inline bool emulation_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 emulation_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
//Obtain current count and target time
boost::posix_time::ptime now = microsec_clock::universal_time();
if(now >= abs_time) return false;
do{
if(this->try_lock()){
break;
}
now = microsec_clock::universal_time();
if(now >= abs_time){
return false;
}
// relinquish current time slice
ipcdetail::thread_yield();
}while (true);
return true;
}
inline void emulation_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_EMULATION_MUTEX_HPP

View File

@@ -0,0 +1,68 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2009. 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
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/mpl.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(ipcdetail::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)T; }
template<class ArgType>
void construct(void *address, typename enable_if_c<!is_same<ArgType, no_arg_t>::value>::type * = 0) const
{ new(address)T(m_arg); }
bool operator()(void *address, std::size_t, bool created) const
{
switch(m_creation_type){
case ipcdetail::DoOpen:
return true;
break;
case ipcdetail::DoCreate:
case ipcdetail::DoOpenOrCreate:
if(created){
construct<Arg>(address);
}
return true;
break;
default:
return false;
break;
}
}
private:
ipcdetail::create_enum_t m_creation_type;
Arg m_arg;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#endif //BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP

View File

@@ -0,0 +1,167 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_EMULATION_RECURSIVE_MUTEX_HPP
#define BOOST_INTERPROCESS_DETAIL_EMULATION_RECURSIVE_MUTEX_HPP
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/cstdint.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/sync/emulation/mutex.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class emulation_recursive_mutex
{
emulation_recursive_mutex(const emulation_recursive_mutex &);
emulation_recursive_mutex &operator=(const emulation_recursive_mutex &);
public:
emulation_recursive_mutex();
~emulation_recursive_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
void take_ownership();
private:
emulation_mutex m_mutex;
unsigned int m_nLockCount;
volatile ipcdetail::OS_systemwide_thread_id_t m_nOwner;
volatile boost::uint32_t m_s;
};
inline emulation_recursive_mutex::emulation_recursive_mutex()
: m_nLockCount(0), m_nOwner(ipcdetail::get_invalid_systemwide_thread_id()){}
inline emulation_recursive_mutex::~emulation_recursive_mutex(){}
inline void emulation_recursive_mutex::lock()
{
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
handle_t old_id;
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)){
if((unsigned int)(m_nLockCount+1) == 0){
//Overflow, throw an exception
throw interprocess_exception("boost::interprocess::emulation_recursive_mutex recursive lock overflow");
}
++m_nLockCount;
}
else{
m_mutex.lock();
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
m_nLockCount = 1;
}
}
inline bool emulation_recursive_mutex::try_lock()
{
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
handle_t old_id;
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it
if((unsigned int)(m_nLockCount+1) == 0){
//Overflow, throw an exception
throw interprocess_exception("boost::interprocess::emulation_recursive_mutex recursive lock overflow");
}
++m_nLockCount;
return true;
}
if(m_mutex.try_lock()){
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
m_nLockCount = 1;
return true;
}
return false;
}
inline bool emulation_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
handle_t old_id;
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it
if((unsigned int)(m_nLockCount+1) == 0){
//Overflow, throw an exception
throw interprocess_exception("boost::interprocess::emulation_recursive_mutex recursive lock overflow");
}
++m_nLockCount;
return true;
}
if(m_mutex.timed_lock(abs_time)){
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
m_nLockCount = 1;
return true;
}
return false;
}
inline void emulation_recursive_mutex::unlock()
{
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
handle_t old_id;
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
(void)old_id;
(void)thr_id;
BOOST_ASSERT(ipcdetail::equal_systemwide_thread_id(thr_id, old_id));
--m_nLockCount;
if(!m_nLockCount){
const handle_t new_id(ipcdetail::get_invalid_systemwide_thread_id());
ipcdetail::systemwide_thread_id_copy(new_id, m_nOwner);
m_mutex.unlock();
}
}
inline void emulation_recursive_mutex::take_ownership()
{
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
this->m_nLockCount = 1;
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
ipcdetail::systemwide_thread_id_copy
(thr_id, m_nOwner);
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#endif //BOOST_INTERPROCESS_DETAIL_EMULATION_RECURSIVE_MUTEX_HPP

View File

@@ -0,0 +1,305 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_FILE_LOCK_HPP
#define BOOST_INTERPROCESS_FILE_LOCK_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/detail/move.hpp>
//!\file
//!Describes a class that wraps file locking capabilities.
namespace boost {
namespace interprocess {
//!A file lock, is a mutual exclusion utility similar to a mutex using a
//!file. A file lock has sharable and exclusive locking capabilities and
//!can be used with scoped_lock and sharable_lock classes.
//!A file lock can't guarantee synchronization between threads of the same
//!process so just use file locks to synchronize threads from different processes.
class file_lock
{
/// @cond
//Non-copyable
BOOST_MOVABLE_BUT_NOT_COPYABLE(file_lock)
/// @endcond
public:
//!Constructs an empty file mapping.
//!Does not throw
file_lock()
: m_file_hnd(file_handle_t(ipcdetail::invalid_file()))
{}
//!Opens a file lock. Throws interprocess_exception if the file does not
//!exist or there are no operating system resources.
file_lock(const char *name);
//!Moves the ownership of "moved"'s file mapping object to *this.
//!After the call, "moved" does not represent any file mapping object.
//!Does not throw
file_lock(BOOST_RV_REF(file_lock) moved)
: m_file_hnd(file_handle_t(ipcdetail::invalid_file()))
{ this->swap(moved); }
//!Moves the ownership of "moved"'s file mapping to *this.
//!After the call, "moved" does not represent any file mapping.
//!Does not throw
file_lock &operator=(BOOST_RV_REF(file_lock) moved)
{
file_lock tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Closes a file lock. Does not throw.
~file_lock();
//!Swaps two file_locks.
//!Does not throw.
void swap(file_lock &other)
{
file_handle_t tmp = m_file_hnd;
m_file_hnd = other.m_file_hnd;
other.m_file_hnd = tmp;
}
//Exclusive locking
//!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
//! and if another thread has exclusive, or sharable ownership of
//! the mutex, it waits until it can obtain the ownership.
//!Throws: interprocess_exception on error.
void lock();
//!Effects: The calling thread tries to acquire exclusive ownership of the mutex
//! without waiting. If no other thread has exclusive, or sharable
//! ownership of the mutex this succeeds.
//!Returns: If it can acquire exclusive ownership immediately returns true.
//! If it has to wait, returns false.
//!Throws: interprocess_exception on error.
bool try_lock();
//!Effects: The calling thread tries to acquire exclusive ownership of the mutex
//! waiting if necessary until no other thread has has exclusive, or sharable
//! ownership of the mutex or abs_time is reached.
//!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
//!Throws: interprocess_exception on error.
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Precondition: The thread must have exclusive ownership of the mutex.
//!Effects: The calling thread releases the exclusive ownership of the mutex.
//!Throws: An exception derived from interprocess_exception on error.
void unlock();
//Sharable locking
//!Effects: The calling thread tries to obtain sharable ownership of the mutex,
//! and if another thread has exclusive ownership of the mutex, waits until
//! it can obtain the ownership.
//!Throws: interprocess_exception on error.
void lock_sharable();
//!Effects: The calling thread tries to acquire sharable ownership of the mutex
//! without waiting. If no other thread has has exclusive ownership of the
//! mutex this succeeds.
//!Returns: If it can acquire sharable ownership immediately returns true. If it
//! has to wait, returns false.
//!Throws: interprocess_exception on error.
bool try_lock_sharable();
//!Effects: The calling thread tries to acquire sharable ownership of the mutex
//! waiting if necessary until no other thread has has exclusive ownership of
//! the mutex or abs_time is reached.
//!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
//!Throws: interprocess_exception on error.
bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
//!Precondition: The thread must have sharable ownership of the mutex.
//!Effects: The calling thread releases the sharable ownership of the mutex.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_sharable();
/// @cond
private:
file_handle_t m_file_hnd;
bool timed_acquire_file_lock
(file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time)
{
//Obtain current count and target time
boost::posix_time::ptime now = microsec_clock::universal_time();
using namespace boost::detail;
if(now >= abs_time) return false;
do{
if(!ipcdetail::try_acquire_file_lock(hnd, acquired))
return false;
if(acquired)
return true;
else{
now = microsec_clock::universal_time();
if(now >= abs_time){
acquired = false;
return true;
}
// relinquish current time slice
ipcdetail::thread_yield();
}
}while (true);
}
bool timed_acquire_file_lock_sharable
(file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time)
{
//Obtain current count and target time
boost::posix_time::ptime now = microsec_clock::universal_time();
using namespace boost::detail;
if(now >= abs_time) return false;
do{
if(!ipcdetail::try_acquire_file_lock_sharable(hnd, acquired))
return false;
if(acquired)
return true;
else{
now = microsec_clock::universal_time();
if(now >= abs_time){
acquired = false;
return true;
}
// relinquish current time slice
ipcdetail::thread_yield();
}
}while (true);
}
/// @endcond
};
inline file_lock::file_lock(const char *name)
{
m_file_hnd = ipcdetail::open_existing_file(name, read_write);
if(m_file_hnd == ipcdetail::invalid_file()){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline file_lock::~file_lock()
{
if(m_file_hnd != ipcdetail::invalid_file()){
ipcdetail::close_file(m_file_hnd);
m_file_hnd = ipcdetail::invalid_file();
}
}
inline void file_lock::lock()
{
if(!ipcdetail::acquire_file_lock(m_file_hnd)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline bool file_lock::try_lock()
{
bool result;
if(!ipcdetail::try_acquire_file_lock(m_file_hnd, result)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
return result;
}
inline bool file_lock::timed_lock(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
bool result;
if(!this->timed_acquire_file_lock(m_file_hnd, result, abs_time)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
return result;
}
inline void file_lock::unlock()
{
if(!ipcdetail::release_file_lock(m_file_hnd)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline void file_lock::lock_sharable()
{
if(!ipcdetail::acquire_file_lock_sharable(m_file_hnd)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline bool file_lock::try_lock_sharable()
{
bool result;
if(!ipcdetail::try_acquire_file_lock_sharable(m_file_hnd, result)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
return result;
}
inline bool file_lock::timed_lock_sharable(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock_sharable();
return true;
}
bool result;
if(!this->timed_acquire_file_lock_sharable(m_file_hnd, result, abs_time)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
return result;
}
inline void file_lock::unlock_sharable()
{
if(!ipcdetail::release_file_lock_sharable(m_file_hnd)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_FILE_LOCK_HPP

View File

@@ -0,0 +1,115 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// barrier is a modified version of Boost Threads barrier
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2003
// David Moore, 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_BARRIER_HPP
#define BOOST_INTERPROCESS_BARRIER_HPP
/// @cond
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED && defined BOOST_INTERPROCESS_POSIX_BARRIERS
# include <pthread.h>
# include <errno.h>
# include <boost/interprocess/sync/posix/pthread_helpers.hpp>
# define BOOST_INTERPROCESS_USE_POSIX
#else
# include <boost/interprocess/sync/interprocess_mutex.hpp>
# include <boost/interprocess/sync/scoped_lock.hpp>
# include <boost/interprocess/sync/interprocess_condition.hpp>
# include <stdexcept>
# define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
#endif
# include <boost/interprocess/exceptions.hpp>
/// @endcond
namespace boost {
namespace interprocess {
//!An object of class barrier is a synchronization primitive that
//!can be placed in shared memory used to cause a set of threads from
//!different processes to wait until they each perform a certain
//!function or each reach a particular point in their execution.
class barrier
{
public:
//!Constructs a barrier object that will cause count threads
//!to block on a call to wait().
barrier(unsigned int count);
//!Destroys *this. If threads are still executing their wait()
//!operations, the behavior for these threads is undefined.
~barrier();
//!Effects: Wait until N threads call wait(), where N equals the count
//!provided to the constructor for the barrier object.
//!Note that if the barrier is destroyed before wait() can return,
//!the behavior is undefined.
//!Returns: Exactly one of the N threads will receive a return value
//!of true, the others will receive a value of false. Precisely which
//!thread receives the return value of true will be implementation-defined.
//!Applications can use this value to designate one thread as a leader that
//!will take a certain action, and the other threads emerging from the barrier
//!can wait for that action to take place.
bool wait();
/// @cond
private:
#if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
interprocess_mutex m_mutex;
interprocess_condition m_cond;
unsigned int m_threshold;
unsigned int m_count;
unsigned int m_generation;
#else //#if defined BOOST_INTERPROCESS_USE_POSIX
pthread_barrier_t m_barrier;
#endif//#if defined BOOST_INTERPROCESS_USE_POSIX
/// @endcond
};
} // namespace interprocess
} // namespace boost
#ifdef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
# undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
# include <boost/interprocess/sync/emulation/interprocess_barrier.hpp>
#endif
#ifdef BOOST_INTERPROCESS_USE_POSIX
# undef BOOST_INTERPROCESS_USE_POSIX
# include <boost/interprocess/sync/posix/interprocess_barrier.hpp>
#endif
#include <boost/interprocess/detail/config_end.hpp>
#endif

View File

@@ -0,0 +1,179 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_CONDITION_HPP
#define BOOST_INTERPROCESS_CONDITION_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
/// @cond
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/limits.hpp>
#include <boost/assert.hpp>
#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
#include <pthread.h>
#include <errno.h>
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
#define BOOST_INTERPROCESS_USE_POSIX
#else
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/cstdint.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
#endif
/// @endcond
//!\file
//!Describes process-shared variables interprocess_condition class
namespace boost {
namespace posix_time
{ class ptime; }
namespace interprocess {
class named_condition;
//!This class is a condition variable that can be placed in shared memory or
//!memory mapped files.
class interprocess_condition
{
/// @cond
//Non-copyable
interprocess_condition(const interprocess_condition &);
interprocess_condition &operator=(const interprocess_condition &);
friend class named_condition;
/// @endcond
public:
//!Constructs a interprocess_condition. On error throws interprocess_exception.
interprocess_condition();
//!Destroys *this
//!liberating system resources.
~interprocess_condition();
//!If there is a thread waiting on *this, change that
//!thread's state to ready. Otherwise there is no effect.
void notify_one();
//!Change the state of all threads waiting on *this to ready.
//!If there are no waiting threads, notify_all() has no effect.
void notify_all();
//!Releases the lock on the interprocess_mutex object associated with lock, blocks
//!the current thread of execution until readied by a call to
//!this->notify_one() or this->notify_all(), and then reacquires the lock.
template <typename L>
void wait(L& lock)
{
if (!lock)
throw lock_exception();
do_wait(*lock.mutex());
}
//!The same as:
//!while (!pred()) wait(lock)
template <typename L, typename Pr>
void wait(L& lock, Pr pred)
{
if (!lock)
throw lock_exception();
while (!pred())
do_wait(*lock.mutex());
}
//!Releases the lock on the interprocess_mutex object associated with lock, blocks
//!the current thread of execution until readied by a call to
//!this->notify_one() or this->notify_all(), or until time abs_time is reached,
//!and then reacquires the lock.
//!Returns: false if time abs_time is reached, otherwise true.
template <typename L>
bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->wait(lock);
return true;
}
if (!lock)
throw lock_exception();
return do_timed_wait(abs_time, *lock.mutex());
}
//!The same as: while (!pred()) {
//! if (!timed_wait(lock, abs_time)) return pred();
//! } return true;
template <typename L, typename Pr>
bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
{
if(abs_time == boost::posix_time::pos_infin){
this->wait(lock, pred);
return true;
}
if (!lock)
throw lock_exception();
while (!pred()){
if (!do_timed_wait(abs_time, *lock.mutex()))
return pred();
}
return true;
}
/// @cond
private:
void do_wait(interprocess_mutex &mut);
bool do_timed_wait(const boost::posix_time::ptime &abs_time, interprocess_mutex &mut);
#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
enum { SLEEP = 0, NOTIFY_ONE, NOTIFY_ALL };
interprocess_mutex m_enter_mut;
//interprocess_mutex m_check_mut;
volatile boost::uint32_t m_command;
volatile boost::uint32_t m_num_waiters;
bool do_timed_wait(bool tout_enabled, const boost::posix_time::ptime &abs_time, interprocess_mutex &mut);
void notify(boost::uint32_t command);
#elif defined(BOOST_INTERPROCESS_USE_POSIX)
pthread_cond_t m_condition;
#endif
/// @endcond
};
} //namespace interprocess
} // namespace boost
#ifdef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
# undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
# include <boost/interprocess/sync/emulation/interprocess_condition.hpp>
#endif
#ifdef BOOST_INTERPROCESS_USE_POSIX
# undef BOOST_INTERPROCESS_USE_POSIX
# include <boost/interprocess/sync/posix/interprocess_condition.hpp>
#endif
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_CONDITION_HPP

View File

@@ -0,0 +1,162 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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
/// @cond
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/assert.hpp>
#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
#include <pthread.h>
#include <errno.h>
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
#define BOOST_INTERPROCESS_USE_POSIX
#else
#include <boost/interprocess/sync/emulation/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
/// @endcond
//!\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
{
/// @cond
//Non-copyable
interprocess_mutex(const interprocess_mutex &);
interprocess_mutex &operator=(const interprocess_mutex &);
friend class interprocess_condition;
/// @endcond
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();
/// @cond
private:
#if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
friend class ipcdetail::robust_emulation_helpers::mutex_traits<interprocess_mutex>;
void take_ownership(){ mutex.take_ownership(); }
ipcdetail::emulation_mutex mutex;
#elif defined(BOOST_INTERPROCESS_USE_POSIX)
pthread_mutex_t m_mut;
#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
/// @endcond
};
} //namespace interprocess {
} //namespace boost {
#ifdef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
# undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
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
= boost::posix_time::microsec_clock::universal_time()
+ boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS);
if (!mutex.timed_lock(wait_time))
{
throw interprocess_exception(timeout_when_locking_error, "Interprocess mutex timeout when locking. Possible deadlock: owner died without unlocking?");
}
#else
mutex.lock();
#endif
}
inline bool interprocess_mutex::try_lock(){ return mutex.try_lock(); }
inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time){ return mutex.timed_lock(abs_time); }
inline void interprocess_mutex::unlock(){ mutex.unlock(); }
} //namespace interprocess {
} //namespace boost {
#endif
#ifdef BOOST_INTERPROCESS_USE_POSIX
#include <boost/interprocess/sync/posix/interprocess_mutex.hpp>
# undef BOOST_INTERPROCESS_USE_POSIX
#endif
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MUTEX_HPP

View File

@@ -0,0 +1,171 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_RECURSIVE_MUTEX_HPP
#define BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP
/// @cond
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/assert.hpp>
#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \
(defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined (BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES))
#include <pthread.h>
#include <errno.h>
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
#define BOOST_INTERPROCESS_USE_POSIX
#else
#include <boost/interprocess/sync/emulation/recursive_mutex.hpp>
#define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
#endif
#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
namespace boost {
namespace interprocess {
namespace ipcdetail{
namespace robust_emulation_helpers {
template<class T>
class mutex_traits;
}}}}
#endif
/// @endcond
//!\file
//!Describes interprocess_recursive_mutex and shared_recursive_try_mutex classes
namespace boost {
namespace interprocess {
//!Wraps a interprocess_mutex that can be placed in shared memory and can be
//!shared between processes. Allows several locking calls by the same
//!process. Allows timed lock tries
class interprocess_recursive_mutex
{
/// @cond
//Non-copyable
interprocess_recursive_mutex(const interprocess_recursive_mutex &);
interprocess_recursive_mutex &operator=(const interprocess_recursive_mutex &);
/// @endcond
public:
//!Constructor.
//!Throws interprocess_exception on error.
interprocess_recursive_mutex();
//!Destructor. If any process uses the mutex after the destructor is called
//!the result is undefined. Does not throw.
~interprocess_recursive_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. The mutex must be unlocked
//! the same number of times it is locked.
//!Throws: interprocess_exception on error.
void lock();
//!Tries to lock the interprocess_mutex, returns false when interprocess_mutex
//!is already locked, returns true when success. The mutex must be unlocked
//!the same number of times it is locked.
//!Throws: interprocess_exception if a severe error is found
bool try_lock();
//!Tries to lock the interprocess_mutex, if interprocess_mutex can't be locked before
//!abs_time time, returns false. The mutex must be unlocked
//! the same number of times it is locked.
//!Throws: interprocess_exception if a severe error is found
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Effects: The calling thread releases the exclusive ownership of the mutex.
//! If the mutex supports recursive locking, the mutex must be unlocked the
//! same number of times it is locked.
//!Throws: interprocess_exception on error.
void unlock();
/// @cond
private:
#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
void take_ownership(){ mutex.take_ownership(); }
friend class ipcdetail::robust_emulation_helpers::mutex_traits<interprocess_recursive_mutex>;
ipcdetail::emulation_recursive_mutex mutex;
#else //#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
pthread_mutex_t m_mut;
#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
/// @endcond
};
} //namespace interprocess {
} //namespace boost {
#ifdef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
# undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
namespace boost {
namespace interprocess {
inline interprocess_recursive_mutex::interprocess_recursive_mutex(){}
inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){}
inline void interprocess_recursive_mutex::lock()
{
#ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING
boost::posix_time::ptime wait_time
= boost::posix_time::microsec_clock::universal_time()
+ boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS);
if (!mutex.timed_lock(wait_time))
{
throw interprocess_exception(timeout_when_locking_error, "Interprocess mutex timeout when locking. Possible deadlock: owner died without unlocking?");
}
#else
mutex.lock();
#endif
}
inline bool interprocess_recursive_mutex::try_lock(){ return mutex.try_lock(); }
inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time){ return mutex.timed_lock(abs_time); }
inline void interprocess_recursive_mutex::unlock(){ mutex.unlock(); }
} //namespace interprocess {
} //namespace boost {
#endif
#ifdef BOOST_INTERPROCESS_USE_POSIX
# undef BOOST_INTERPROCESS_USE_POSIX
#include <boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp>
#endif
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP

View File

@@ -0,0 +1,119 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_SEMAPHORE_HPP
#define BOOST_INTERPROCESS_SEMAPHORE_HPP
/// @cond
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \
(defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES))
#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/interprocess/sync/posix/semaphore_wrapper.hpp>
#define BOOST_INTERPROCESS_USE_POSIX
#else
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/cstdint.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
#endif
/// @endcond
//!\file
//!Describes a interprocess_semaphore class for inter-process synchronization
namespace boost {
namespace interprocess {
//!Wraps a interprocess_semaphore that can be placed in shared memory and can be
//!shared between processes. Allows timed lock tries
class interprocess_semaphore
{
/// @cond
//Non-copyable
interprocess_semaphore(const interprocess_semaphore &);
interprocess_semaphore &operator=(const interprocess_semaphore &);
/// @endcond
public:
//!Creates a interprocess_semaphore with the given initial count.
//!interprocess_exception if there is an error.*/
interprocess_semaphore(unsigned int initialCount);
//!Destroys the interprocess_semaphore.
//!Does not throw
~interprocess_semaphore();
//!Increments the interprocess_semaphore count. If there are processes/threads blocked waiting
//!for the interprocess_semaphore, then one of these processes will return successfully from
//!its wait function. If there is an error an interprocess_exception exception is thrown.
void post();
//!Decrements the interprocess_semaphore. If the interprocess_semaphore value is not greater than zero,
//!then the calling process/thread blocks until it can decrement the counter.
//!If there is an error an interprocess_exception exception is thrown.
void wait();
//!Decrements the interprocess_semaphore if the interprocess_semaphore's value is greater than zero
//!and returns true. If the value is not greater than zero returns false.
//!If there is an error an interprocess_exception exception is thrown.
bool try_wait();
//!Decrements the interprocess_semaphore if the interprocess_semaphore's value is greater
//!than zero and returns true. Otherwise, waits for the interprocess_semaphore
//!to the posted or the timeout expires. If the timeout expires, the
//!function returns false. If the interprocess_semaphore is posted the function
//!returns true. If there is an error throws sem_exception
bool timed_wait(const boost::posix_time::ptime &abs_time);
//!Returns the interprocess_semaphore count
// int get_count() const;
/// @cond
private:
#if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
volatile boost::uint32_t m_count;
#else
ipcdetail::semaphore_wrapper m_sem;
#endif //#if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
/// @endcond
};
} //namespace interprocess {
} //namespace boost {
#ifdef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
# undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
# include <boost/interprocess/sync/emulation/interprocess_semaphore.hpp>
#endif
#ifdef BOOST_INTERPROCESS_USE_POSIX
# undef BOOST_INTERPROCESS_USE_POSIX
# include <boost/interprocess/sync/posix/interprocess_semaphore.hpp>
#endif
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_SEMAPHORE_HPP

View File

@@ -0,0 +1,658 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_UPGRADABLE_MUTEX_HPP
#define BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <climits>
//!\file
//!Describes interprocess_upgradable_mutex class
namespace boost {
namespace interprocess {
//!Wraps a interprocess_upgradable_mutex that can be placed in shared memory and can be
//!shared between processes. Allows timed lock tries
class interprocess_upgradable_mutex
{
//Non-copyable
interprocess_upgradable_mutex(const interprocess_upgradable_mutex &);
interprocess_upgradable_mutex &operator=(const interprocess_upgradable_mutex &);
friend class interprocess_condition;
public:
//!Constructs the upgradable lock.
//!Throws interprocess_exception on error.
interprocess_upgradable_mutex();
//!Destroys the upgradable lock.
//!Does not throw.
~interprocess_upgradable_mutex();
//Exclusive locking
//!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
//! and if another thread has exclusive, sharable or upgradable ownership of
//! the mutex, it waits until it can obtain the ownership.
//!Throws: interprocess_exception on error.
void lock();
//!Effects: The calling thread tries to acquire exclusive ownership of the mutex
//! without waiting. If no other thread has exclusive, sharable or upgradable
//! ownership of the mutex this succeeds.
//!Returns: If it can acquire exclusive ownership immediately returns true.
//! If it has to wait, returns false.
//!Throws: interprocess_exception on error.
bool try_lock();
//!Effects: The calling thread tries to acquire exclusive ownership of the mutex
//! waiting if necessary until no other thread has has exclusive, sharable or
//! upgradable ownership of the mutex or abs_time is reached.
//!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
//!Throws: interprocess_exception on error.
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Precondition: The thread must have exclusive ownership of the mutex.
//!Effects: The calling thread releases the exclusive ownership of the mutex.
//!Throws: An exception derived from interprocess_exception on error.
void unlock();
//Sharable locking
//!Effects: The calling thread tries to obtain sharable ownership of the mutex,
//! and if another thread has exclusive or upgradable ownership of the mutex,
//! waits until it can obtain the ownership.
//!Throws: interprocess_exception on error.
void lock_sharable();
//!Effects: The calling thread tries to acquire sharable ownership of the mutex
//! without waiting. If no other thread has has exclusive or upgradable ownership
//! of the mutex this succeeds.
//!Returns: If it can acquire sharable ownership immediately returns true. If it
//! has to wait, returns false.
//!Throws: interprocess_exception on error.
bool try_lock_sharable();
//!Effects: The calling thread tries to acquire sharable ownership of the mutex
//! waiting if necessary until no other thread has has exclusive or upgradable
//! ownership of the mutex or abs_time is reached.
//!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
//!Throws: interprocess_exception on error.
bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
//!Precondition: The thread must have sharable ownership of the mutex.
//!Effects: The calling thread releases the sharable ownership of the mutex.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_sharable();
//Upgradable locking
//!Effects: The calling thread tries to obtain upgradable ownership of the mutex,
//! and if another thread has exclusive or upgradable ownership of the mutex,
//! waits until it can obtain the ownership.
//!Throws: interprocess_exception on error.
void lock_upgradable();
//!Effects: The calling thread tries to acquire upgradable ownership of the mutex
//! without waiting. If no other thread has has exclusive or upgradable ownership
//! of the mutex this succeeds.
//!Returns: If it can acquire upgradable ownership immediately returns true.
//! If it has to wait, returns false.
//!Throws: interprocess_exception on error.
bool try_lock_upgradable();
//!Effects: The calling thread tries to acquire upgradable ownership of the mutex
//! waiting if necessary until no other thread has has exclusive or upgradable
//! ownership of the mutex or abs_time is reached.
//!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
//!Throws: interprocess_exception on error.
bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time);
//!Precondition: The thread must have upgradable ownership of the mutex.
//!Effects: The calling thread releases the upgradable ownership of the mutex.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_upgradable();
//Demotions
//!Precondition: The thread must have exclusive ownership of the mutex.
//!Effects: The thread atomically releases exclusive ownership and acquires
//! upgradable ownership. This operation is non-blocking.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_and_lock_upgradable();
//!Precondition: The thread must have exclusive ownership of the mutex.
//!Effects: The thread atomically releases exclusive ownership and acquires
//! sharable ownership. This operation is non-blocking.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_and_lock_sharable();
//!Precondition: The thread must have upgradable ownership of the mutex.
//!Effects: The thread atomically releases upgradable ownership and acquires
//! sharable ownership. This operation is non-blocking.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_upgradable_and_lock_sharable();
//Promotions
//!Precondition: The thread must have upgradable ownership of the mutex.
//!Effects: The thread atomically releases upgradable ownership and acquires
//! exclusive ownership. This operation will block until all threads with
//! sharable ownership release their sharable lock.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_upgradable_and_lock();
//!Precondition: The thread must have upgradable ownership of the mutex.
//!Effects: The thread atomically releases upgradable ownership and tries to
//! acquire exclusive ownership. This operation will fail if there are threads
//! with sharable ownership, but it will maintain upgradable ownership.
//!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
//!Throws: An exception derived from interprocess_exception on error.
bool try_unlock_upgradable_and_lock();
//!Precondition: The thread must have upgradable ownership of the mutex.
//!Effects: The thread atomically releases upgradable ownership and tries to acquire
//! exclusive ownership, waiting if necessary until abs_time. This operation will
//! fail if there are threads with sharable ownership or timeout reaches, but it
//! will maintain upgradable ownership.
//!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
//!Throws: An exception derived from interprocess_exception on error. */
bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time);
//!Precondition: The thread must have sharable ownership of the mutex.
//!Effects: The thread atomically releases sharable ownership and tries to acquire
//! exclusive ownership. This operation will fail if there are threads with sharable
//! or upgradable ownership, but it will maintain sharable ownership.
//!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
//!Throws: An exception derived from interprocess_exception on error.
bool try_unlock_sharable_and_lock();
//!Precondition: The thread must have sharable ownership of the mutex.
//!Effects: The thread atomically releases sharable ownership and tries to acquire
//! upgradable ownership. This operation will fail if there are threads with sharable
//! or upgradable ownership, but it will maintain sharable ownership.
//!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
//!Throws: An exception derived from interprocess_exception on error.
bool try_unlock_sharable_and_lock_upgradable();
/// @cond
private:
typedef scoped_lock<interprocess_mutex> scoped_lock_t;
//Pack all the control data in a word to be able
//to use atomic instructions in the future
struct control_word_t
{
unsigned exclusive_in : 1;
unsigned upgradable_in : 1;
unsigned num_upr_shar : sizeof(unsigned)*CHAR_BIT-2;
} m_ctrl;
interprocess_mutex m_mut;
interprocess_condition m_first_gate;
interprocess_condition m_second_gate;
private:
//Rollback structures for exceptions or failure return values
struct exclusive_rollback
{
exclusive_rollback(control_word_t &ctrl
,interprocess_condition &first_gate)
: mp_ctrl(&ctrl), m_first_gate(first_gate)
{}
void release()
{ mp_ctrl = 0; }
~exclusive_rollback()
{
if(mp_ctrl){
mp_ctrl->exclusive_in = 0;
m_first_gate.notify_all();
}
}
control_word_t *mp_ctrl;
interprocess_condition &m_first_gate;
};
struct upgradable_to_exclusive_rollback
{
upgradable_to_exclusive_rollback(control_word_t &ctrl)
: mp_ctrl(&ctrl)
{}
void release()
{ mp_ctrl = 0; }
~upgradable_to_exclusive_rollback()
{
if(mp_ctrl){
//Recover upgradable lock
mp_ctrl->upgradable_in = 1;
++mp_ctrl->num_upr_shar;
//Execute the second half of exclusive locking
mp_ctrl->exclusive_in = 0;
}
}
control_word_t *mp_ctrl;
};
template<int Dummy>
struct base_constants_t
{
static const unsigned max_readers
= ~(unsigned(3) << (sizeof(unsigned)*CHAR_BIT-2));
};
typedef base_constants_t<0> constants;
/// @endcond
};
/// @cond
template <int Dummy>
const unsigned interprocess_upgradable_mutex::base_constants_t<Dummy>::max_readers;
inline interprocess_upgradable_mutex::interprocess_upgradable_mutex()
{
this->m_ctrl.exclusive_in = 0;
this->m_ctrl.upgradable_in = 0;
this->m_ctrl.num_upr_shar = 0;
}
inline interprocess_upgradable_mutex::~interprocess_upgradable_mutex()
{}
inline void interprocess_upgradable_mutex::lock()
{
scoped_lock_t lock(m_mut);
//The exclusive lock must block in the first gate
//if an exclusive or upgradable lock has been acquired
while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
this->m_first_gate.wait(lock);
}
//Mark that exclusive lock has been acquired
this->m_ctrl.exclusive_in = 1;
//Prepare rollback
exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
//Now wait until all readers are gone
while (this->m_ctrl.num_upr_shar){
this->m_second_gate.wait(lock);
}
rollback.release();
}
inline bool interprocess_upgradable_mutex::try_lock()
{
scoped_lock_t lock(m_mut, try_to_lock);
//If we can't lock or any has there is any exclusive, upgradable
//or sharable mark return false;
if(!lock.owns()
|| this->m_ctrl.exclusive_in
|| this->m_ctrl.num_upr_shar){
return false;
}
this->m_ctrl.exclusive_in = 1;
return true;
}
inline bool interprocess_upgradable_mutex::timed_lock
(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
scoped_lock_t lock(m_mut, abs_time);
if(!lock.owns()) return false;
//The exclusive lock must block in the first gate
//if an exclusive or upgradable lock has been acquired
while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
if(!this->m_first_gate.timed_wait(lock, abs_time))
return !(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in);
}
//Mark that exclusive lock has been acquired
this->m_ctrl.exclusive_in = 1;
//Prepare rollback
exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
//Now wait until all readers are gone
while (this->m_ctrl.num_upr_shar){
if(!this->m_second_gate.timed_wait(lock, abs_time)){
return !(this->m_ctrl.num_upr_shar);
}
}
rollback.release();
return true;
}
inline void interprocess_upgradable_mutex::unlock()
{
scoped_lock_t lock(m_mut);
this->m_ctrl.exclusive_in = 0;
this->m_first_gate.notify_all();
}
//Upgradable locking
inline void interprocess_upgradable_mutex::lock_upgradable()
{
scoped_lock_t lock(m_mut);
//The upgradable lock must block in the first gate
//if an exclusive or upgradable lock has been acquired
//or there are too many sharable locks
while(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in
|| this->m_ctrl.num_upr_shar == constants::max_readers){
this->m_first_gate.wait(lock);
}
//Mark that upgradable lock has been acquired
//And add upgradable to the sharable count
this->m_ctrl.upgradable_in = 1;
++this->m_ctrl.num_upr_shar;
}
inline bool interprocess_upgradable_mutex::try_lock_upgradable()
{
scoped_lock_t lock(m_mut, try_to_lock);
//The upgradable lock must fail
//if an exclusive or upgradable lock has been acquired
//or there are too many sharable locks
if(!lock.owns()
|| this->m_ctrl.exclusive_in
|| this->m_ctrl.upgradable_in
|| this->m_ctrl.num_upr_shar == constants::max_readers){
return false;
}
//Mark that upgradable lock has been acquired
//And add upgradable to the sharable count
this->m_ctrl.upgradable_in = 1;
++this->m_ctrl.num_upr_shar;
return true;
}
inline bool interprocess_upgradable_mutex::timed_lock_upgradable
(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock_upgradable();
return true;
}
scoped_lock_t lock(m_mut, abs_time);
if(!lock.owns()) return false;
//The upgradable lock must block in the first gate
//if an exclusive or upgradable lock has been acquired
//or there are too many sharable locks
while(this->m_ctrl.exclusive_in
|| this->m_ctrl.upgradable_in
|| this->m_ctrl.num_upr_shar == constants::max_readers){
if(!this->m_first_gate.timed_wait(lock, abs_time)){
return!(this->m_ctrl.exclusive_in
|| this->m_ctrl.upgradable_in
|| this->m_ctrl.num_upr_shar == constants::max_readers);
}
}
//Mark that upgradable lock has been acquired
//And add upgradable to the sharable count
this->m_ctrl.upgradable_in = 1;
++this->m_ctrl.num_upr_shar;
return true;
}
inline void interprocess_upgradable_mutex::unlock_upgradable()
{
scoped_lock_t lock(m_mut);
//Mark that upgradable lock has been acquired
//And add upgradable to the sharable count
this->m_ctrl.upgradable_in = 0;
--this->m_ctrl.num_upr_shar;
this->m_first_gate.notify_all();
}
//Sharable locking
inline void interprocess_upgradable_mutex::lock_sharable()
{
scoped_lock_t lock(m_mut);
//The sharable lock must block in the first gate
//if an exclusive lock has been acquired
//or there are too many sharable locks
while(this->m_ctrl.exclusive_in
|| this->m_ctrl.num_upr_shar == constants::max_readers){
this->m_first_gate.wait(lock);
}
//Increment sharable count
++this->m_ctrl.num_upr_shar;
}
inline bool interprocess_upgradable_mutex::try_lock_sharable()
{
scoped_lock_t lock(m_mut, try_to_lock);
//The sharable lock must fail
//if an exclusive lock has been acquired
//or there are too many sharable locks
if(!lock.owns()
|| this->m_ctrl.exclusive_in
|| this->m_ctrl.num_upr_shar == constants::max_readers){
return false;
}
//Increment sharable count
++this->m_ctrl.num_upr_shar;
return true;
}
inline bool interprocess_upgradable_mutex::timed_lock_sharable
(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock_sharable();
return true;
}
scoped_lock_t lock(m_mut, abs_time);
if(!lock.owns()) return false;
//The sharable lock must block in the first gate
//if an exclusive lock has been acquired
//or there are too many sharable locks
while (this->m_ctrl.exclusive_in
|| this->m_ctrl.num_upr_shar == constants::max_readers){
if(!this->m_first_gate.timed_wait(lock, abs_time)){
return!(this->m_ctrl.exclusive_in
|| this->m_ctrl.num_upr_shar == constants::max_readers);
}
}
//Increment sharable count
++this->m_ctrl.num_upr_shar;
return true;
}
inline void interprocess_upgradable_mutex::unlock_sharable()
{
scoped_lock_t lock(m_mut);
//Decrement sharable count
--this->m_ctrl.num_upr_shar;
if (this->m_ctrl.num_upr_shar == 0){
this->m_second_gate.notify_one();
}
//Check if there are blocked sharables because of
//there were too many sharables
else if(this->m_ctrl.num_upr_shar == (constants::max_readers-1)){
this->m_first_gate.notify_all();
}
}
//Downgrading
inline void interprocess_upgradable_mutex::unlock_and_lock_upgradable()
{
scoped_lock_t lock(m_mut);
//Unmark it as exclusive
this->m_ctrl.exclusive_in = 0;
//Mark it as upgradable
this->m_ctrl.upgradable_in = 1;
//The sharable count should be 0 so increment it
this->m_ctrl.num_upr_shar = 1;
//Notify readers that they can enter
m_first_gate.notify_all();
}
inline void interprocess_upgradable_mutex::unlock_and_lock_sharable()
{
scoped_lock_t lock(m_mut);
//Unmark it as exclusive
this->m_ctrl.exclusive_in = 0;
//The sharable count should be 0 so increment it
this->m_ctrl.num_upr_shar = 1;
//Notify readers that they can enter
m_first_gate.notify_all();
}
inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock_sharable()
{
scoped_lock_t lock(m_mut);
//Unmark it as upgradable (we don't have to decrement count)
this->m_ctrl.upgradable_in = 0;
//Notify readers/upgradable that they can enter
m_first_gate.notify_all();
}
//Upgrading
inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock()
{
scoped_lock_t lock(m_mut);
//Simulate unlock_upgradable() without
//notifying sharables.
this->m_ctrl.upgradable_in = 0;
--this->m_ctrl.num_upr_shar;
//Execute the second half of exclusive locking
this->m_ctrl.exclusive_in = 1;
//Prepare rollback
upgradable_to_exclusive_rollback rollback(m_ctrl);
while (this->m_ctrl.num_upr_shar){
this->m_second_gate.wait(lock);
}
rollback.release();
}
inline bool interprocess_upgradable_mutex::try_unlock_upgradable_and_lock()
{
scoped_lock_t lock(m_mut, try_to_lock);
//Check if there are no readers
if(!lock.owns()
|| this->m_ctrl.num_upr_shar != 1){
return false;
}
//Now unlock upgradable and mark exclusive
this->m_ctrl.upgradable_in = 0;
--this->m_ctrl.num_upr_shar;
this->m_ctrl.exclusive_in = 1;
return true;
}
inline bool interprocess_upgradable_mutex::timed_unlock_upgradable_and_lock
(const boost::posix_time::ptime &abs_time)
{
scoped_lock_t lock(m_mut, abs_time);
if(!lock.owns()) return false;
//Simulate unlock_upgradable() without
//notifying sharables.
this->m_ctrl.upgradable_in = 0;
--this->m_ctrl.num_upr_shar;
//Execute the second half of exclusive locking
this->m_ctrl.exclusive_in = 1;
//Prepare rollback
upgradable_to_exclusive_rollback rollback(m_ctrl);
while (this->m_ctrl.num_upr_shar){
if(!this->m_second_gate.timed_wait(lock, abs_time)){
return !(this->m_ctrl.num_upr_shar);
}
}
rollback.release();
return true;
}
inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock()
{
scoped_lock_t lock(m_mut, try_to_lock);
//If we can't lock or any has there is any exclusive, upgradable
//or sharable mark return false;
if(!lock.owns()
|| this->m_ctrl.exclusive_in
|| this->m_ctrl.upgradable_in
|| this->m_ctrl.num_upr_shar != 1){
return false;
}
this->m_ctrl.exclusive_in = 1;
this->m_ctrl.num_upr_shar = 0;
return true;
}
inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradable()
{
scoped_lock_t lock(m_mut, try_to_lock);
//The upgradable lock must fail
//if an exclusive or upgradable lock has been acquired
if(!lock.owns()
|| this->m_ctrl.exclusive_in
|| this->m_ctrl.upgradable_in){
return false;
}
//Mark that upgradable lock has been acquired
this->m_ctrl.upgradable_in = 1;
return true;
}
/// @endcond
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP

View File

@@ -0,0 +1,55 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# 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 {
namespace posix_time
{ class ptime; }
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

View File

@@ -0,0 +1,56 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MUTEX_FAMILY_HPP
#define BOOST_INTERPROCESS_MUTEX_FAMILY_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/interprocess/sync/null_mutex.hpp>
//!\file
//!Describes a shared interprocess_mutex family fit algorithm used to allocate objects in shared memory.
namespace boost {
namespace interprocess {
//!Describes interprocess_mutex family to use with Interprocess framework
//!based on boost::interprocess synchronization objects.
struct mutex_family
{
typedef boost::interprocess::interprocess_mutex mutex_type;
typedef boost::interprocess::interprocess_recursive_mutex recursive_mutex_type;
};
//!Describes interprocess_mutex family to use with Interprocess frameworks
//!based on null operation synchronization objects.
struct null_mutex_family
{
typedef boost::interprocess::null_mutex mutex_type;
typedef boost::interprocess::null_mutex recursive_mutex_type;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP

View File

@@ -0,0 +1,371 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_CONDITION_HPP
#define BOOST_INTERPROCESS_NAMED_CONDITION_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/static_assert.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/emulation/named_creation_functor.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/permissions.hpp>
#if defined BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#endif
//!\file
//!Describes process-shared variables interprocess_condition class
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail{ class interprocess_tester; }
/// @endcond
//! A global condition variable that can be created by name.
//! This condition variable is designed to work with named_mutex and
//! can't be placed in shared memory or memory mapped files.
class named_condition
{
/// @cond
//Non-copyable
named_condition();
named_condition(const named_condition &);
named_condition &operator=(const named_condition &);
/// @endcond
public:
//!Creates a global condition with a name.
//!If the condition can't be created throws interprocess_exception
named_condition(create_only_t create_only, const char *name, const permissions &perm = permissions());
//!Opens or creates a global condition with a name.
//!If the condition is created, this call is equivalent to
//!named_condition(create_only_t, ... )
//!If the condition is already created, this call is equivalent
//!named_condition(open_only_t, ... )
//!Does not throw
named_condition(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions());
//!Opens a global condition with a name if that condition is previously
//!created. If it is not previously created this function throws
//!interprocess_exception.
named_condition(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_condition();
//!If there is a thread waiting on *this, change that
//!thread's state to ready. Otherwise there is no effect.*/
void notify_one();
//!Change the state of all threads waiting on *this to ready.
//!If there are no waiting threads, notify_all() has no effect.
void notify_all();
//!Releases the lock on the named_mutex object associated with lock, blocks
//!the current thread of execution until readied by a call to
//!this->notify_one() or this->notify_all(), and then reacquires the lock.
template <typename L>
void wait(L& lock);
//!The same as:
//!while (!pred()) wait(lock)
template <typename L, typename Pr>
void wait(L& lock, Pr pred);
//!Releases the lock on the named_mutex object associated with lock, blocks
//!the current thread of execution until readied by a call to
//!this->notify_one() or this->notify_all(), or until time abs_time is reached,
//!and then reacquires the lock.
//!Returns: false if time abs_time is reached, otherwise true.
template <typename L>
bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time);
//!The same as: while (!pred()) {
//! if (!timed_wait(lock, abs_time)) return pred();
//! } return true;
template <typename L, typename Pr>
bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred);
//!Erases a named condition from the system.
//!Returns false on error. Never throws.
static bool remove(const char *name);
/// @cond
private:
struct condition_holder
{
interprocess_condition cond_;
//If named_mutex is implemented using semaphores
//we need to store an additional mutex
#if defined (BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
interprocess_mutex mutex_;
#endif
};
interprocess_condition *condition() const
{ return &static_cast<condition_holder*>(m_shmem.get_user_address())->cond_; }
template <class Lock>
class lock_inverter
{
Lock &l_;
public:
lock_inverter(Lock &l)
: l_(l)
{}
void lock() { l_.unlock(); }
void unlock() { l_.lock(); }
};
#if defined (BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
interprocess_mutex *mutex() const
{ return &static_cast<condition_holder*>(m_shmem.get_user_address())->mutex_; }
template <class Lock>
void do_wait(Lock& lock)
{
//named_condition only works with named_mutex
BOOST_STATIC_ASSERT((ipcdetail::is_convertible<typename Lock::mutex_type&, named_mutex&>::value == true));
//lock internal before unlocking external to avoid race with a notifier
scoped_lock<interprocess_mutex> internal_lock(*this->mutex());
lock_inverter<Lock> inverted_lock(lock);
scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock);
//unlock internal first to avoid deadlock with near simultaneous waits
scoped_lock<interprocess_mutex> internal_unlock;
internal_lock.swap(internal_unlock);
this->condition()->wait(internal_unlock);
}
template <class Lock>
bool do_timed_wait(Lock& lock, const boost::posix_time::ptime &abs_time)
{
//named_condition only works with named_mutex
BOOST_STATIC_ASSERT((ipcdetail::is_convertible<typename Lock::mutex_type&, named_mutex&>::value == true));
//lock internal before unlocking external to avoid race with a notifier
scoped_lock<interprocess_mutex> internal_lock(*this->mutex(), abs_time);
if(!internal_lock) return false;
lock_inverter<Lock> inverted_lock(lock);
scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock);
//unlock internal first to avoid deadlock with near simultaneous waits
scoped_lock<interprocess_mutex> internal_unlock;
internal_lock.swap(internal_unlock);
return this->condition()->timed_wait(internal_unlock, abs_time);
}
#endif
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction();
ipcdetail::managed_open_or_create_impl<shared_memory_object> m_shmem;
template <class T, class Arg> friend class boost::interprocess::ipcdetail::named_creation_functor;
typedef ipcdetail::named_creation_functor<condition_holder> construct_func_t;
/// @endcond
};
/// @cond
inline named_condition::~named_condition()
{}
inline named_condition::named_condition(create_only_t, const char *name, const permissions &perm)
: m_shmem (create_only
,name
,sizeof(condition_holder) +
ipcdetail::managed_open_or_create_impl<shared_memory_object>::
ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoCreate)
,perm)
{}
inline named_condition::named_condition(open_or_create_t, const char *name, const permissions &perm)
: m_shmem (open_or_create
,name
,sizeof(condition_holder) +
ipcdetail::managed_open_or_create_impl<shared_memory_object>::
ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoOpenOrCreate)
,perm)
{}
inline named_condition::named_condition(open_only_t, const char *name)
: m_shmem (open_only
,name
,read_write
,0
,construct_func_t(ipcdetail::DoOpen))
{}
inline void named_condition::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); }
#if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
inline void named_condition::notify_one()
{
scoped_lock<interprocess_mutex> internal_lock(*this->mutex());
this->condition()->notify_one();
}
inline void named_condition::notify_all()
{
scoped_lock<interprocess_mutex> internal_lock(*this->mutex());
this->condition()->notify_all();
}
template <typename L>
inline void named_condition::wait(L& lock)
{
if (!lock)
throw lock_exception();
this->do_wait(lock);
}
template <typename L, typename Pr>
inline void named_condition::wait(L& lock, Pr pred)
{
if (!lock)
throw lock_exception();
while (!pred())
this->do_wait(lock);
}
template <typename L>
inline bool named_condition::timed_wait
(L& lock, const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->wait(lock);
return true;
}
if (!lock)
throw lock_exception();
return this->do_timed_wait(lock, abs_time);
}
template <typename L, typename Pr>
inline bool named_condition::timed_wait
(L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
{
if(abs_time == boost::posix_time::pos_infin){
this->wait(lock, pred);
return true;
}
if (!lock)
throw lock_exception();
while (!pred()){
if(!this->do_timed_wait(lock, abs_time)){
return pred();
}
}
return true;
}
#else
inline void named_condition::notify_one()
{ this->condition()->notify_one(); }
inline void named_condition::notify_all()
{ this->condition()->notify_all(); }
template <typename L>
inline void named_condition::wait(L& lock)
{
if (!lock)
throw lock_exception();
this->condition()->do_wait(*lock.mutex()->mutex());
}
template <typename L, typename Pr>
inline void named_condition::wait(L& lock, Pr pred)
{
if (!lock)
throw lock_exception();
while (!pred())
this->condition()->do_wait(*lock.mutex()->mutex());
}
template <typename L>
inline bool named_condition::timed_wait
(L& lock, const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->wait(lock);
return true;
}
if (!lock)
throw lock_exception();
return this->condition()->do_timed_wait(abs_time, *lock.mutex()->mutex());
}
template <typename L, typename Pr>
inline bool named_condition::timed_wait
(L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
{
if(abs_time == boost::posix_time::pos_infin){
this->wait(lock, pred);
return true;
}
if (!lock)
throw lock_exception();
while (!pred()){
if (!this->condition()->do_timed_wait(abs_time, *lock.mutex()->mutex()))
return pred();
}
return true;
}
#endif
inline bool named_condition::remove(const char *name)
{ return shared_memory_object::remove(name); }
/// @endcond
} //namespace interprocess
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_NAMED_CONDITION_HPP

View File

@@ -0,0 +1,235 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/sync/emulation/named_creation_functor.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/permissions.hpp>
#if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
#include <boost/interprocess/sync/posix/semaphore_wrapper.hpp>
#else
#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/detail/posix_time_types_wrk.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
{
/// @cond
//Non-copyable
named_mutex();
named_mutex(const named_mutex &);
named_mutex &operator=(const named_mutex &);
friend class named_condition;
/// @endcond
public:
//!Creates a global interprocess_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
//!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);
/// @cond
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction();
#if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
ipcdetail::named_semaphore_wrapper m_sem;
#else
interprocess_mutex *mutex() const
{ return static_cast<interprocess_mutex*>(m_shmem.get_user_address()); }
ipcdetail::managed_open_or_create_impl<shared_memory_object> m_shmem;
typedef ipcdetail::named_creation_functor<interprocess_mutex> construct_func_t;
#endif
/// @endcond
};
/// @cond
#if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
inline named_mutex::named_mutex(create_only_t, const char *name, const permissions &perm)
: m_sem(ipcdetail::DoCreate, name, 1, perm)
{}
inline named_mutex::named_mutex(open_or_create_t, const char *name, const permissions &perm)
: m_sem(ipcdetail::DoOpenOrCreate, name, 1, perm)
{}
inline named_mutex::named_mutex(open_only_t, const char *name)
: m_sem(ipcdetail::DoOpen, name, 1, permissions())
{}
inline void named_mutex::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_sem); }
inline named_mutex::~named_mutex()
{}
inline void named_mutex::lock()
{ m_sem.wait(); }
inline void named_mutex::unlock()
{ m_sem.post(); }
inline bool named_mutex::try_lock()
{ return m_sem.try_wait(); }
inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
return m_sem.timed_wait(abs_time);
}
inline bool named_mutex::remove(const char *name)
{ return ipcdetail::named_semaphore_wrapper::remove(name); }
#else
inline void named_mutex::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); }
inline named_mutex::~named_mutex()
{}
inline named_mutex::named_mutex(create_only_t, const char *name, const permissions &perm)
: m_shmem (create_only
,name
,sizeof(interprocess_mutex) +
ipcdetail::managed_open_or_create_impl<shared_memory_object>::
ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoCreate)
,perm)
{}
inline named_mutex::named_mutex(open_or_create_t, const char *name, const permissions &perm)
: m_shmem (open_or_create
,name
,sizeof(interprocess_mutex) +
ipcdetail::managed_open_or_create_impl<shared_memory_object>::
ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoOpenOrCreate)
,perm)
{}
inline named_mutex::named_mutex(open_only_t, const char *name)
: m_shmem (open_only
,name
,read_write
,0
,construct_func_t(ipcdetail::DoOpen))
{}
inline void named_mutex::lock()
{ this->mutex()->lock(); }
inline void named_mutex::unlock()
{ this->mutex()->unlock(); }
inline bool named_mutex::try_lock()
{ return this->mutex()->try_lock(); }
inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
return this->mutex()->timed_lock(abs_time);
}
inline bool named_mutex::remove(const char *name)
{ return shared_memory_object::remove(name); }
#endif
/// @endcond
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NAMED_MUTEX_HPP

View File

@@ -0,0 +1,180 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_RECURSIVE_MUTEX_HPP
#define BOOST_INTERPROCESS_NAMED_RECURSIVE_MUTEX_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/interprocess/sync/emulation/named_creation_functor.hpp>
#include <boost/interprocess/permissions.hpp>
//!\file
//!Describes a named named_recursive_mutex class for inter-process synchronization
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail{ class interprocess_tester; }
/// @endcond
//!A recursive 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_recursive_mutex.
class named_recursive_mutex
{
/// @cond
//Non-copyable
named_recursive_mutex();
named_recursive_mutex(const named_recursive_mutex &);
named_recursive_mutex &operator=(const named_recursive_mutex &);
/// @endcond
public:
//!Creates a global recursive_mutex with a name.
//!If the recursive_mutex can't be created throws interprocess_exception
named_recursive_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions());
//!Opens or creates a global recursive_mutex with a name.
//!If the recursive_mutex is created, this call is equivalent to
//!named_recursive_mutex(create_only_t, ... )
//!If the recursive_mutex is already created, this call is equivalent
//!named_recursive_mutex(open_only_t, ... )
//!Does not throw
named_recursive_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions());
//!Opens a global recursive_mutex with a name if that recursive_mutex is previously
//!created. If it is not previously created this function throws
//!interprocess_exception.
named_recursive_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_recursive_mutex();
//!Unlocks a previously locked
//!named_recursive_mutex.
void unlock();
//!Locks named_recursive_mutex, sleeps when named_recursive_mutex is already locked.
//!Throws interprocess_exception if a severe error is found.
void lock();
//!Tries to lock the named_recursive_mutex, returns false when named_recursive_mutex
//!is already locked, returns true when success.
//!Throws interprocess_exception if a severe error is found.
bool try_lock();
//!Tries to lock the named_recursive_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 recursive mutex
//!from the system
static bool remove(const char *name);
/// @cond
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction();
interprocess_recursive_mutex *mutex() const
{ return static_cast<interprocess_recursive_mutex*>(m_shmem.get_user_address()); }
ipcdetail::managed_open_or_create_impl<shared_memory_object> m_shmem;
typedef ipcdetail::named_creation_functor<interprocess_recursive_mutex> construct_func_t;
/// @endcond
};
/// @cond
inline named_recursive_mutex::~named_recursive_mutex()
{}
inline void named_recursive_mutex::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); }
inline named_recursive_mutex::named_recursive_mutex(create_only_t, const char *name, const permissions &perm)
: m_shmem (create_only
,name
,sizeof(interprocess_recursive_mutex) +
ipcdetail::managed_open_or_create_impl<shared_memory_object>::
ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoCreate)
,perm)
{}
inline named_recursive_mutex::named_recursive_mutex(open_or_create_t, const char *name, const permissions &perm)
: m_shmem (open_or_create
,name
,sizeof(interprocess_recursive_mutex) +
ipcdetail::managed_open_or_create_impl<shared_memory_object>::
ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoOpenOrCreate)
,perm)
{}
inline named_recursive_mutex::named_recursive_mutex(open_only_t, const char *name)
: m_shmem (open_only
,name
,read_write
,0
,construct_func_t(ipcdetail::DoOpen))
{}
inline void named_recursive_mutex::lock()
{ this->mutex()->lock(); }
inline void named_recursive_mutex::unlock()
{ this->mutex()->unlock(); }
inline bool named_recursive_mutex::try_lock()
{ return this->mutex()->try_lock(); }
inline bool named_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
return this->mutex()->timed_lock(abs_time);
}
inline bool named_recursive_mutex::remove(const char *name)
{ return shared_memory_object::remove(name); }
/// @endcond
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NAMED_RECURSIVE_MUTEX_HPP

View File

@@ -0,0 +1,242 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_SEMAPHORE_HPP
#define BOOST_INTERPROCESS_NAMED_SEMAPHORE_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#if defined(BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES)
#include <boost/interprocess/sync/posix/semaphore_wrapper.hpp>
#else
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/interprocess/sync/emulation/named_creation_functor.hpp>
#endif
//!\file
//!Describes a named semaphore class for inter-process synchronization
namespace boost {
namespace interprocess {
//!A semaphore with a global name, so it can be found from different
//!processes. Allows several resource sharing patterns and efficient
//!acknowledgment mechanisms.
class named_semaphore
{
/// @cond
//Non-copyable
named_semaphore();
named_semaphore(const named_semaphore &);
named_semaphore &operator=(const named_semaphore &);
/// @endcond
public:
//!Creates a global semaphore with a name, and an initial count.
//!If the semaphore can't be created throws interprocess_exception
named_semaphore(create_only_t, const char *name, unsigned int initialCount, const permissions &perm = permissions());
//!Opens or creates a global semaphore with a name, and an initial count.
//!If the semaphore is created, this call is equivalent to
//!named_semaphore(create_only_t, ...)
//!If the semaphore is already created, this call is equivalent to
//!named_semaphore(open_only_t, ... )
//!and initialCount is ignored.
named_semaphore(open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm = permissions());
//!Opens a global semaphore with a name if that semaphore is previously.
//!created. If it is not previously created this function throws
//!interprocess_exception.
named_semaphore(open_only_t, 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_semaphore();
//!Increments the semaphore count. If there are processes/threads blocked waiting
//!for the semaphore, then one of these processes will return successfully from
//!its wait function. If there is an error an interprocess_exception exception is thrown.
void post();
//!Decrements the semaphore. If the semaphore value is not greater than zero,
//!then the calling process/thread blocks until it can decrement the counter.
//!If there is an error an interprocess_exception exception is thrown.
void wait();
//!Decrements the semaphore if the semaphore's value is greater than zero
//!and returns true. If the value is not greater than zero returns false.
//!If there is an error an interprocess_exception exception is thrown.
bool try_wait();
//!Decrements the semaphore if the semaphore's value is greater
//!than zero and returns true. Otherwise, waits for the semaphore
//!to the posted or the timeout expires. If the timeout expires, the
//!function returns false. If the semaphore is posted the function
//!returns true. If there is an error throws sem_exception
bool timed_wait(const boost::posix_time::ptime &abs_time);
//!Erases a named semaphore from the system.
//!Returns false on error. Never throws.
static bool remove(const char *name);
/// @cond
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction();
#if defined(BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES)
ipcdetail::named_semaphore_wrapper m_sem;
#else
interprocess_semaphore *semaphore() const
{ return static_cast<interprocess_semaphore*>(m_shmem.get_user_address()); }
ipcdetail::managed_open_or_create_impl<shared_memory_object> m_shmem;
typedef ipcdetail::named_creation_functor<interprocess_semaphore, int> construct_func_t;
#endif
/// @endcond
};
/// @cond
#if defined(BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES)
inline named_semaphore::named_semaphore
(create_only_t, const char *name, unsigned int initialCount, const permissions &perm)
: m_sem(ipcdetail::DoCreate, name, initialCount, perm)
{}
inline named_semaphore::named_semaphore
(open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm)
: m_sem(ipcdetail::DoOpenOrCreate, name, initialCount, perm)
{}
inline named_semaphore::named_semaphore(open_only_t, const char *name)
: m_sem(ipcdetail::DoOpen, name, 1, permissions())
{}
inline named_semaphore::~named_semaphore()
{}
inline void named_semaphore::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_sem); }
inline void named_semaphore::wait()
{ m_sem.wait(); }
inline void named_semaphore::post()
{ m_sem.post(); }
inline bool named_semaphore::try_wait()
{ return m_sem.try_wait(); }
inline bool named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->wait();
return true;
}
return m_sem.timed_wait(abs_time);
}
inline bool named_semaphore::remove(const char *name)
{ return ipcdetail::named_semaphore_wrapper::remove(name); }
#else
inline named_semaphore::~named_semaphore()
{}
inline void named_semaphore::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); }
inline named_semaphore::named_semaphore
(create_only_t, const char *name, unsigned int initialCount, const permissions &perm)
: m_shmem (create_only
,name
,sizeof(interprocess_semaphore) +
ipcdetail::managed_open_or_create_impl<shared_memory_object>::
ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoCreate, initialCount)
,perm)
{}
inline named_semaphore::named_semaphore
(open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm)
: m_shmem (open_or_create
,name
,sizeof(interprocess_semaphore) +
ipcdetail::managed_open_or_create_impl<shared_memory_object>::
ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoOpenOrCreate, initialCount)
,perm)
{}
inline named_semaphore::named_semaphore
(open_only_t, const char *name)
: m_shmem (open_only
,name
,read_write
,0
,construct_func_t(ipcdetail::DoOpen, 0))
{}
inline void named_semaphore::post()
{ semaphore()->post(); }
inline void named_semaphore::wait()
{ semaphore()->wait(); }
inline bool named_semaphore::try_wait()
{ return semaphore()->try_wait(); }
inline bool named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->wait();
return true;
}
return semaphore()->timed_wait(abs_time);
}
inline bool named_semaphore::remove(const char *name)
{ return shared_memory_object::remove(name); }
#endif
/// @endcond
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NAMED_SEMAPHORE_HPP

View File

@@ -0,0 +1,372 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_upgradable_mutex_HPP
#define BOOST_INTERPROCESS_named_upgradable_mutex_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/emulation/named_creation_functor.hpp>
#include <boost/interprocess/permissions.hpp>
//!\file
//!Describes a named upgradable mutex class for inter-process synchronization
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail{ class interprocess_tester; }
/// @endcond
class named_condition;
//!A upgradable 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 upgradable mutex.
class named_upgradable_mutex
{
/// @cond
//Non-copyable
named_upgradable_mutex();
named_upgradable_mutex(const named_upgradable_mutex &);
named_upgradable_mutex &operator=(const named_upgradable_mutex &);
friend class named_condition;
/// @endcond
public:
//!Creates a global upgradable mutex with a name.
//!If the upgradable mutex can't be created throws interprocess_exception
named_upgradable_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions());
//!Opens or creates a global upgradable mutex with a name, and an initial count.
//!If the upgradable mutex is created, this call is equivalent to
//!named_upgradable_mutex(create_only_t, ...)
//!If the upgradable mutex is already created, this call is equivalent to
//!named_upgradable_mutex(open_only_t, ... ).
named_upgradable_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions());
//!Opens a global upgradable mutex with a name if that upgradable mutex
//!is previously.
//!created. If it is not previously created this function throws
//!interprocess_exception.
named_upgradable_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_upgradable_mutex();
//Exclusive locking
//!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
//! and if another thread has exclusive, sharable or upgradable ownership of
//! the mutex, it waits until it can obtain the ownership.
//!Throws: interprocess_exception on error.
void lock();
//!Effects: The calling thread tries to acquire exclusive ownership of the mutex
//! without waiting. If no other thread has exclusive, sharable or upgradable
//! ownership of the mutex this succeeds.
//!Returns: If it can acquire exclusive ownership immediately returns true.
//! If it has to wait, returns false.
//!Throws: interprocess_exception on error.
bool try_lock();
//!Effects: The calling thread tries to acquire exclusive ownership of the mutex
//! waiting if necessary until no other thread has has exclusive, sharable or
//! upgradable ownership of the mutex or abs_time is reached.
//!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
//!Throws: interprocess_exception on error.
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Precondition: The thread must have exclusive ownership of the mutex.
//!Effects: The calling thread releases the exclusive ownership of the mutex.
//!Throws: An exception derived from interprocess_exception on error.
void unlock();
//Sharable locking
//!Effects: The calling thread tries to obtain sharable ownership of the mutex,
//! and if another thread has exclusive or upgradable ownership of the mutex,
//! waits until it can obtain the ownership.
//!Throws: interprocess_exception on error.
void lock_sharable();
//!Effects: The calling thread tries to acquire sharable ownership of the mutex
//! without waiting. If no other thread has has exclusive or upgradable ownership
//! of the mutex this succeeds.
//!Returns: If it can acquire sharable ownership immediately returns true. If it
//! has to wait, returns false.
//!Throws: interprocess_exception on error.
bool try_lock_sharable();
//!Effects: The calling thread tries to acquire sharable ownership of the mutex
//! waiting if necessary until no other thread has has exclusive or upgradable
//! ownership of the mutex or abs_time is reached.
//!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
//!Throws: interprocess_exception on error.
bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
//!Precondition: The thread must have sharable ownership of the mutex.
//!Effects: The calling thread releases the sharable ownership of the mutex.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_sharable();
//Upgradable locking
//!Effects: The calling thread tries to obtain upgradable ownership of the mutex,
//! and if another thread has exclusive or upgradable ownership of the mutex,
//! waits until it can obtain the ownership.
//!Throws: interprocess_exception on error.
void lock_upgradable();
//!Effects: The calling thread tries to acquire upgradable ownership of the mutex
//! without waiting. If no other thread has has exclusive or upgradable ownership
//! of the mutex this succeeds.
//!Returns: If it can acquire upgradable ownership immediately returns true.
//! If it has to wait, returns false.
//!Throws: interprocess_exception on error.
bool try_lock_upgradable();
//!Effects: The calling thread tries to acquire upgradable ownership of the mutex
//! waiting if necessary until no other thread has has exclusive or upgradable
//! ownership of the mutex or abs_time is reached.
//!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
//!Throws: interprocess_exception on error.
bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time);
//!Precondition: The thread must have upgradable ownership of the mutex.
//!Effects: The calling thread releases the upgradable ownership of the mutex.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_upgradable();
//Demotions
//!Precondition: The thread must have exclusive ownership of the mutex.
//!Effects: The thread atomically releases exclusive ownership and acquires
//! upgradable ownership. This operation is non-blocking.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_and_lock_upgradable();
//!Precondition: The thread must have exclusive ownership of the mutex.
//!Effects: The thread atomically releases exclusive ownership and acquires
//! sharable ownership. This operation is non-blocking.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_and_lock_sharable();
//!Precondition: The thread must have upgradable ownership of the mutex.
//!Effects: The thread atomically releases upgradable ownership and acquires
//! sharable ownership. This operation is non-blocking.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_upgradable_and_lock_sharable();
//Promotions
//!Precondition: The thread must have upgradable ownership of the mutex.
//!Effects: The thread atomically releases upgradable ownership and acquires
//! exclusive ownership. This operation will block until all threads with
//! sharable ownership release it.
//!Throws: An exception derived from interprocess_exception on error.
void unlock_upgradable_and_lock();
//!Precondition: The thread must have upgradable ownership of the mutex.
//!Effects: The thread atomically releases upgradable ownership and tries to
//! acquire exclusive ownership. This operation will fail if there are threads
//! with sharable ownership, but it will maintain upgradable ownership.
//!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
//!Throws: An exception derived from interprocess_exception on error.
bool try_unlock_upgradable_and_lock();
//!Precondition: The thread must have upgradable ownership of the mutex.
//!Effects: The thread atomically releases upgradable ownership and tries to acquire
//! exclusive ownership, waiting if necessary until abs_time. This operation will
//! fail if there are threads with sharable ownership or timeout reaches, but it
//! will maintain upgradable ownership.
//!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
//!Throws: An exception derived from interprocess_exception on error.
bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time);
//!Precondition: The thread must have sharable ownership of the mutex.
//!Effects: The thread atomically releases sharable ownership and tries to acquire
//! exclusive ownership. This operation will fail if there are threads with sharable
//! or upgradable ownership, but it will maintain sharable ownership.
//!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
//!Throws: An exception derived from interprocess_exception on error.
bool try_unlock_sharable_and_lock();
bool try_unlock_sharable_and_lock_upgradable();
//!Erases a named upgradable mutex from the system.
//!Returns false on error. Never throws.
static bool remove(const char *name);
/// @cond
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction();
interprocess_upgradable_mutex *mutex() const
{ return static_cast<interprocess_upgradable_mutex*>(m_shmem.get_user_address()); }
ipcdetail::managed_open_or_create_impl<shared_memory_object> m_shmem;
typedef ipcdetail::named_creation_functor<interprocess_upgradable_mutex> construct_func_t;
/// @endcond
};
/// @cond
inline named_upgradable_mutex::~named_upgradable_mutex()
{}
inline named_upgradable_mutex::named_upgradable_mutex
(create_only_t, const char *name, const permissions &perm)
: m_shmem (create_only
,name
,sizeof(interprocess_upgradable_mutex) +
ipcdetail::managed_open_or_create_impl<shared_memory_object>::
ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoCreate)
,perm)
{}
inline named_upgradable_mutex::named_upgradable_mutex
(open_or_create_t, const char *name, const permissions &perm)
: m_shmem (open_or_create
,name
,sizeof(interprocess_upgradable_mutex) +
ipcdetail::managed_open_or_create_impl<shared_memory_object>::
ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoOpenOrCreate)
,perm)
{}
inline named_upgradable_mutex::named_upgradable_mutex
(open_only_t, const char *name)
: m_shmem (open_only
,name
,read_write
,0
,construct_func_t(ipcdetail::DoOpen))
{}
inline void named_upgradable_mutex::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); }
inline void named_upgradable_mutex::lock()
{ this->mutex()->lock(); }
inline void named_upgradable_mutex::unlock()
{ this->mutex()->unlock(); }
inline bool named_upgradable_mutex::try_lock()
{ return this->mutex()->try_lock(); }
inline bool named_upgradable_mutex::timed_lock
(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
return this->mutex()->timed_lock(abs_time);
}
inline void named_upgradable_mutex::lock_upgradable()
{ this->mutex()->lock_upgradable(); }
inline void named_upgradable_mutex::unlock_upgradable()
{ this->mutex()->unlock_upgradable(); }
inline bool named_upgradable_mutex::try_lock_upgradable()
{ return this->mutex()->try_lock_upgradable(); }
inline bool named_upgradable_mutex::timed_lock_upgradable
(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock_upgradable();
return true;
}
return this->mutex()->timed_lock_upgradable(abs_time);
}
inline void named_upgradable_mutex::lock_sharable()
{ this->mutex()->lock_sharable(); }
inline void named_upgradable_mutex::unlock_sharable()
{ this->mutex()->unlock_sharable(); }
inline bool named_upgradable_mutex::try_lock_sharable()
{ return this->mutex()->try_lock_sharable(); }
inline bool named_upgradable_mutex::timed_lock_sharable
(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock_sharable();
return true;
}
return this->mutex()->timed_lock_sharable(abs_time);
}
inline void named_upgradable_mutex::unlock_and_lock_upgradable()
{ this->mutex()->unlock_and_lock_upgradable(); }
inline void named_upgradable_mutex::unlock_and_lock_sharable()
{ this->mutex()->unlock_and_lock_sharable(); }
inline void named_upgradable_mutex::unlock_upgradable_and_lock_sharable()
{ this->mutex()->unlock_upgradable_and_lock_sharable(); }
inline void named_upgradable_mutex::unlock_upgradable_and_lock()
{ this->mutex()->unlock_upgradable_and_lock(); }
inline bool named_upgradable_mutex::try_unlock_upgradable_and_lock()
{ return this->mutex()->try_unlock_upgradable_and_lock(); }
inline bool named_upgradable_mutex::timed_unlock_upgradable_and_lock
(const boost::posix_time::ptime &abs_time)
{ return this->mutex()->timed_unlock_upgradable_and_lock(abs_time); }
inline bool named_upgradable_mutex::try_unlock_sharable_and_lock()
{ return this->mutex()->try_unlock_sharable_and_lock(); }
inline bool named_upgradable_mutex::try_unlock_sharable_and_lock_upgradable()
{ return this->mutex()->try_unlock_sharable_and_lock_upgradable(); }
inline bool named_upgradable_mutex::remove(const char *name)
{ return shared_memory_object::remove(name); }
/// @endcond
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_named_upgradable_mutex_HPP

View File

@@ -0,0 +1,147 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_NULL_MUTEX_HPP
#define BOOST_INTERPROCESS_NULL_MUTEX_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
//!\file
//!Describes null_mutex classes
namespace boost {
namespace posix_time
{ class ptime; }
namespace interprocess {
//!Implements a mutex that simulates a mutex without doing any operation and
//!simulates a successful operation.
class null_mutex
{
/// @cond
null_mutex(const null_mutex&);
null_mutex &operator= (const null_mutex&);
/// @endcond
public:
//!Constructor.
//!Empty.
null_mutex(){}
//!Destructor.
//!Empty.
~null_mutex(){}
//!Simulates a mutex lock() operation. Empty function.
void lock(){}
//!Simulates a mutex try_lock() operation.
//!Equivalent to "return true;"
bool try_lock()
{ return true; }
//!Simulates a mutex timed_lock() operation.
//!Equivalent to "return true;"
bool timed_lock(const boost::posix_time::ptime &)
{ return true; }
//!Simulates a mutex unlock() operation.
//!Empty function.
void unlock(){}
//!Simulates a mutex lock_sharable() operation.
//!Empty function.
void lock_sharable(){}
//!Simulates a mutex try_lock_sharable() operation.
//!Equivalent to "return true;"
bool try_lock_sharable()
{ return true; }
//!Simulates a mutex timed_lock_sharable() operation.
//!Equivalent to "return true;"
bool timed_lock_sharable(const boost::posix_time::ptime &)
{ return true; }
//!Simulates a mutex unlock_sharable() operation.
//!Empty function.
void unlock_sharable(){}
//!Simulates a mutex lock_upgradable() operation.
//!Empty function.
void lock_upgradable(){}
//!Simulates a mutex try_lock_upgradable() operation.
//!Equivalent to "return true;"
bool try_lock_upgradable()
{ return true; }
//!Simulates a mutex timed_lock_upgradable() operation.
//!Equivalent to "return true;"
bool timed_lock_upgradable(const boost::posix_time::ptime &)
{ return true; }
//!Simulates a mutex unlock_upgradable() operation.
//!Empty function.
void unlock_upgradable(){}
//!Simulates unlock_and_lock_upgradable().
//!Empty function.
void unlock_and_lock_upgradable(){}
//!Simulates unlock_and_lock_sharable().
//!Empty function.
void unlock_and_lock_sharable(){}
//!Simulates unlock_upgradable_and_lock_sharable().
//!Empty function.
void unlock_upgradable_and_lock_sharable(){}
//Promotions
//!Simulates unlock_upgradable_and_lock().
//!Empty function.
void unlock_upgradable_and_lock(){}
//!Simulates try_unlock_upgradable_and_lock().
//!Equivalent to "return true;"
bool try_unlock_upgradable_and_lock()
{ return true; }
//!Simulates timed_unlock_upgradable_and_lock().
//!Equivalent to "return true;"
bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &)
{ return true; }
//!Simulates try_unlock_sharable_and_lock().
//!Equivalent to "return true;"
bool try_unlock_sharable_and_lock()
{ return true; }
//!Simulates try_unlock_sharable_and_lock_upgradable().
//!Equivalent to "return true;"
bool try_unlock_sharable_and_lock_upgradable()
{ return true; }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NULL_MUTEX_HPP

View File

@@ -0,0 +1,45 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
#include<boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
inline barrier::barrier(unsigned int count)
{
if (count == 0)
throw std::invalid_argument("count cannot be zero.");
ipcdetail::barrierattr_wrapper barrier_attr;
ipcdetail::barrier_initializer barrier
(m_barrier, barrier_attr, static_cast<int>(count));
barrier.release();
}
inline barrier::~barrier()
{
int res = pthread_barrier_destroy(&m_barrier);
BOOST_ASSERT(res == 0);(void)res;
}
inline bool barrier::wait()
{
int res = pthread_barrier_wait(&m_barrier);
if (res != PTHREAD_BARRIER_SERIAL_THREAD && res != 0){
throw interprocess_exception(res);
}
return res == PTHREAD_BARRIER_SERIAL_THREAD;
}
} //namespace interprocess {
} //namespace boost {

View File

@@ -0,0 +1,82 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
inline interprocess_condition::interprocess_condition()
{
int res;
pthread_condattr_t cond_attr;
res = pthread_condattr_init(&cond_attr);
if(res != 0){
throw interprocess_exception("pthread_condattr_init failed");
}
res = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
if(res != 0){
pthread_condattr_destroy(&cond_attr);
throw interprocess_exception(res);
}
res = pthread_cond_init(&m_condition, &cond_attr);
pthread_condattr_destroy(&cond_attr);
if(res != 0){
throw interprocess_exception(res);
}
}
inline interprocess_condition::~interprocess_condition()
{
int res = 0;
res = pthread_cond_destroy(&m_condition);
BOOST_ASSERT(res == 0);
}
inline void interprocess_condition::notify_one()
{
int res = 0;
res = pthread_cond_signal(&m_condition);
BOOST_ASSERT(res == 0);
}
inline void interprocess_condition::notify_all()
{
int res = 0;
res = pthread_cond_broadcast(&m_condition);
BOOST_ASSERT(res == 0);
}
inline void interprocess_condition::do_wait(interprocess_mutex &mut)
{
pthread_mutex_t* pmutex = &mut.m_mut;
int res = 0;
res = pthread_cond_wait(&m_condition, pmutex);
BOOST_ASSERT(res == 0);
}
inline bool interprocess_condition::do_timed_wait
(const boost::posix_time::ptime &abs_time, interprocess_mutex &mut)
{
timespec ts = ipcdetail::ptime_to_timespec(abs_time);
pthread_mutex_t* pmutex = &mut.m_mut;
int res = 0;
res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
BOOST_ASSERT(res == 0 || res == ETIMEDOUT);
return res != ETIMEDOUT;
}
} //namespace interprocess
} // namespace boost

View File

@@ -0,0 +1,122 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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.
//////////////////////////////////////////////////////////////////////////////
#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>
#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
# include <boost/interprocess/detail/os_thread_functions.hpp>
#endif
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
inline interprocess_mutex::interprocess_mutex()
{
ipcdetail::mutexattr_wrapper mut_attr;
ipcdetail::mutex_initializer mut(m_mut, mut_attr);
mut.release();
}
inline interprocess_mutex::~interprocess_mutex()
{
int res = pthread_mutex_destroy(&m_mut);
BOOST_ASSERT(res == 0);(void)res;
}
inline void interprocess_mutex::lock()
{
#ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING
boost::posix_time::ptime wait_time
= boost::posix_time::microsec_clock::universal_time()
+ boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS);
if (!timed_lock(wait_time))
{
throw interprocess_exception(timeout_when_locking_error, "Interprocess mutex timeout when locking. Possible deadlock: owner died without unlocking?");
}
#else
if (pthread_mutex_lock(&m_mut) != 0)
throw lock_exception();
#endif
}
inline bool interprocess_mutex::try_lock()
{
int res = pthread_mutex_trylock(&m_mut);
if (!(res == 0 || res == EBUSY))
throw lock_exception();
return res == 0;
}
inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
timespec ts = ipcdetail::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
//Obtain current count and target time
boost::posix_time::ptime now = microsec_clock::universal_time();
if(now >= abs_time) return false;
do{
if(this->try_lock()){
break;
}
now = microsec_clock::universal_time();
if(now >= abs_time){
return false;
}
// relinquish current time slice
ipcdetail::thread_yield();
}while (true);
return true;
#endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS
}
inline void interprocess_mutex::unlock()
{
int res = 0;
res = pthread_mutex_unlock(&m_mut);
BOOST_ASSERT(res == 0);
}
} //namespace interprocess {
} //namespace boost {

View File

@@ -0,0 +1,122 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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.
//////////////////////////////////////////////////////////////////////////////
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/exceptions.hpp>
#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
# include <boost/interprocess/detail/os_thread_functions.hpp>
#endif
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
inline interprocess_recursive_mutex::interprocess_recursive_mutex()
{
ipcdetail::mutexattr_wrapper mut_attr(true);
ipcdetail::mutex_initializer mut(m_mut, mut_attr);
mut.release();
}
inline interprocess_recursive_mutex::~interprocess_recursive_mutex()
{
int res = pthread_mutex_destroy(&m_mut);
BOOST_ASSERT(res == 0);(void)res;
}
inline void interprocess_recursive_mutex::lock()
{
#ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING
boost::posix_time::ptime wait_time
= boost::posix_time::microsec_clock::universal_time()
+ boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS);
if (!timed_lock(wait_time))
{
throw interprocess_exception(timeout_when_locking_error, "Interprocess mutex timeout when locking. Possible deadlock: owner died without unlocking?");
}
#else
if (pthread_mutex_lock(&m_mut) != 0)
throw lock_exception();
#endif
}
inline bool interprocess_recursive_mutex::try_lock()
{
int res = pthread_mutex_trylock(&m_mut);
if (!(res == 0 || res == EBUSY))
throw lock_exception();
return res == 0;
}
inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
timespec ts = ipcdetail::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
//Obtain current count and target time
boost::posix_time::ptime now = microsec_clock::universal_time();
if(now >= abs_time) return false;
do{
if(this->try_lock()){
break;
}
now = microsec_clock::universal_time();
if(now >= abs_time){
return false;
}
// relinquish current time slice
ipcdetail::thread_yield();
}while (true);
return true;
#endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS
}
inline void interprocess_recursive_mutex::unlock()
{
int res = 0;
res = pthread_mutex_unlock(&m_mut);
BOOST_ASSERT(res == 0);
}
} //namespace interprocess {
} //namespace boost {

View File

@@ -0,0 +1,49 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
namespace boost {
namespace interprocess {
inline interprocess_semaphore::~interprocess_semaphore()
{}
inline interprocess_semaphore::interprocess_semaphore(unsigned int initialCount)
: m_sem(initialCount)
{}
inline void interprocess_semaphore::post()
{ m_sem.post(); }
inline void interprocess_semaphore::wait()
{ m_sem.wait(); }
inline bool interprocess_semaphore::try_wait()
{ return m_sem.try_wait(); }
inline bool interprocess_semaphore::timed_wait(const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->wait();
return true;
}
return m_sem.timed_wait(abs_time);
}
/*
inline int interprocess_semaphore::get_count() const
{ return m_sem.get_count(); }
*/
} //namespace interprocess {
} //namespace boost {

View File

@@ -0,0 +1,168 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# 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

View File

@@ -0,0 +1,38 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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
#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));
boost::posix_time::time_duration 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

View File

@@ -0,0 +1,265 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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
#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/tmp_dir_helpers.hpp>
#include <boost/interprocess/permissions.hpp>
#include <string>
#include <semaphore.h>
#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>
#endif
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail{ class interprocess_tester; }
/// @endcond
namespace ipcdetail {
inline bool semaphore_open
(sem_t *&handle, ipcdetail::create_enum_t type, const char *origname,
unsigned int count, const permissions &perm = permissions())
{
std::string name;
#ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
ipcdetail::add_leading_slash(origname, name);
#else
ipcdetail::create_tmp_and_clean_old_and_get_filename(origname, name);
#endif
//Create new mapping
int oflag = 0;
switch(type){
case ipcdetail::DoOpen:
//No addition
break;
case ipcdetail::DoCreate:
oflag |= (O_CREAT | O_EXCL);
break;
case ipcdetail::DoOpenOrCreate:
oflag |= O_CREAT;
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Open file using POSIX API
if(oflag & O_CREAT)
handle = sem_open(name.c_str(), oflag, perm.get_permissions(), count);
else
handle = sem_open(name.c_str(), oflag);
//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
ipcdetail::add_leading_slash(semname, sem_str);
#else
ipcdetail::tmp_filename(semname, sem_str);
#endif
return 0 == sem_unlink(sem_str.c_str());
}
catch(...){
return false;
}
}
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){
throw interprocess_exception(system_error_code());
}
}
inline void semaphore_destroy(sem_t *handle)
{
int ret = sem_destroy(handle);
if(ret != 0){
BOOST_ASSERT(0);
}
}
inline void semaphore_post(sem_t *handle)
{
int ret = sem_post(handle);
if(ret != 0){
throw interprocess_exception(system_error_code());
}
}
inline void semaphore_wait(sem_t *handle)
{
int ret = sem_wait(handle);
if(ret != 0){
throw interprocess_exception(system_error_code());
}
}
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;
}
throw interprocess_exception(system_error_code());
return false;
}
inline bool semaphore_timed_wait(sem_t *handle, const boost::posix_time::ptime &abs_time)
{
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
timespec tspec = ipcdetail::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;
}
throw interprocess_exception(system_error_code());
}
return false;
#else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
boost::posix_time::ptime now;
while((now = microsec_clock::universal_time()) < abs_time){
if(semaphore_try_wait(handle))
return true;
thread_yield();
}
return false;
#endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
}
class named_semaphore_wrapper
{
named_semaphore_wrapper();
named_semaphore_wrapper(const named_semaphore_wrapper&);
named_semaphore_wrapper &operator= (const named_semaphore_wrapper &);
public:
named_semaphore_wrapper
(ipcdetail::create_enum_t type, const char *name, unsigned int count, const permissions &perm = permissions())
{ semaphore_open(mp_sem, type, name, count, perm); }
~named_semaphore_wrapper()
{
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;
};
class semaphore_wrapper
{
semaphore_wrapper();
semaphore_wrapper(const semaphore_wrapper&);
semaphore_wrapper &operator= (const semaphore_wrapper &);
public:
semaphore_wrapper(unsigned int initialCount)
{ semaphore_init(&m_sem, initialCount); }
~semaphore_wrapper()
{ semaphore_destroy(&m_sem); }
void post()
{ semaphore_post(&m_sem); }
void wait()
{ semaphore_wait(&m_sem); }
bool try_wait()
{ return semaphore_try_wait(&m_sem); }
bool timed_wait(const boost::posix_time::ptime &abs_time)
{ return semaphore_timed_wait(&m_sem, abs_time); }
private:
sem_t m_sem;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#undef BOOST_INTERPROCESS_POSIX_SEM_FAILED
#endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP

View File

@@ -0,0 +1,372 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/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/interprocess/detail/move.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.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
{
/// @cond
private:
typedef scoped_lock<Mutex> this_type;
BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_lock)
typedef bool this_type::*unspecified_bool_type;
/// @endcond
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::interprocess::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::interprocess::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)
{
std::swap(mp_mutex, other.mp_mutex);
std::swap(m_locked, other.m_locked);
}
/// @cond
private:
mutex_type *mp_mutex;
bool m_locked;
/// @endcond
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_SCOPED_LOCK_HPP

View File

@@ -0,0 +1,305 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_SHARABLE_LOCK_HPP
#define BOOST_INTERPROCESS_SHARABLE_LOCK_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/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/interprocess/detail/move.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
//!\file
//!Describes the upgradable_lock class that serves to acquire the upgradable
//!lock of a mutex.
namespace boost {
namespace interprocess {
//!sharable_lock is meant to carry out the tasks for sharable-locking
//!(such as read-locking), unlocking, try-sharable-locking and timed-sharable-locking
//!(recursive or not) for the Mutex. The Mutex need not supply all of this
//!functionality. If the client of sharable_lock<Mutex> does not use functionality which
//!the Mutex does not supply, no harm is done. Mutex ownership can be shared among
//!sharable_locks, and a single upgradable_lock. sharable_lock does not support
//!copy semantics. But sharable_lock supports ownership transfer from an sharable_lock,
//!upgradable_lock and scoped_lock via transfer_lock syntax.*/
template <class SharableMutex>
class sharable_lock
{
public:
typedef SharableMutex mutex_type;
/// @cond
private:
typedef sharable_lock<SharableMutex> this_type;
explicit sharable_lock(scoped_lock<mutex_type>&);
typedef bool this_type::*unspecified_bool_type;
BOOST_MOVABLE_BUT_NOT_COPYABLE(sharable_lock)
/// @endcond
public:
//!Effects: Default constructs a sharable_lock.
//!Postconditions: owns() == false and mutex() == 0.
sharable_lock()
: mp_mutex(0), m_locked(false)
{}
//!Effects: m.lock_sharable().
//!Postconditions: owns() == true and mutex() == &m.
//!Notes: The constructor will take sharable-ownership of the mutex. If
//! another thread already owns the mutex with exclusive ownership
//! (scoped_lock), this thread will block until the mutex is released.
//! If another thread owns the mutex with sharable or upgradable ownership,
//! then no blocking will occur. Whether or not this constructor handles
//! recursive locking depends upon the mutex.
explicit sharable_lock(mutex_type& m)
: mp_mutex(&m), m_locked(false)
{ mp_mutex->lock_sharable(); 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.
sharable_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 sharable
//! locked. There is no effect required on the referenced mutex.
sharable_lock(mutex_type& m, accept_ownership_type)
: mp_mutex(&m), m_locked(true)
{}
//!Effects: m.try_lock_sharable()
//!Postconditions: mutex() == &m. owns() == the return value of the
//! m.try_lock_sharable() executed within the constructor.
//!Notes: The constructor will take sharable-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_sharable, this constructor will fail at compile
//! time if instantiated, but otherwise have no effect.
sharable_lock(mutex_type& m, try_to_lock_type)
: mp_mutex(&m), m_locked(false)
{ m_locked = mp_mutex->try_lock_sharable(); }
//!Effects: m.timed_lock_sharable(abs_time)
//!Postconditions: mutex() == &m. owns() == the return value of the
//! m.timed_lock_sharable() executed within the constructor.
//!Notes: The constructor will take sharable-ownership of the mutex if it
//! can do so within the time specified. Whether or not this constructor
//! handles recursive locking depends upon the mutex. If the mutex_type
//! does not support timed_lock_sharable, this constructor will fail at
//! compile time if instantiated, but otherwise have no effect.
sharable_lock(mutex_type& m, const boost::posix_time::ptime& abs_time)
: mp_mutex(&m), m_locked(false)
{ m_locked = mp_mutex->timed_lock_sharable(abs_time); }
//!Postconditions: mutex() == upgr.mutex(). owns() == the value of upgr.owns()
//! before the construction. upgr.owns() == false after the construction.
//!Notes: If the upgr sharable_lock owns the mutex, ownership is moved to this
//! sharable_lock with no blocking. If the upgr sharable_lock does not own the mutex, then
//! neither will this sharable_lock. Only a moved sharable_lock's will match this
//! signature. An non-moved sharable_lock can be moved with the expression:
//! "boost::interprocess::move(lock);". This constructor does not alter the state of the mutex,
//! only potentially who owns it.
sharable_lock(BOOST_RV_REF(sharable_lock<mutex_type>) upgr)
: mp_mutex(0), m_locked(upgr.owns())
{ mp_mutex = upgr.release(); }
//!Effects: If upgr.owns() then calls unlock_upgradable_and_lock_sharable() on the
//! referenced mutex.
//!Postconditions: mutex() == the value upgr.mutex() had before the construction.
//! upgr.mutex() == 0 owns() == the value of upgr.owns() before construction.
//! upgr.owns() == false after the construction.
//!Notes: If upgr is locked, this constructor will lock this sharable_lock while
//! unlocking upgr. Only a moved sharable_lock's will match this
//! signature. An non-moved upgradable_lock can be moved with the expression:
//! "boost::interprocess::move(lock);".*/
template<class T>
sharable_lock(BOOST_RV_REF(upgradable_lock<T>) upgr
, typename ipcdetail::enable_if< ipcdetail::is_same<T, SharableMutex> >::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_sharable();
m_locked = true;
}
mp_mutex = u_lock.release();
}
//!Effects: If scop.owns() then calls unlock_and_lock_sharable() on the
//! referenced mutex.
//!Postconditions: mutex() == the value scop.mutex() had before the construction.
//! scop.mutex() == 0 owns() == scop.owns() before the constructor. After the
//! construction, scop.owns() == false.
//!Notes: If scop is locked, this constructor will transfer the exclusive ownership
//! to a sharable-ownership of this sharable_lock.
//! Only a moved scoped_lock's will match this
//! signature. An non-moved scoped_lock can be moved with the expression:
//! "boost::interprocess::move(lock);".
template<class T>
sharable_lock(BOOST_RV_REF(scoped_lock<T>) scop
, typename ipcdetail::enable_if< ipcdetail::is_same<T, SharableMutex> >::type * = 0)
: mp_mutex(0), m_locked(false)
{
scoped_lock<mutex_type> &e_lock = scop;
if(e_lock.owns()){
e_lock.mutex()->unlock_and_lock_sharable();
m_locked = true;
}
mp_mutex = e_lock.release();
}
//!Effects: if (owns()) mp_mutex->unlock_sharable().
//!Notes: The destructor behavior ensures that the mutex lock is not leaked.
~sharable_lock()
{
try{
if(m_locked && mp_mutex) mp_mutex->unlock_sharable();
}
catch(...){}
}
//!Effects: If owns() before the call, then unlock_sharable() is called on mutex().
//! *this gets the state of upgr and upgr gets set to a default constructed state.
//!Notes: With a recursive mutex it is possible that both this and upgr own the mutex
//! before the assignment. In this case, this will own the mutex after the assignment
//! (and upgr will not), but the mutex's lock count will be decremented by one.
sharable_lock &operator=(BOOST_RV_REF(sharable_lock<mutex_type>) upgr)
{
if(this->owns())
this->unlock();
m_locked = upgr.owns();
mp_mutex = upgr.release();
return *this;
}
//!Effects: If mutex() == 0 or already locked, throws a lock_exception()
//! exception. Calls lock_sharable() on the referenced mutex.
//!Postconditions: owns() == true.
//!Notes: The sharable_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_sharable();
m_locked = true;
}
//!Effects: If mutex() == 0 or already locked, throws a lock_exception()
//! exception. Calls try_lock_sharable() on the referenced mutex.
//!Postconditions: owns() == the value returned from
//! mutex()->try_lock_sharable().
//!Notes: The sharable_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_sharable(), 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_sharable();
return m_locked;
}
//!Effects: If mutex() == 0 or already locked, throws a lock_exception()
//! exception. Calls timed_lock_sharable(abs_time) on the referenced mutex.
//!Postconditions: owns() == the value returned from
//! mutex()->timed_lock_sharable(elps_time).
//!Notes: The sharable_lock changes from a state of not owning the mutex,
//! to owning the mutex, but only if it can obtain ownership within the
//! specified time interval. If the mutex_type does not support
//! timed_lock_sharable(), 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_sharable(abs_time);
return m_locked;
}
//!Effects: If mutex() == 0 or not locked, throws a lock_exception() exception.
//! Calls unlock_sharable() on the referenced mutex.
//!Postconditions: owns() == false.
//!Notes: The sharable_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_sharable();
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(sharable_lock<mutex_type> &other)
{
std::swap(mp_mutex, other.mp_mutex);
std::swap(m_locked, other.m_locked);
}
/// @cond
private:
mutex_type *mp_mutex;
bool m_locked;
/// @endcond
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_SHARABLE_LOCK_HPP

View File

@@ -0,0 +1,309 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_UPGRADABLE_LOCK_HPP
#define BOOST_INTERPROCESS_UPGRADABLE_LOCK_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/sync/lock_options.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
//!\file
//!Describes the upgradable_lock class that serves to acquire the upgradable
//!lock of a mutex.
namespace boost {
namespace interprocess {
//!upgradable_lock is meant to carry out the tasks for read-locking, unlocking,
//!try-read-locking and timed-read-locking (recursive or not) for the Mutex.
//!Additionally the upgradable_lock can transfer ownership to a scoped_lock
//!using transfer_lock syntax. The Mutex need not supply all of the functionality.
//!If the client of upgradable_lock<Mutex> does not use functionality which the
//!Mutex does not supply, no harm is done. Mutex ownership can be shared among
//!read_locks, and a single upgradable_lock. upgradable_lock does not support
//!copy semantics. However upgradable_lock supports ownership transfer from
//!a upgradable_locks or scoped_locks via transfer_lock syntax.
template <class UpgradableMutex>
class upgradable_lock
{
public:
typedef UpgradableMutex mutex_type;
/// @cond
private:
typedef upgradable_lock<UpgradableMutex> this_type;
explicit upgradable_lock(scoped_lock<mutex_type>&);
typedef bool this_type::*unspecified_bool_type;
BOOST_MOVABLE_BUT_NOT_COPYABLE(upgradable_lock)
/// @endcond
public:
//!Effects: Default constructs a upgradable_lock.
//!Postconditions: owns() == false and mutex() == 0.
upgradable_lock()
: mp_mutex(0), m_locked(false)
{}
explicit upgradable_lock(mutex_type& m)
: mp_mutex(&m), m_locked(false)
{ mp_mutex->lock_upgradable(); 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.
upgradable_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 upgradable
//! locked. There is no effect required on the referenced mutex.
upgradable_lock(mutex_type& m, accept_ownership_type)
: mp_mutex(&m), m_locked(true)
{}
//!Effects: m.try_lock_upgradable().
//!Postconditions: mutex() == &m. owns() == the return value of the
//! m.try_lock_upgradable() executed within the constructor.
//!Notes: The constructor will take upgradable-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_upgradable, this constructor will fail at
//! compile time if instantiated, but otherwise have no effect.
upgradable_lock(mutex_type& m, try_to_lock_type)
: mp_mutex(&m), m_locked(false)
{ m_locked = mp_mutex->try_lock_upgradable(); }
//!Effects: m.timed_lock_upgradable(abs_time)
//!Postconditions: mutex() == &m. owns() == the return value of the
//! m.timed_lock_upgradable() executed within the constructor.
//!Notes: The constructor will take upgradable-ownership of the mutex if it
//! can do so within the time specified. Whether or not this constructor
//! handles recursive locking depends upon the mutex. If the mutex_type
//! does not support timed_lock_upgradable, this constructor will fail
//! at compile time if instantiated, but otherwise have no effect.
upgradable_lock(mutex_type& m, const boost::posix_time::ptime& abs_time)
: mp_mutex(&m), m_locked(false)
{ m_locked = mp_mutex->timed_lock_upgradable(abs_time); }
//!Effects: No effects on the underlying mutex.
//!Postconditions: mutex() == the value upgr.mutex() had before the
//! construction. upgr.mutex() == 0. owns() == upgr.owns() before the
//! construction. upgr.owns() == false.
//!Notes: If upgr is locked, this constructor will lock this upgradable_lock
//! while unlocking upgr. If upgr is unlocked, then this upgradable_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::interprocess::move(lock);". This constructor does not alter the
//! state of the mutex, only potentially who owns it.
upgradable_lock(BOOST_RV_REF(upgradable_lock<mutex_type>) upgr)
: mp_mutex(0), m_locked(upgr.owns())
{ mp_mutex = upgr.release(); }
//!Effects: If scop.owns(), m_.unlock_and_lock_upgradable().
//!Postconditions: mutex() == the value scop.mutex() had before the construction.
//! scop.mutex() == 0. owns() == scop.owns() before the constructor. After the
//! construction, scop.owns() == false.
//!Notes: If scop is locked, this constructor will transfer the exclusive-ownership
//! to an upgradable-ownership of this upgradable_lock.
//! Only a moved sharable_lock's will match this
//! signature. An non-moved sharable_lock can be moved with the
//! expression: "boost::interprocess::move(lock);".
template<class T>
upgradable_lock(BOOST_RV_REF(scoped_lock<T>) scop
, typename ipcdetail::enable_if< ipcdetail::is_same<T, UpgradableMutex> >::type * = 0)
: mp_mutex(0), m_locked(false)
{
scoped_lock<mutex_type> &u_lock = scop;
if(u_lock.owns()){
u_lock.mutex()->unlock_and_lock_upgradable();
m_locked = true;
}
mp_mutex = u_lock.release();
}
//!Effects: If shar.owns() then calls try_unlock_sharable_and_lock_upgradable()
//! on the referenced mutex.
//! a)if try_unlock_sharable_and_lock_upgradable() returns true then mutex()
//! obtains the value from shar.release() and owns() is set to true.
//! b)if try_unlock_sharable_and_lock_upgradable() returns false then shar is
//! unaffected and this upgradable_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 an "upgradable lock". If the "read lock" isn't held
//! in the first place, the mutex merely changes type to an unlocked
//! "upgradable 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>
upgradable_lock( BOOST_RV_REF(sharable_lock<T>) shar, try_to_lock_type
, typename ipcdetail::enable_if< ipcdetail::is_same<T, UpgradableMutex> >::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_upgradable()) == true){
mp_mutex = s_lock.release();
}
}
else{
s_lock.release();
}
}
//!Effects: if (owns()) m_->unlock_upgradable().
//!Notes: The destructor behavior ensures that the mutex lock is not leaked.
~upgradable_lock()
{
try{
if(m_locked && mp_mutex) mp_mutex->unlock_upgradable();
}
catch(...){}
}
//!Effects: If owns(), then unlock_upgradable() is called on mutex().
//! *this gets the state of upgr and upgr gets set to a default constructed state.
//!Notes: With a recursive mutex it is possible that both this and upgr own the
//! mutex before the assignment. In this case, this will own the mutex
//! after the assignment (and upgr will not), but the mutex's upgradable lock
//! count will be decremented by one.
upgradable_lock &operator=(BOOST_RV_REF(upgradable_lock) upgr)
{
if(this->owns())
this->unlock();
m_locked = upgr.owns();
mp_mutex = upgr.release();
return *this;
}
//!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
//! exception. Calls lock_upgradable() on the referenced mutex.
//!Postconditions: owns() == true.
//!Notes: The sharable_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_upgradable();
m_locked = true;
}
//!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
//! exception. Calls try_lock_upgradable() on the referenced mutex.
//!Postconditions: owns() == the value returned from
//! mutex()->try_lock_upgradable().
//!Notes: The upgradable_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_upgradable(), 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_upgradable();
return m_locked;
}
//!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
//! exception. Calls timed_lock_upgradable(abs_time) on the referenced mutex.
//!Postconditions: owns() == the value returned from
//! mutex()->timed_lock_upgradable(abs_time).
//!Notes: The upgradable_lock changes from a state of not owning the mutex,
//! to owning the mutex, but only if it can obtain ownership within the
//! specified time. If the mutex_type does not support
//! timed_lock_upgradable(abs_time), 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_upgradable(abs_time);
return m_locked;
}
//!Effects: If mutex() == 0 or if not locked, throws a lock_exception()
//! exception. Calls unlock_upgradable() on the referenced mutex.
//!Postconditions: owns() == false.
//!Notes: The upgradable_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_upgradable();
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(upgradable_lock<mutex_type> &other)
{
std::swap(mp_mutex, other.mp_mutex);
std::swap(m_locked, other.m_locked);
}
/// @cond
private:
mutex_type *mp_mutex;
bool m_locked;
/// @endcond
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_UPGRADABLE_LOCK_HPP

View File

@@ -0,0 +1,193 @@
/*
* Provide an simpler and easier to understand interface to the System V
* semaphore system calls. There are 7 routines available to the user:
*
* id = sem_create(key, initval); # create with initial value or open
* id = sem_open(key); # open (must already exist)
* sem_wait(id); # wait = P = down by 1
* sem_signal(id); # signal = V = up by 1
* sem_op(id, amount); # wait if (amount < 0)
* # signal if (amount > 0)
* sem_close(id); # close
* sem_rm(id); # remove (delete)
*
* We create and use a 3-member set for the requested semaphore.
* The first member, [0], is the actual semaphore value, and the second
* member, [1], is a counter used to know when all processes have finished
* with the semaphore. The counter is initialized to a large number,
* decremented on every create or open and incremented on every close.
* This way we can use the "adjust" feature provided by System V so that
* any process that exit's without calling sem_close() is accounted
* for. It doesn't help us if the last process does this (as we have
* no way of getting control to remove the semaphore) but it will
* work if any process other than the last does an exit (intentional
* or unintentional).
* The third member, [2], of the semaphore set is used as a lock variable
* to avoid any race conditions in the sem_create() and sem_close()
* functions.
*/
#ifndef BOOST_INTERPROCESS_SYNC_XSI_ADVANCED_XSI_SEMAPHORE_HPP
#define BOOST_INTERPROCESS_SYNC_XSI_ADVANCED_XSI_SEMAPHORE_HPP
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
namespace boost {
namespace interprocess {
namespace xsi {
// Create a semaphore with a specified initial value.
// If the semaphore already exists, we don't initialize it (of course).
// We return the semaphore ID if all OK, else -1.
inline bool advanced_sem_open_or_create(::key_t key, int initval, int &semid, int perm)
{
semid = -1;
int id, semval;
union semun {
int val;
::semid_ds *buf;
ushort *array;
} semctl_arg;
if (key == IPC_PRIVATE)
return false; //not intended for private semaphores
else if (key == (::key_t) -1)
return false; //probably an ftok() error by caller
again:
if ((id = ::semget(key, 3, (perm & 0x01FF) | IPC_CREAT)) < 0)
return false; //permission problem or tables full
// When the semaphore is created, we know that the value of all
// 3 members is 0.
// Get a lock on the semaphore by waiting for [2] to equal 0,
// then increment it.
//
// There is a race condition here. There is a possibility that
// between the semget() above and the ::semop() below, another
// process can call our sem_close() function which can remove
// the semaphore if that process is the last one using it.
// Therefore, we handle the error condition of an invalid
// semaphore ID specially below, and if it does happen, we just
// go back and create it again.
struct sembuf op_lock[2] = {
{2, 0, 0}, // wait for [2] (lock) to equal 0
{2, 1, SEM_UNDO} // then increment [2] to 1 - this locks it
// UNDO to release the lock if processes exits
// before explicitly unlocking
};
if (::semop(id, &op_lock[0], 2) < 0) {
if (errno == EINVAL)
goto again;
}
// Get the value of the process counter. If it equals 0,
// then no one has initialized the semaphore yet.
if ((semval = ::semctl(id, 1, GETVAL, 0)) < 0)
return false;
if (semval == 0) {
// We could initialize by doing a SETALL, but that
// would clear the adjust value that we set when we
// locked the semaphore above. Instead, we'll do 2
// system calls to initialize [0] and [1].
semctl_arg.val = initval;
if (::semctl(id, 0, SETVAL, semctl_arg) < 0)
return false;
semctl_arg.val = 1;
if (::semctl(id, 1, SETVAL, semctl_arg) < 0)
return false;
}
// Decrement the process counter and then release the lock.
struct sembuf op_unlock[1] = {
2, -1, 0/*SEM_UNDO*/ // decrement [2] (lock) back to 0
};
if (::semop(id, &op_unlock[0], 1) < 0)
return false;
semid = id;
return true;
}
// Open a semaphore that must already exist.
// This function should be used, instead of sem_create(), if the caller
// knows that the semaphore must already exist. For example a client
// from a client-server pair would use this, if its the server's
// responsibility to create the semaphore.
// We return the semaphore ID if all OK, else -1.
/*
inline bool advanced_sem_open(key_t key, int &semid)
{
semid = -1;
if (key == IPC_PRIVATE)
return false; // not intended for private semaphores
else if (key == (::key_t) -1)
return false; // probably an ftok() error by caller
if ((semid = ::semget(key, 3, 0)) < 0)
return false; // doesn't exist, or tables full
// Decrement the process counter. We don't need a lock
struct sembuf op_open[1] = {
1, -1, SEM_UNDO // decrement [1] (proc counter) with undo on exit
};
if (::semop(id, &op_open[0], 1) < 0)
return false;
return true;
}
*/
/****************************************************************************
* Remove a semaphore.
* This call is intended to be called by a server, for example,
* when it is being shut down, as we do an IPC_RMID on the semaphore,
* regardless whether other processes may be using it or not.
* Most other processes should use sem_close() below.
*/
inline bool advanced_sem_rm(int id)
{
if (::semctl(id, 0, IPC_RMID, 0) < 0)
return false;
return true;
}
/****************************************************************************
* General semaphore operation. Increment or decrement by a user-specified
* amount (positive or negative; amount can't be zero).
*/
inline bool advanced_sem_op(int id, int value, bool undo = true)
{
::sembuf op_op[1] = {
0, 99, 0 // decrement or increment [0] with undo on exit
// the 99 is set to the actual amount to add
// or subtract (positive or negative)
};
if(undo){
op_op[0].sem_flg = SEM_UNDO;
}
if ((op_op[0].sem_op = value) == 0)
return false;
if (::semop(id, &op_op[0], 1) < 0)
return false;
return true;
}
} //namespace xsi {
} //namespace interprocess {
} //namespace boost {
#endif //BOOST_INTERPROCESS_SYNC_XSI_ADVANCED_XSI_SEMAPHORE_HPP

View File

@@ -0,0 +1,116 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2011. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SYNC_XSI_SIMPLE_XSI_SEMAPHORE_HPP
#define BOOST_INTERPROCESS_SYNC_XSI_SIMPLE_XSI_SEMAPHORE_HPP
/*
* Provide an simpler and easier to understand interface to the System V
* semaphore system calls. There are 7 routines available to the user:
*
* id = sem_create(key, initval); # create with initial value or open
* id = sem_open(key); # open (must already exist)
* sem_wait(id); # wait = P = down by 1
* sem_signal(id); # signal = V = up by 1
* sem_op(id, amount); # wait if (amount < 0)
* # signal if (amount > 0)
* sem_close(id); # close
* sem_rm(id); # remove (delete)
*
* We create and use a 3-member set for the requested semaphore.
* The first member, [0], is the actual semaphore value, and the second
* member, [1], is a counter used to know when all processes have finished
* with the semaphore. The counter is initialized to a large number,
* decremented on every create or open and incremented on every close.
* This way we can use the "adjust" feature provided by System V so that
* any process that exit's without calling sem_close() is accounted
* for. It doesn't help us if the last process does this (as we have
* no way of getting control to remove the semaphore) but it will
* work if any process other than the last does an exit (intentional
* or unintentional).
* The third member, [2], of the semaphore set is used as a lock variable
* to avoid any race conditions in the sem_create() and sem_close()
* functions.
*/
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
namespace boost {
namespace interprocess {
namespace xsi {
// Create a semaphore with a specified initial value.
// If the semaphore already exists, we don't initialize it (of course).
// We return the semaphore ID if all OK, else -1.
inline bool simple_sem_open_or_create(::key_t key, int initval, int &semid, int perm)
{
int id, semval;
semid = -1;
if (key == IPC_PRIVATE)
return false; //not intended for private semaphores
else if (key == (::key_t) -1)
return false; //probably an ftok() error by caller
again:
if ((id = ::semget(key, 1, (perm & 0x01FF) | IPC_CREAT)) < 0)
return false; //permission problem or tables full
semid = id;
return true;
}
/****************************************************************************
* Remove a semaphore.
* This call is intended to be called by a server, for example,
* when it is being shut down, as we do an IPC_RMID on the semaphore,
* regardless whether other processes may be using it or not.
* Most other processes should use sem_close() below.
*/
inline bool simple_sem_rm(int id)
{
if (::semctl(id, 0, IPC_RMID, 0) < 0)
return false;
return true;
}
/****************************************************************************
* General semaphore operation. Increment or decrement by a user-specified
* amount (positive or negative; amount can't be zero).
*/
inline bool simple_sem_op(int id, int value, bool undo = true)
{
::sembuf op_op[1] = {
0, 99, 0 // decrement or increment [0] with undo on exit
// the 99 is set to the actual amount to add
// or subtract (positive or negative)
};
if(undo){
op_op[0].sem_flg = SEM_UNDO;
}
if ((op_op[0].sem_op = value) == 0)
return false;
if (::semop(id, &op_op[0], 1) < 0)
return false;
return true;
}
} //namespace xsi {
} //namespace interprocess {
} //namespace boost {
#endif //BOOST_INTERPROCESS_SYNC_XSI_SIMPLE_XSI_SEMAPHORE_HPP

View File

@@ -0,0 +1,228 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2009-2011. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_XSI_XSI_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_XSI_XSI_NAMED_MUTEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#if defined(BOOST_INTERPROCESS_WINDOWS)
#error "This header can't be used in Windows operating systems"
#endif
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/sync/xsi/basic_xsi_semaphore.hpp>
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/cstdint.hpp>
#include <string>
#include <boost/assert.hpp>
//!\file
//!Describes a class representing a xsi-based named_mutex.
namespace boost {
namespace interprocess {
//!A class that wraps a XSI (System V)-based named semaphore
//!that undoes the operation if the process crashes.
class xsi_named_mutex
{
/// @cond
//Non-copyable and non-assignable
xsi_named_mutex(xsi_named_mutex &);
xsi_named_mutex &operator=(xsi_named_mutex &);
/// @endcond
public:
BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_named_mutex)
//!Default constructor.
//!Represents an empty xsi_named_mutex.
xsi_named_mutex();
//!Tries to create a new XSI-based named mutex with a key obtained from a call to ftok (with path
//!"path" and id "id"), and permissions "perm".
//!If the named mutex previously exists, it tries to open it.
//!Otherwise throws an error.
xsi_named_mutex(open_or_create_t, const char *path, boost::uint8_t id, int perm = 0666)
{ this->priv_open_or_create(ipcdetail::DoOpenOrCreate, path, id, perm); }
//!Moves the ownership of "moved"'s named mutex to *this.
//!After the call, "moved" does not represent any named mutex
//!Does not throw
xsi_named_mutex(BOOST_RV_REF(xsi_named_mutex) moved)
{ this->swap(moved); }
//!Moves the ownership of "moved"'s named mutex to *this.
//!After the call, "moved" does not represent any named mutex.
//!Does not throw
xsi_named_mutex &operator=(BOOST_RV_REF(xsi_named_mutex) moved)
{
xsi_named_mutex tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps two xsi_named_mutex. Does not throw
void swap(xsi_named_mutex &other);
//!Destroys *this. The named mutex is still valid after
//!destruction. use remove() to destroy the named mutex.
~xsi_named_mutex();
//!Returns the path used to construct the
//!named mutex.
const char *get_path() const;
//!Returns access
//!permissions
int get_permissions() const;
//!Returns the mapping handle.
//!Never throws
mapping_handle_t get_mapping_handle() const;
//!Erases a XSI-based named mutex from the system.
//!Returns false on error. Never throws
bool remove();
void lock();
void unlock();
/// @cond
private:
//!Closes a previously opened file mapping. Never throws.
void priv_close();
//!Closes a previously opened file mapping. Never throws.
bool priv_open_or_create( ipcdetail::create_enum_t type
, const char *path
, boost::uint8_t id
, int perm);
int m_semid;
key_t m_key;
boost::uint8_t m_id;
int m_perm;
std::string m_path;
/// @endcond
};
/// @cond
inline xsi_named_mutex::xsi_named_mutex()
: m_semid(-1), m_key(-1), m_id(0), m_perm(0), m_path()
{}
inline xsi_named_mutex::~xsi_named_mutex()
{ this->priv_close(); }
inline const char *xsi_named_mutex::get_path() const
{ return m_path.c_str(); }
inline void xsi_named_mutex::swap(xsi_named_mutex &other)
{
std::swap(m_key, other.m_key);
std::swap(m_id, other.m_id);
std::swap(m_semid, other.m_semid);
std::swap(m_perm, other.m_perm);
m_path.swap(other.m_path);
}
inline mapping_handle_t xsi_named_mutex::get_mapping_handle() const
{ mapping_handle_t mhnd = { m_semid, true}; return mhnd; }
inline int xsi_named_mutex::get_permissions() const
{ return m_perm; }
inline bool xsi_named_mutex::priv_open_or_create
(ipcdetail::create_enum_t type, const char *path, boost::uint8_t id, int perm)
{
key_t key;
if(path){
key = ::ftok(path, id);
if(((key_t)-1) == key){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
else{
key = IPC_PRIVATE;
}
perm &= 0x01FF;
int semid;
if(!xsi::simple_sem_open_or_create(key, 1, semid, perm)){
error_info err = system_error_code();
throw interprocess_exception(err);
}
m_perm = perm;
m_semid = semid;
m_path = path ? path : "";
m_id = id;
m_key = key;
return true;
}
inline void xsi_named_mutex::priv_close()
{
}
inline void xsi_named_mutex::lock()
{
if(!xsi::simple_sem_op(m_semid, -1)){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline void xsi_named_mutex::unlock()
{
bool success = xsi::simple_sem_op(m_semid, 1);
(void)success;
BOOST_ASSERT(success);
}
inline bool xsi_named_mutex::remove()
{
if(m_semid != -1){
int ret = ::semctl(m_semid, IPC_RMID, 0);
if(-1 == ret)
return false;
//Now put it in default-constructed state
m_semid = -1;
m_key = -1;
m_id = 0;
m_perm = 0;
m_path.clear();
}
return false;
}
///@endcond
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_XSI_XSI_NAMED_MUTEX_HPP