diff --git a/include/boost/interprocess/detail/move.hpp b/include/boost/interprocess/detail/move.hpp new file mode 100644 index 0000000..ab653b7 --- /dev/null +++ b/include/boost/interprocess/detail/move.hpp @@ -0,0 +1,60 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztañaga 2005-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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MOVE_HPP +#define BOOST_INTERPROCESS_MOVE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +/*!\file + Describes a function and a type to emulate move semantics. +*/ +namespace boost { +namespace interprocess { +namespace detail { + +/*!An object that represents a moved object.*/ +template +struct moved_object +{ + moved_object(const Object &obj) + : m_obj(const_cast(&obj)) + {} + + Object &get() + { return *m_obj; } + + private: + Object *m_obj; +}; + +} //namespace detail { + +/*!A function that converts an object to a moved object so that + it can match a function taking a detail::moved_object object.*/ +template +detail::moved_object move + (/*const */Object &lock) +{ return detail::moved_object(lock); } + +} //namespace interprocess { +} //namespace boost { + + +#include + +#endif + + diff --git a/include/boost/interprocess/detail/os_thread_functions.hpp b/include/boost/interprocess/detail/os_thread_functions.hpp new file mode 100644 index 0000000..5c51d28 --- /dev/null +++ b/include/boost/interprocess/detail/os_thread_functions.hpp @@ -0,0 +1,69 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztañaga 2005-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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP + +#include +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include +# include +# else +# error Unknown platform +# endif +#endif + +namespace boost { +namespace interprocess { +namespace detail{ + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + +typedef unsigned long OS_thread_id_t; + +inline OS_thread_id_t get_current_thread_id() +{ return winapi::get_current_thread_id(); } + +inline OS_thread_id_t get_invalid_thread_id() +{ return OS_thread_id_t(0xffffffff); } + +inline OS_thread_id_t equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) +{ return id1 == id2; } + +#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + +typedef pthread_t OS_thread_id_t; + +inline pthread_t get_current_thread_id() +{ return pthread_self(); } + +inline OS_thread_id_t invalid_thread_id() +{ + static pthread_t invalid_id; + return invalid_id; +} + +inline OS_thread_id_t equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) +{ return 0 != pthread_equal(id1, id2); } + +#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + +} //namespace detail{ +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP diff --git a/include/boost/interprocess/smart_ptr/unique_ptr.hpp b/include/boost/interprocess/smart_ptr/unique_ptr.hpp new file mode 100644 index 0000000..4564ff2 --- /dev/null +++ b/include/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -0,0 +1,390 @@ +////////////////////////////////////////////////////////////////////////////// +// I, Howard Hinnant, hereby place this code in the public domain. +////////////////////////////////////////////////////////////////////////////// +// +// This file is the adaptation for Interprocess of +// Howard Hinnant's unique_ptr emulation +// +// (C) Copyright Ion Gaztañaga 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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_UNIQUE_PTR_HPP_INCLUDED +#define BOOST_INTERPROCESS_UNIQUE_PTR_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace interprocess{ + +template +struct default_delete +{ + default_delete() {} + template default_delete(const default_delete&) {} + void operator() (T* ptr) const + { + BOOST_STATIC_ASSERT(sizeof(T) > 0); + delete ptr; + } +}; + +template +struct default_delete +{ + void operator() (T* ptr) const + { + BOOST_STATIC_ASSERT(sizeof(T) > 0); + delete [] ptr; + } +}; + +template +struct default_delete +{ + void operator() (T* ptr, std::size_t) const + { + BOOST_STATIC_ASSERT(sizeof(T) > 0); + delete [] ptr; + } +}; + +template class unique_ptr; + +namespace detail { + +template struct unique_ptr_error; + +template +struct unique_ptr_error > +{ + typedef unique_ptr type; +}; + +} //namespace detail { + +template > +class unique_ptr +{ + struct nat {int for_bool_;}; + typedef typename boost::add_reference::type deleter_reference; + typedef typename boost::add_reference::type deleter_const_reference; + public: + typedef T element_type; + typedef D deleter_type; + typedef typename detail::pointer_type::type pointer; + + // constructors + unique_ptr() : ptr_(pointer()) {} + explicit unique_ptr(pointer p) : ptr_(p) {} + unique_ptr(pointer p + ,typename boost::mpl::if_ + ,D + ,typename boost::add_reference::type>::type d) + : ptr_(p, d) + {} +/* + unique_ptr(const unique_ptr& u) + : ptr_(const_cast(u).release(), u.get_deleter()) + {} +*/ + unique_ptr(detail::moved_object u) + : ptr_(u.get().release(), u.get().get_deleter()) + {} + + template + unique_ptr(const unique_ptr& u, + typename boost::enable_if_c< + boost::is_convertible::pointer, pointer>::value && + boost::is_convertible::value && + ( + !boost::is_reference::value || + boost::is_same::value + ) + , + nat + >::type = nat()) + : ptr_(const_cast&>(u).release(), u.get_deleter()) + {} + + // destructor + ~unique_ptr() + { reset(); } + + // assignment + unique_ptr& operator=(const unique_ptr& cu) + { + unique_ptr& u = const_cast(cu); + reset(u.release()); + ptr_.second() = u.get_deleter(); + return *this; + } + + template + unique_ptr& operator=(const unique_ptr& cu) + { + unique_ptr& u = const_cast&>(cu); + reset(u.release()); + ptr_.second() = u.get_deleter(); + return *this; + } + + unique_ptr& operator=(int nat::*) + { + reset(); + return *this; + } + + // observers + typename boost::add_reference::type operator*() const {return *ptr_.first();} + pointer operator->() const {return ptr_.first();} + pointer get() const {return ptr_.first();} + deleter_reference get_deleter() {return ptr_.second();} + deleter_const_reference get_deleter() const {return ptr_.second();} + operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;} + + // modifiers + pointer release() + { + pointer tmp = ptr_.first(); + ptr_.first() = pointer(); + return tmp; + } + + void reset(pointer p = pointer()) + { + if (ptr_.first() != p) + { + if (ptr_.first()) + ptr_.second()(ptr_.first()); + ptr_.first() = p; + } + } + + void swap(unique_ptr& u) {ptr_.swap(u.ptr_);} + + private: + boost::compressed_pair ptr_; + + //This private constructor avoids moving from non-const lvalues + unique_ptr(const unique_ptr&); + template unique_ptr(unique_ptr&); + template unique_ptr(U&, typename detail::unique_ptr_error::type = 0); + + + unique_ptr& operator=(unique_ptr&); + template unique_ptr& operator=(unique_ptr&); + template typename detail::unique_ptr_error::type operator=(U&); +}; +/* +template +class unique_ptr +{ + struct nat {int for_bool_;}; + typedef typename boost::add_reference::type deleter_reference; + typedef typename boost::add_reference::type deleter_const_reference; +public: + typedef T element_type; + typedef D deleter_type; + typedef typename detail::pointer_type::type pointer; + + // constructors + unique_ptr() : ptr_(pointer()) {} + explicit unique_ptr(pointer p) : ptr_(p) {} + unique_ptr(pointer p, typename boost::mpl::if_< + boost::is_reference, + D, + typename boost::add_reference::type>::type d) + : ptr_(p, d) {} + unique_ptr(const unique_ptr& u) + : ptr_(const_cast(u).release(), u.get_deleter()) {} + + // destructor + ~unique_ptr() {reset();} + + // assignment + unique_ptr& operator=(const unique_ptr& cu) + { + unique_ptr& u = const_cast(cu); + reset(u.release()); + ptr_.second() = u.get_deleter(); + return *this; + } + unique_ptr& operator=(int nat::*) + { + reset(); + return *this; + } + + // observers + typename boost::add_reference::type operator[](std::size_t i) const {return ptr_.first()[i];} + pointer get() const {return ptr_.first();} + deleter_reference get_deleter() {return ptr_.second();} + deleter_const_reference get_deleter() const {return ptr_.second();} + operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;} + + // modifiers + pointer release() + { + pointer tmp = ptr_.first(); + ptr_.first() = pointer(); + return tmp; + } + void reset(pointer p = pointer()) + { + if (ptr_.first() != p) + { + if (ptr_.first()) + ptr_.second()(ptr_.first()); + ptr_.first() = p; + } + } + void swap(unique_ptr& u) {ptr_.swap(u.ptr_);} +private: + boost::compressed_pair ptr_; + + template unique_ptr(U p, E, + typename boost::enable_if >::type* = 0); + template explicit unique_ptr(U, + typename boost::enable_if >::type* = 0); + + unique_ptr(unique_ptr&); + template unique_ptr(U&, typename detail::unique_ptr_error::type = 0); + + unique_ptr& operator=(unique_ptr&); + template typename detail::unique_ptr_error::type operator=(U&); +}; + +template +class unique_ptr +{ + struct nat {int for_bool_;}; + typedef typename boost::add_reference::type deleter_reference; + typedef typename boost::add_reference::type deleter_const_reference; +public: + typedef T element_type; + typedef D deleter_type; + typedef typename detail::pointer_type::type pointer; + static const std::size_t size = N; + + // constructors + unique_ptr() : ptr_(pointer()) {} + explicit unique_ptr(pointer p) : ptr_(p) {} + unique_ptr(pointer p, typename boost::mpl::if_< + boost::is_reference, + D, + typename boost::add_reference::type>::type d) + : ptr_(p, d) {} + unique_ptr(const unique_ptr& u) + : ptr_(const_cast(u).release(), u.get_deleter()) {} + + // destructor + ~unique_ptr() {reset();} + + // assignment + unique_ptr& operator=(const unique_ptr& cu) + { + unique_ptr& u = const_cast(cu); + reset(u.release()); + ptr_.second() = u.get_deleter(); + return *this; + } + unique_ptr& operator=(int nat::*) + { + reset(); + return *this; + } + + // observers + typename boost::add_reference::type operator[](std::size_t i) const {return ptr_.first()[i];} + pointer get() const {return ptr_.first();} + deleter_reference get_deleter() {return ptr_.second();} + deleter_const_reference get_deleter() const {return ptr_.second();} + operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;} + + // modifiers + pointer release() + { + pointer tmp = ptr_.first(); + ptr_.first() = pointer(); + return tmp; + } + void reset(pointer p = pointer()) + { + if (ptr_.first() != p) + { + if (ptr_.first()) + ptr_.second()(ptr_.first(), N); + ptr_.first() = p; + } + } + void swap(unique_ptr& u) {ptr_.swap(u.ptr_);} +private: + boost::compressed_pair ptr_; + + template unique_ptr(U p, E, + typename boost::enable_if >::type* = 0); + template explicit unique_ptr(U, + typename boost::enable_if >::type* = 0); + + unique_ptr(unique_ptr&); + template unique_ptr(U&, typename detail::unique_ptr_error::type = 0); + + unique_ptr& operator=(unique_ptr&); + template typename detail::unique_ptr_error::type operator=(U&); +}; +*/ +template inline +void swap(unique_ptr& x, unique_ptr& y) +{ x.swap(y); } + +template inline +bool operator==(const unique_ptr& x, const unique_ptr& y) +{ return x.get() == y.get(); } + +template inline +bool operator!=(const unique_ptr& x, const unique_ptr& y) +{ return x.get() != y.get(); } + +template inline +bool operator <(const unique_ptr& x, const unique_ptr& y) +{ return x.get() < y.get(); } + +template inline +bool operator<=(const unique_ptr& x, const unique_ptr& y) +{ return x.get() <= y.get(); } + +template inline +bool operator >(const unique_ptr& x, const unique_ptr& y) +{ return x.get() > y.get(); } + +template inline +bool operator>=(const unique_ptr& x, const unique_ptr& y) +{ return x.get() >= y.get(); } +/* +template inline +unique_ptr move(unique_ptr& p) +{ + return unique_ptr(p.release(), p.get_deleter()); +} +*/ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_INTERPROCESS_UNIQUE_PTR_HPP_INCLUDED diff --git a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp new file mode 100644 index 0000000..e22601c --- /dev/null +++ b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp @@ -0,0 +1,111 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztañaga 2005-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. +// +////////////////////////////////////////////////////////////////////////////// +// +// 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 +#include +#include + +namespace boost { + +namespace interprocess { + +inline interprocess_recursive_mutex::interprocess_recursive_mutex() + : m_nLockCount(0), m_nOwner(detail::get_invalid_thread_id()){} + +inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){} + +inline void interprocess_recursive_mutex::lock() +{ + unsigned long pNumber = detail::get_current_thread_id(); + if(pNumber == m_nOwner){ + if((unsigned int)(m_nLockCount+1) == 0){ + //Overflow, throw an exception + throw interprocess_exception(); + } + ++m_nLockCount; + } + else{ + m_mutex.lock(); + m_nOwner = pNumber; + m_nLockCount = 1; + } +} + +inline bool interprocess_recursive_mutex::try_lock() +{ + unsigned long pNumber = detail::get_current_thread_id(); + if(pNumber == m_nOwner) { // we own it + if((unsigned int)(m_nLockCount+1) == 0){ + //Overflow, throw an exception + throw interprocess_exception(); + } + ++m_nLockCount; + return true; + } + if(m_mutex.try_lock()){ + m_nOwner = pNumber; + m_nLockCount = 1; + return true; + } + return false; +} + +inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + unsigned long pNumber = detail::get_current_thread_id(); + if(pNumber == m_nOwner) { // we own it + if((unsigned int)(m_nLockCount+1) == 0){ + //Overflow, throw an exception + throw interprocess_exception(); + } + ++m_nLockCount; + return true; + } + if(m_mutex.timed_lock(abs_time)){ + m_nOwner = pNumber; + m_nLockCount = 1; + return true; + } + return false; +} + +inline void interprocess_recursive_mutex::unlock() +{ + #ifndef NDEBUG + unsigned long pNumber = detail::get_current_thread_id(); + assert(pNumber == m_nOwner); + #endif + --m_nLockCount; + if(!m_nLockCount){ + m_nOwner = detail::get_invalid_thread_id(); + m_mutex.unlock(); + } +} + +} //namespace interprocess { + +} //namespace boost { + diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp new file mode 100644 index 0000000..3b49e53 --- /dev/null +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -0,0 +1,250 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztañaga 2005-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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_NAMED_CONDITION_HPP +#define BOOST_NAMED_CONDITION_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +/*!\file + Describes process-shared variables interprocess_condition class +*/ + +namespace boost { + +namespace interprocess { + +class named_condition +{ + //Non-copyable + named_condition(); + named_condition(const named_condition &); + named_condition &operator=(const named_condition &); + + public: + /*!Creates a global condition with a name.*/ + named_condition(detail::create_only_t create_only, const char *name); + + /*!Opens or creates a global condition with a name. + If the condition is created, this call is equivalent to create(). + If the condition is already created, this call is equivalent to open(). + Does not throw*/ + named_condition(detail::open_or_create_t open_or_create, const char *name); + + /*!Opens a global condition with a name if that condition is previously. + created. If it is not previously created this function return false. + Does not throw*/ + named_condition(detail::open_only_t open_only, const char *name); + + /*!Destroys *this*/ + ~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 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 + void wait(L& lock); + + /*!The same as: while (!pred()) wait(lock)*/ + template + void wait(L& lock, Pr pred); + + /*!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 + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time); + + /*!The same as: while (!pred()) { + if (!timed_wait(lock, abs_time)) return false; + } return true;*/ + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred); + + static bool remove(const char *name); + + private: + + interprocess_condition *condition() const + { return static_cast(m_shmem.get_address()); } + + shared_memory m_shmem; + + class construct_func_t; +}; + + +class named_condition::construct_func_t +{ + public: + enum CreationType { open_only, open_or_create, create_only }; + + construct_func_t(CreationType type) + : m_creation_type(type){} + + bool operator()(const mapped_region ®ion, bool created) const + { + switch(m_creation_type){ + case open_only: + return true; + break; + case create_only: + case open_or_create: + if(created){ + new(region.get_address())interprocess_condition; + } + return true; + break; + + default: + return false; + break; + } + return true; + } + private: + CreationType m_creation_type; +}; + +inline named_condition::~named_condition() +{} + +inline named_condition::named_condition(detail::create_only_t, const char *name) + : m_shmem (create_only + ,name + ,sizeof(interprocess_condition) + ,memory_mappable::read_write + ,0 + ,construct_func_t(construct_func_t::create_only)) +{} + +inline named_condition::named_condition(detail::open_or_create_t, const char *name) + : m_shmem (open_or_create + ,name + ,sizeof(interprocess_condition) + ,memory_mappable::read_write + ,0 + ,construct_func_t(construct_func_t::open_or_create)) +{} + +inline named_condition::named_condition(detail::open_only_t, const char *name) + : m_shmem (open_only + ,name + ,memory_mappable::read_write + ,0 + ,construct_func_t(construct_func_t::open_only)) +{} + + +inline void named_condition::notify_one() +{ this->condition()->notify_one(); } + +inline void named_condition::notify_all() +{ this->condition()->notify_all(); } + +template +inline void named_condition::wait(L& lock) +{ + if (!lock) + throw lock_exception(); + this->condition()->do_wait(*lock.mutex()->mutex()); +} + +template +inline void named_condition::wait + (L& lock, Pr pred) +{ + if (!lock) + throw lock_exception(); + + while (!pred()) + this->condition()->do_wait(*lock.mutex()->mutex()); +} + +template +inline bool named_condition::timed_wait + (L& lock, const boost::posix_time::ptime &abs_time) +{ + if (!lock) + throw lock_exception(); + + return this->condition()->do_timed_wait(abs_time, *lock.mutex()->mutex()); +} + +template +inline bool named_condition::timed_wait + (L& lock, const boost::posix_time::ptime &abs_time, Pr pred) +{ + if (!lock) + throw lock_exception(); + + while (!pred()){ + if (!this->condition()->do_timed_wait(abs_time, *lock.mutex()->mutex())) + return false; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + +/* +template +inline void named_condition::wait(L& lock) +{ this->condition()->wait(lock); } + +template +inline void named_condition::wait(L& lock, Pr pred) +{ this->condition()->wait(lock, pred); } + +template +inline bool named_condition::timed_wait + (L& lock, const boost::posix_time::ptime &abs_time) +{ this->condition()->timed_wait(lock, abs_time); } + +template +inline bool named_condition::timed_wait + (L& lock, const boost::posix_time::ptime &abs_time, Pr pred) +{ this->condition()->timed_wait(lock, abs_time, pred); } +*/ +inline bool named_condition::remove(const char *name) +{ return shared_memory_object::remove(name); } + +} //namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_NAMED_CONDITION_HPP diff --git a/include/boost/interprocess/sync/named_upgradable_mutex.hpp b/include/boost/interprocess/sync/named_upgradable_mutex.hpp new file mode 100644 index 0000000..b4b8388 --- /dev/null +++ b/include/boost/interprocess/sync/named_upgradable_mutex.hpp @@ -0,0 +1,356 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztañaga 2005-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. +// +////////////////////////////////////////////////////////////////////////////// + +#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 +#include +#include +#include +#include +#include +#include +#include + +/*!\file + Describes a named upgradable mutex class for inter-process synchronization +*/ + +namespace boost { + +namespace interprocess { + +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 +{ + //Non-copyable + named_upgradable_mutex(); + named_upgradable_mutex(const named_upgradable_mutex &); + named_upgradable_mutex &operator=(const named_upgradable_mutex &); + friend class named_condition; + + public: + /*!Creates a global interprocess_mutex with a name.*/ + named_upgradable_mutex(detail::create_only_t create_only, const char *name); + + /*!Opens or creates a global upgradable mutex with a name. + If the upgradable mutex is created, this call is equivalent to create(). + If the upgradable mutex is already created, this call is equivalent to open(). + Throws interprocess_exception on error.*/ + named_upgradable_mutex(detail::open_or_create_t open_or_create, const char *name); + + /*!Opens a global upgradable mutex with a name if that mutex is previously. + created. If it is not previously created this function return false. + Throws interprocess_exception on error.*/ + named_upgradable_mutex(detail::open_only_t open_only, const char *name); + + /*!Closes the named upgradable mutex. Does not throw*/ + ~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 releas 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*/ + static bool remove(const char *name); + + private: + + interprocess_upgradable_mutex *mutex() const + { return static_cast(m_shmem.get_address()); } + + shared_memory m_shmem; + + class construct_func_t; +}; + +class named_upgradable_mutex::construct_func_t +{ + public: + enum CreationType { open_only, open_or_create, create_only }; + + construct_func_t(CreationType type) + : m_creation_type(type){} + + bool operator()(const mapped_region ®ion, bool created) const + { + switch(m_creation_type){ + case open_only: + return true; + break; + case create_only: + case open_or_create: + if(created){ + new(region.get_address())interprocess_upgradable_mutex; + } + return true; + break; + + default: + return false; + break; + } + return true; + } + private: + CreationType m_creation_type; +}; + +inline named_upgradable_mutex::~named_upgradable_mutex() +{} + +inline named_upgradable_mutex::named_upgradable_mutex + (detail::create_only_t, const char *name) + : m_shmem (create_only + ,name + ,sizeof(interprocess_upgradable_mutex) + ,memory_mappable::read_write + ,0 + ,construct_func_t(construct_func_t::create_only)) +{} + +inline named_upgradable_mutex::named_upgradable_mutex + (detail::open_or_create_t, const char *name) + : m_shmem (open_or_create + ,name + ,sizeof(interprocess_upgradable_mutex) + ,memory_mappable::read_write + ,0 + ,construct_func_t(construct_func_t::open_or_create)) +{} + +inline named_upgradable_mutex::named_upgradable_mutex + (detail::open_only_t, const char *name) + : m_shmem (open_only + ,name + ,memory_mappable::read_write + ,0 + ,construct_func_t(construct_func_t::open_only)) +{} + +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) +{ 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) +{ 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) +{ 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); } + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_named_upgradable_mutex_HPP diff --git a/include/boost/interprocess/sync/upgradable_lock.hpp b/include/boost/interprocess/sync/upgradable_lock.hpp new file mode 100644 index 0000000..090248d --- /dev/null +++ b/include/boost/interprocess/sync/upgradable_lock.hpp @@ -0,0 +1,308 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztañaga 2005-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. +// +////////////////////////////////////////////////////////////////////////////// +// +// 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 +#include +#include +#include +#include +#include +#include + +/*!\file + Describes the upgradable_lock class that serves to acquire the upgradable + lock of a mutex. +*/ + +namespace boost { +namespace interprocess { + +template +class scoped_lock; + +template +class sharable_lock; + +/*!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 trasfer_lock syntax. The Mutex need not supply all of the functionality. + If the client of upgradable_lock 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 trasfer_lock syntax.*/ +template +class upgradable_lock +{ + public: + typedef UpgradableMutex mutex_type; + + private: + typedef upgradable_lock this_type; + upgradable_lock(upgradable_lock const&); + explicit upgradable_lock(scoped_lock const&); + typedef bool this_type::*unspecified_bool_type; + upgradable_lock& operator=(upgradable_lock const&); + upgradable_lock& operator=(scoped_lock const&); + + 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, detail::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, detail::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, detail::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: "move(lock);". This constructor does not alter the + state of the mutex, only potentially who owns it.*/ + explicit upgradable_lock(detail::moved_object > upgr) + : mp_mutex(0), m_locked(upgr.get().owns()) + { mp_mutex = upgr.get().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: "move(lock);".*/ + explicit upgradable_lock(detail::moved_object > scop) + : mp_mutex(0), m_locked(false) + { + scoped_lock &u_lock = scop.get(); + 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.*/ + upgradable_lock( detail::moved_object > shar + , detail::try_to_lock_type) + : mp_mutex(0), m_locked(false) + { + sharable_lock &s_lock = shar.get(); + 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=(detail::moved_object > upgr) + { + if(this->owns()) + this->unlock(); + m_locked = upgr.get().owns(); + mp_mutex = upgr.get().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(detail::moved_object > other) + { + std::swap(mp_mutex, other.get().mp_mutex); + std::swap(m_locked, other.get().m_locked); + } + + private: + mutex_type *mp_mutex; + bool m_locked; +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_UPGRADABLE_LOCK_HPP