diff options
author | Anas Nashif <anas.nashif@intel.com> | 2013-08-26 08:15:55 -0400 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2013-08-26 08:15:55 -0400 |
commit | bb4dd8289b351fae6b55e303f189127a394a1edd (patch) | |
tree | 77c9c35a31b1459dd7988c2448e797d142530c41 /boost/interprocess/detail | |
parent | 1a78a62555be32868418fe52f8e330c9d0f95d5a (diff) | |
download | boost-bb4dd8289b351fae6b55e303f189127a394a1edd.tar.gz boost-bb4dd8289b351fae6b55e303f189127a394a1edd.tar.bz2 boost-bb4dd8289b351fae6b55e303f189127a394a1edd.zip |
Imported Upstream version 1.51.0upstream/1.51.0
Diffstat (limited to 'boost/interprocess/detail')
36 files changed, 2640 insertions, 2159 deletions
diff --git a/boost/interprocess/detail/atomic.hpp b/boost/interprocess/detail/atomic.hpp index f7551f3dda..aab1533985 100644 --- a/boost/interprocess/detail/atomic.hpp +++ b/boost/interprocess/detail/atomic.hpp @@ -117,23 +117,6 @@ inline boost::uint32_t atomic_cas32 : "cc"); return prev; -/* - asm volatile( "lock\n\t" - "cmpxchg %3,%1" - : "=a" (prev), "=m" (*(mem)) - : "0" (prev), "r" (with) - : "memory", "cc"); -*/ -/* - boost::uint32_t prev; - - asm volatile ("lock; cmpxchgl %1, %2" - : "=a" (prev) - : "r" (with), "m" (*(mem)), "0"(cmp)); - asm volatile("" : : : "memory"); - - return prev; -*/ } //! Atomically add 'val' to an boost::uint32_t @@ -158,14 +141,6 @@ inline boost::uint32_t atomic_add32 ); return r; -/* - asm volatile( "lock\n\t; xaddl %0,%1" - : "=r"(val), "=m"(*mem) - : "0"(val), "m"(*mem)); - asm volatile("" : : : "memory"); - - return val; -*/ } //! Atomically increment an apr_uint32_t by 1 @@ -208,17 +183,14 @@ inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32 { boost::uint32_t prev, temp; - asm volatile ("0:\n\t" // retry local label - "lwarx %0,0,%2\n\t" // load prev and reserve - "add %1,%0,%3\n\t" // temp = prev + val - "stwcx. %1,0,%2\n\t" // conditionally store - "bne- 0b" // start over if we lost - // the reservation - //XXX find a cleaner way to define the temp - //it's not an output - : "=&r" (prev), "=&r" (temp) // output, temp - : "b" (mem), "r" (val) // inputs - : "memory", "cc"); // clobbered + asm volatile ("1:\n\t" + "lwarx %0,0,%2\n\t" + "add %1,%0,%3\n\t" + "stwcx. %1,0,%2\n\t" + "bne- 1b" + : "=&r" (prev), "=&r" (temp) + : "b" (mem), "r" (val) + : "cc", "memory"); return prev; } @@ -233,19 +205,16 @@ inline boost::uint32_t atomic_cas32 { boost::uint32_t prev; - asm volatile ("0:\n\t" // retry local label - "lwarx %0,0,%1\n\t" // load prev and reserve - "cmpw %0,%3\n\t" // does it match cmp? - "bne- 1f\n\t" // ...no, bail out - "stwcx. %2,0,%1\n\t" // ...yes, conditionally - // store with - "bne- 0b\n\t" // start over if we lost - // the reservation - "1:" // exit local label - - : "=&r"(prev) // output - : "b" (mem), "r" (with), "r"(cmp) // inputs - : "memory", "cc"); // clobbered + asm volatile ("1:\n\t" + "lwarx %0,0,%1\n\t" + "cmpw %0,%3\n\t" + "bne- 2f\n\t" + "stwcx. %2,0,%1\n\t" + "bne- 1b\n\t" + "2:" + : "=&r"(prev) + : "b" (mem), "r"(cmp), "r" (with) + : "cc", "memory"); return prev; } @@ -275,56 +244,6 @@ inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) } //namespace interprocess{ } //namespace boost{ -#elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) - -namespace boost { -namespace interprocess { -namespace ipcdetail{ - -//! Atomically add 'val' to an boost::uint32_t -//! "mem": pointer to the object -//! "val": amount to add -//! Returns the old value pointed to by mem -inline boost::uint32_t atomic_add32 - (volatile boost::uint32_t *mem, boost::uint32_t val) -{ return __sync_fetch_and_add(const_cast<boost::uint32_t *>(mem), val); } - -//! Atomically increment an apr_uint32_t by 1 -//! "mem": pointer to the object -//! Returns the old value pointed to by mem -inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) -{ return atomic_add32(mem, 1); } - -//! Atomically decrement an boost::uint32_t by 1 -//! "mem": pointer to the atomic value -//! Returns the old value pointed to by mem -inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) -{ return atomic_add32(mem, (boost::uint32_t)-1); } - -//! Atomically read an boost::uint32_t from memory -inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) -{ return *mem; } - -//! Compare an boost::uint32_t's value with "cmp". -//! If they are the same swap the value with "with" -//! "mem": pointer to the value -//! "with" what to swap it with -//! "cmp": the value to compare it to -//! Returns the old value of *mem -inline boost::uint32_t atomic_cas32 - (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) -{ return __sync_val_compare_and_swap(const_cast<boost::uint32_t *>(mem), cmp, with); } - -//! Atomically set an boost::uint32_t in memory -//! "mem": pointer to the object -//! "param": val value that the object will assume -inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) -{ *mem = val; } - -} //namespace ipcdetail{ -} //namespace interprocess{ -} //namespace boost{ - #elif (defined(sun) || defined(__sun)) #include <atomic.h> @@ -471,97 +390,147 @@ inline boost::uint32_t atomic_cas32( } //namespace interprocess{ } //namespace boost{ -#elif defined(__IBMCPP__) && (__IBMCPP__ >= 800) && defined(_AIX) - -#include <builtins.h> - -namespace boost { -namespace interprocess { -namespace ipcdetail{ - -//first define boost::uint32_t versions of __lwarx and __stwcx to avoid poluting -//all the functions with casts - -//! From XLC documenation : -//! This function can be used with a subsequent stwcxu call to implement a -//! read-modify-write on a specified memory location. The two functions work -//! together to ensure that if the store is successfully performed, no other -//! processor or mechanism can modify the target doubleword between the time -//! lwarxu function is executed and the time the stwcxu functio ncompletes. -//! "mem" : pointer to the object -//! Returns the value at pointed to by mem -inline boost::uint32_t lwarxu(volatile boost::uint32_t *mem) -{ - return static_cast<boost::uint32_t>(__lwarx(reinterpret_cast<volatile int*>(mem))); -} - -//! "mem" : pointer to the object -//! "val" : the value to store -//! Returns true if the update of mem is successful and false if it is -//!unsuccessful -inline bool stwcxu(volatile boost::uint32_t* mem, boost::uint32_t val) -{ - return (__stwcx(reinterpret_cast<volatile int*>(mem), static_cast<int>(val)) != 0); -} - -//! "mem": pointer to the object -//! "val": amount to add -//! Returns the old value pointed to by mem -inline boost::uint32_t atomic_add32 - (volatile boost::uint32_t *mem, boost::uint32_t val) -{ - boost::uint32_t oldValue; - do - { - oldValue = lwarxu(mem); - }while (!stwcxu(mem, oldValue+val)); - return oldValue; -} - -//! Atomically increment an apr_uint32_t by 1 -//! "mem": pointer to the object -//! Returns the old value pointed to by mem -inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) -{ return atomic_add32(mem, 1); } - -//! Atomically decrement an boost::uint32_t by 1 -//! "mem": pointer to the atomic value -//! Returns the old value pointed to by mem -inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) -{ return atomic_add32(mem, (boost::uint32_t)-1); } - -//! Atomically read an boost::uint32_t from memory -inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) -{ return *mem; } - -//! Compare an boost::uint32_t's value with "cmp". -//! If they are the same swap the value with "with" -//! "mem": pointer to the value -//! "with" what to swap it with -//! "cmp": the value to compare it to -//! Returns the old value of *mem -inline boost::uint32_t atomic_cas32 - (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) -{ - boost::uint32_t oldValue; - boost::uint32_t valueToStore; - do - { - oldValue = lwarxu(mem); - } while (!stwcxu(mem, (oldValue == with) ? cmp : oldValue)); - - return oldValue; -} - -//! Atomically set an boost::uint32_t in memory -//! "mem": pointer to the object -//! "param": val value that the object will assume -inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) -{ *mem = val; } - -} //namespace ipcdetail -} //namespace interprocess -} //namespace boost +#elif defined(__IBMCPP__) && (__IBMCPP__ >= 800) && defined(_AIX) + +#include <builtins.h> + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +//first define boost::uint32_t versions of __lwarx and __stwcx to avoid poluting +//all the functions with casts + +//! From XLC documenation : +//! This function can be used with a subsequent stwcxu call to implement a +//! read-modify-write on a specified memory location. The two functions work +//! together to ensure that if the store is successfully performed, no other +//! processor or mechanism can modify the target doubleword between the time +//! lwarxu function is executed and the time the stwcxu functio ncompletes. +//! "mem" : pointer to the object +//! Returns the value at pointed to by mem +inline boost::uint32_t lwarxu(volatile boost::uint32_t *mem) +{ + return static_cast<boost::uint32_t>(__lwarx(reinterpret_cast<volatile int*>(mem))); +} + +//! "mem" : pointer to the object +//! "val" : the value to store +//! Returns true if the update of mem is successful and false if it is +//!unsuccessful +inline bool stwcxu(volatile boost::uint32_t* mem, boost::uint32_t val) +{ + return (__stwcx(reinterpret_cast<volatile int*>(mem), static_cast<int>(val)) != 0); +} + +//! "mem": pointer to the object +//! "val": amount to add +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_add32 + (volatile boost::uint32_t *mem, boost::uint32_t val) +{ + boost::uint32_t oldValue; + do + { + oldValue = lwarxu(mem); + }while (!stwcxu(mem, oldValue+val)); + return oldValue; +} + +//! Atomically increment an apr_uint32_t by 1 +//! "mem": pointer to the object +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) +{ return atomic_add32(mem, 1); } + +//! Atomically decrement an boost::uint32_t by 1 +//! "mem": pointer to the atomic value +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) +{ return atomic_add32(mem, (boost::uint32_t)-1); } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ return *mem; } + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! Returns the old value of *mem +inline boost::uint32_t atomic_cas32 + (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) +{ + boost::uint32_t oldValue; + boost::uint32_t valueToStore; + do + { + oldValue = lwarxu(mem); + } while (!stwcxu(mem, (oldValue == with) ? cmp : oldValue)); + + return oldValue; +} + +//! Atomically set an boost::uint32_t in memory +//! "mem": pointer to the object +//! "param": val value that the object will assume +inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ *mem = val; } + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +//! Atomically add 'val' to an boost::uint32_t +//! "mem": pointer to the object +//! "val": amount to add +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_add32 + (volatile boost::uint32_t *mem, boost::uint32_t val) +{ return __sync_fetch_and_add(const_cast<boost::uint32_t *>(mem), val); } + +//! Atomically increment an apr_uint32_t by 1 +//! "mem": pointer to the object +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) +{ return atomic_add32(mem, 1); } + +//! Atomically decrement an boost::uint32_t by 1 +//! "mem": pointer to the atomic value +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) +{ return atomic_add32(mem, (boost::uint32_t)-1); } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ return *mem; } + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! Returns the old value of *mem +inline boost::uint32_t atomic_cas32 + (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) +{ return __sync_val_compare_and_swap(const_cast<boost::uint32_t *>(mem), cmp, with); } + +//! Atomically set an boost::uint32_t in memory +//! "mem": pointer to the object +//! "param": val value that the object will assume +inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ *mem = val; } + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ #else @@ -583,9 +552,9 @@ inline bool atomic_add_unless32 return c != unless_this; } -} //namespace ipcdetail -} //namespace interprocess -} //namespace boost +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost #include <boost/interprocess/detail/config_end.hpp> diff --git a/boost/interprocess/detail/config_begin.hpp b/boost/interprocess/detail/config_begin.hpp index 559331ab32..a72f6df1fe 100644 --- a/boost/interprocess/detail/config_begin.hpp +++ b/boost/interprocess/detail/config_begin.hpp @@ -44,4 +44,5 @@ // with /GR-; unpredictable behavior may result #pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site #pragma warning (disable : 4671) // the copy constructor is inaccessible + #pragma warning (disable : 4250) // inherits 'x' via dominance #endif diff --git a/boost/interprocess/detail/file_locking_helpers.hpp b/boost/interprocess/detail/file_locking_helpers.hpp new file mode 100644 index 0000000000..2b96e2b6d5 --- /dev/null +++ b/boost/interprocess/detail/file_locking_helpers.hpp @@ -0,0 +1,298 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP +#define BOOST_INTERPROCESS_FILE_LOCKING_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 <sstream> +#include <string> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <cstddef> +#include <boost/interprocess/detail/os_file_functions.hpp> + +#include <boost/interprocess/detail/tmp_dir_helpers.hpp> + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +#include <fcntl.h> +#include <io.h> +#include <sys/locking.h> + +#else //defined(BOOST_INTERPROCESS_WINDOWS) + +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#endif //defined(BOOST_INTERPROCESS_WINDOWS) + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +struct locking_file_serial_id +{ + int fd; + unsigned long dwVolumeSerialNumber; + unsigned long nFileIndexHigh; + unsigned long nFileIndexLow; + //This reference count counts the number of modules attached + //to the shared memory and lock file. This serves to unlink + //the locking file and shared memory when all modules are + //done with the global memory (shared memory) + volatile boost::uint32_t modules_attached_to_gmem_count; +}; + +inline bool lock_locking_file(int fd) +{ + int ret = 0; + while(ret != 0 && errno == EDEADLK){ + ret = _locking(fd, _LK_LOCK, 1/*lock_file_contents_length()*/); + } + return 0 == ret; +} + +inline bool try_lock_locking_file(int fd) +{ + return 0 == _locking(fd, _LK_NBLCK , 1); +} + +inline int open_or_create_and_lock_file(const char *name) +{ + permissions p; + p.set_unrestricted(); + while(1){ + file_handle_t handle = create_or_open_file(name, read_write, p); + int fd = _open_osfhandle((intptr_t)handle, _O_TEXT); + if(fd < 0){ + close_file(handle); + return fd; + } + if(!try_lock_locking_file(fd)){ + _close(fd); + return -1; + } + struct _stat s; + if(0 == _stat(name, &s)){ + return fd; + } + else{ + _close(fd); + } + } +} + +inline int try_open_and_lock_file(const char *name) +{ + file_handle_t handle = open_existing_file(name, read_write); + int fd = _open_osfhandle((intptr_t)handle, _O_TEXT); + if(fd < 0){ + close_file(handle); + return fd; + } + if(!try_lock_locking_file(fd)){ + _close(fd); + return -1; + } + return fd; +} + +inline void close_lock_file(int fd) +{ _close(fd); } + +inline bool is_valid_fd(int fd) +{ + struct _stat s; + return EBADF != _fstat(fd, &s); +} + +inline bool is_normal_file(int fd) +{ + if(_isatty(fd)) + return false; + struct _stat s; + if(0 != _fstat(fd, &s)) + return false; + return 0 != (s.st_mode & _S_IFREG); +} + +inline std::size_t get_size(int fd) +{ + struct _stat s; + if(0 != _fstat(fd, &s)) + return 0u; + return (std::size_t)s.st_size; +} + +inline bool fill_file_serial_id(int fd, locking_file_serial_id &id) +{ + winapi::interprocess_by_handle_file_information info; + if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info)) + return false; + id.fd = fd; + id.dwVolumeSerialNumber = info.dwVolumeSerialNumber; + id.nFileIndexHigh = info.nFileIndexHigh; + id.nFileIndexLow = info.nFileIndexLow; + id.modules_attached_to_gmem_count = 1; //Initialize attached count + return true; +} + +inline bool compare_file_serial(int fd, const locking_file_serial_id &id) +{ + winapi::interprocess_by_handle_file_information info; + if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info)) + return false; + + return id.dwVolumeSerialNumber == info.dwVolumeSerialNumber && + id.nFileIndexHigh == info.nFileIndexHigh && + id.nFileIndexLow == info.nFileIndexLow; +} + +#else //UNIX + +struct locking_file_serial_id +{ + int fd; + dev_t st_dev; + ino_t st_ino; + //This reference count counts the number of modules attached + //to the shared memory and lock file. This serves to unlink + //the locking file and shared memory when all modules are + //done with the global memory (shared memory) + volatile boost::uint32_t modules_attached_to_gmem_count; +}; + +inline bool lock_locking_file(int fd) +{ + int ret = 0; + while(ret != 0 && errno != EINTR){ + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + ret = fcntl (fd, F_SETLKW, &lock); + } + return 0 == ret; +} + +inline bool try_lock_locking_file(int fd) +{ + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + return 0 == fcntl (fd, F_SETLK, &lock); +} + +inline int open_or_create_and_lock_file(const char *name) +{ + permissions p; + p.set_unrestricted(); + while(1){ + int fd = create_or_open_file(name, read_write, p); + if(fd < 0){ + return fd; + } + if(!try_lock_locking_file(fd)){ + close(fd); + return -1; + } + struct stat s; + if(0 == stat(name, &s)){ + return fd; + } + else{ + close(fd); + } + } +} + +inline int try_open_and_lock_file(const char *name) +{ + int fd = open_existing_file(name, read_write); + if(fd < 0){ + return fd; + } + if(!try_lock_locking_file(fd)){ + close(fd); + return -1; + } + return fd; +} + +inline void close_lock_file(int fd) +{ close(fd); } + +inline bool is_valid_fd(int fd) +{ + struct stat s; + return EBADF != fstat(fd, &s); +} + +inline bool is_normal_file(int fd) +{ + struct stat s; + if(0 != fstat(fd, &s)) + return false; + return 0 != (s.st_mode & S_IFREG); +} + +inline std::size_t get_size(int fd) +{ + struct stat s; + if(0 != fstat(fd, &s)) + return 0u; + return (std::size_t)s.st_size; +} + +inline bool fill_file_serial_id(int fd, locking_file_serial_id &id) +{ + struct stat s; + if(0 != fstat(fd, &s)) + return false; + id.fd = fd; + id.st_dev = s.st_dev; + id.st_ino = s.st_ino; + id.modules_attached_to_gmem_count = 1; //Initialize attached count + return true; +} + +inline bool compare_file_serial(int fd, const locking_file_serial_id &id) +{ + struct stat info; + if(0 != fstat(fd, &info)) + return false; + + return id.st_dev == info.st_dev && + id.st_ino == info.st_ino; +} + +#endif + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP diff --git a/boost/interprocess/detail/file_wrapper.hpp b/boost/interprocess/detail/file_wrapper.hpp index 7b53f36ac8..586e20db4d 100644 --- a/boost/interprocess/detail/file_wrapper.hpp +++ b/boost/interprocess/detail/file_wrapper.hpp @@ -44,13 +44,13 @@ class file_wrapper file_wrapper(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions()) { this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm); } - //!Tries to open a file with name "name", with the access mode "mode". + //!Tries to open a file with name "name", with the access mode "mode". //!If the file does not previously exist, it throws an error. file_wrapper(open_only_t, const char *name, mode_t mode) { this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); } - //!Moves the ownership of "moved"'s file to *this. - //!After the call, "moved" does not represent any file. + //!Moves the ownership of "moved"'s file to *this. + //!After the call, "moved" does not represent any file. //!Does not throw file_wrapper(BOOST_RV_REF(file_wrapper) moved) : m_handle(file_handle_t(ipcdetail::invalid_file())) @@ -60,10 +60,10 @@ class file_wrapper //!After the call, "moved" does not represent any file. //!Does not throw file_wrapper &operator=(BOOST_RV_REF(file_wrapper) moved) - { + { file_wrapper tmp(boost::move(moved)); this->swap(tmp); - return *this; + return *this; } //!Swaps to file_wrappers. @@ -73,7 +73,7 @@ class file_wrapper //!Erases a file from the system. //!Returns false on error. Never throws static bool remove(const char *name); - + //!Sets the size of the file void truncate(offset_t length); @@ -108,11 +108,11 @@ class file_wrapper std::string m_filename; }; -inline file_wrapper::file_wrapper() +inline file_wrapper::file_wrapper() : m_handle(file_handle_t(ipcdetail::invalid_file())) {} -inline file_wrapper::~file_wrapper() +inline file_wrapper::~file_wrapper() { this->priv_close(); } inline const char *file_wrapper::get_name() const @@ -122,10 +122,10 @@ inline bool file_wrapper::get_size(offset_t &size) const { return get_file_size((file_handle_t)m_handle, size); } inline void file_wrapper::swap(file_wrapper &other) -{ +{ std::swap(m_handle, other.m_handle); std::swap(m_mode, other.m_mode); - m_filename.swap(other.m_filename); + m_filename.swap(other.m_filename); } inline mapping_handle_t file_wrapper::get_mapping_handle() const @@ -135,7 +135,7 @@ inline mode_t file_wrapper::get_mode() const { return m_mode; } inline bool file_wrapper::priv_open_or_create - (ipcdetail::create_enum_t type, + (ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm = permissions()) diff --git a/boost/interprocess/detail/in_place_interface.hpp b/boost/interprocess/detail/in_place_interface.hpp index 0e69452a40..b43b2ce165 100644 --- a/boost/interprocess/detail/in_place_interface.hpp +++ b/boost/interprocess/detail/in_place_interface.hpp @@ -25,7 +25,7 @@ //!Describes an abstract interface for placement construction and destruction. namespace boost { -namespace interprocess { +namespace interprocess { namespace ipcdetail { struct in_place_interface diff --git a/boost/interprocess/detail/intermodule_singleton.hpp b/boost/interprocess/detail/intermodule_singleton.hpp index 4bffbe9d4e..054322699d 100644 --- a/boost/interprocess/detail/intermodule_singleton.hpp +++ b/boost/interprocess/detail/intermodule_singleton.hpp @@ -18,1163 +18,27 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> -#if defined(BOOST_INTERPROCESS_WINDOWS) -#include <boost/interprocess/windows_shared_memory.hpp> -#endif - -#include <boost/interprocess/shared_memory_object.hpp> - -#include <boost/interprocess/offset_ptr.hpp> -#include <boost/interprocess/sync/spin/mutex.hpp> -#include <boost/interprocess/sync/spin/recursive_mutex.hpp> -#include <boost/interprocess/detail/managed_memory_impl.hpp> -#include <boost/interprocess/detail/managed_open_or_create_impl.hpp> -#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp> -#include <boost/interprocess/indexes/iset_index.hpp> -#include <boost/interprocess/creation_tags.hpp> -#include <boost/interprocess/permissions.hpp> - - -#include <boost/interprocess/detail/atomic.hpp> -#include <boost/interprocess/detail/os_thread_functions.hpp> -#include <boost/interprocess/detail/tmp_dir_helpers.hpp> -#include <boost/interprocess/detail/os_file_functions.hpp> -#include <boost/interprocess/detail/mpl.hpp> -#include <boost/type_traits/type_with_alignment.hpp> -#include <boost/assert.hpp> -#include <cstddef> -#include <cstdio> -#include <cstring> -#include <string> - -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> - -#if defined(BOOST_INTERPROCESS_WINDOWS) -#include <fcntl.h> -#include <io.h> - -#include <sys/locking.h> -#else -#include <fcntl.h> -#include <sys/stat.h> -#include <unistd.h> +#ifdef BOOST_INTERPROCESS_WINDOWS + #include <boost/interprocess/detail/windows_intermodule_singleton.hpp> #endif +#include <boost/interprocess/detail/portable_intermodule_singleton.hpp> namespace boost{ namespace interprocess{ namespace ipcdetail{ -struct intermodule_singleton_mutex_family -{ - typedef boost::interprocess::ipcdetail::spin_mutex mutex_type; - typedef boost::interprocess::ipcdetail::spin_recursive_mutex recursive_mutex_type; -}; - -struct intermodule_types -{ - //We must use offset_ptr since a loaded DLL can map the singleton holder shared memory - //at a different address than other DLLs/main executables - typedef rbtree_best_fit<intermodule_singleton_mutex_family, offset_ptr<void> > mem_algo; - template<class Device, bool FileBased> - struct open_or_create - { - typedef managed_open_or_create_impl - <Device, mem_algo::Alignment, FileBased> type; - }; -}; - -template<class Device, bool FileBased> -class basic_managed_global_memory - : public basic_managed_memory_impl - < char - , intermodule_types::mem_algo - , iset_index - , intermodule_types::open_or_create<Device, FileBased>::type::ManagedOpenOrCreateUserOffset - > - , private intermodule_types::open_or_create<Device, FileBased>::type -{ - /// @cond - typedef typename intermodule_types::template open_or_create<Device, FileBased>::type base2_t; - - typedef basic_managed_memory_impl - < char - , intermodule_types::mem_algo - , iset_index - , base2_t::ManagedOpenOrCreateUserOffset - > base_t; - - typedef create_open_func<base_t> create_open_func_t; - - basic_managed_global_memory *get_this_pointer() - { return this; } - - public: - typedef typename base_t::size_type size_type; - - private: - typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; - BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_global_memory) - /// @endcond - - public: //functions -/* - basic_managed_global_memory() - {} - - basic_managed_global_memory(create_only_t create_only, const char *name, - size_type size, const void *addr = 0, const permissions& perm = permissions()) - : base_t() - , base2_t(create_only, name, size, read_write, addr, - create_open_func_t(get_this_pointer(), DoCreate), perm) - {} -*/ - basic_managed_global_memory (open_or_create_t open_or_create, - const char *name, size_type size, - const void *addr = 0, const permissions& perm = permissions()) - : base_t() - , base2_t(open_or_create, name, size, read_write, addr, - create_open_func_t(get_this_pointer(), - DoOpenOrCreate), perm) - {} - - basic_managed_global_memory (open_only_t open_only, const char* name, - const void *addr = 0) - : base_t() - , base2_t(open_only, name, read_write, addr, - create_open_func_t(get_this_pointer(), - DoOpen)) - {} - -/* - basic_managed_global_memory (open_copy_on_write_t, const char* name, - const void *addr = 0) - : base_t() - , base2_t(open_only, name, copy_on_write, addr, - create_open_func_t(get_this_pointer(), - DoOpen)) - {} - - //!Connects to a created shared memory and its segment manager. - //!in read-only mode. - //!This can throw. - basic_managed_global_memory (open_read_only_t, const char* name, - const void *addr = 0) - : base_t() - , base2_t(open_only, name, read_only, addr, - create_open_func_t(get_this_pointer(), - DoOpen)) - {} - - //!Moves the ownership of "moved"'s managed memory to *this. - //!Does not throw - basic_managed_global_memory(BOOST_RV_REF(basic_managed_global_memory) moved) - { - basic_managed_global_memory tmp; - this->swap(moved); - tmp.swap(moved); - } - - //!Moves the ownership of "moved"'s managed memory to *this. - //!Does not throw - basic_managed_global_memory &operator=(BOOST_RV_REF(basic_managed_global_memory) moved) - { - basic_managed_global_memory tmp(boost::move(moved)); - this->swap(tmp); - return *this; - }*/ -}; - -#if defined(BOOST_INTERPROCESS_WINDOWS) -typedef basic_managed_global_memory<windows_shared_memory, false> windows_managed_global_memory; -#endif - -typedef basic_managed_global_memory<shared_memory_object, true> managed_global_memory; - -namespace file_locking_helpers { - -inline void get_pid_creation_time_str(std::string &s) -{ - std::stringstream stream; - stream << get_current_process_id() << '_'; - stream.precision(6); - stream << std::fixed << get_current_process_creation_time(); - s = stream.str(); -} - -inline void create_tmp_subdir_and_get_pid_based_filepath(const char *subdir_name, const char *file_prefix, OS_process_id_t pid, std::string &s, bool creation_time = false) -{ - //Let's create a lock file for each process gmem that will mark if - //the process is alive or not - create_tmp_and_clean_old(s); - s += "/"; - s += subdir_name; - if(!open_or_create_directory(s.c_str())){ - throw interprocess_exception(error_info(system_error_code())); - } - s += "/"; - s += file_prefix; - if(creation_time){ - std::string sstamp; - get_pid_creation_time_str(sstamp); - s += sstamp; - } - else{ - pid_str_t pid_str; - get_pid_str(pid_str, pid); - s += pid_str; - } -} - -inline bool check_if_filename_complies_with_pid - (const char *filename, const char *prefix, OS_process_id_t pid, std::string &file_suffix, bool creation_time = false) -{ - //Check if filename complies with lock file name pattern - std::string fname(filename); - std::string fprefix(prefix); - if(fname.size() <= fprefix.size()){ - return false; - } - fname.resize(fprefix.size()); - if(fname != fprefix){ - return false; - } - - //If not our lock file, delete it if we can lock it - fname = filename; - fname.erase(0, fprefix.size()); - pid_str_t pid_str; - get_pid_str(pid_str, pid); - file_suffix = pid_str; - if(creation_time){ - std::size_t p = fname.find('_'); - if (p == std::string::npos){ - return false; - } - std::string save_suffix(fname); - fname.erase(p); - fname.swap(file_suffix); - bool ret = (file_suffix == fname); - file_suffix.swap(save_suffix); - return ret; - } - else{ - fname.swap(file_suffix); - return (file_suffix == fname); - } -} - -} //file_locking_helpers - -namespace intermodule_singleton_helpers { - -const int GMemMarkToBeRemoved = -1; -const int GMemNotPresent = -2; - -inline const char *get_lock_file_subdir_name() -{ return "gmem"; } - -inline const char *get_lock_file_base_name() -{ return "lck"; } - -inline void create_and_get_singleton_lock_file_path(std::string &s) -{ - file_locking_helpers::create_tmp_subdir_and_get_pid_based_filepath - (get_lock_file_subdir_name(), get_lock_file_base_name(), get_current_process_id(), s, true); -} - -inline const char *get_shm_base_name() -{ return "bip.gmem.shm."; } - -inline void get_shm_name(std::string &shm_name) -{ - file_locking_helpers::get_pid_creation_time_str(shm_name); - shm_name.insert(0, get_shm_base_name()); -} - -inline std::size_t get_shm_size() -{ return 65536; } - -template<class ManagedShMem> -struct managed_sh_dependant -{ - static void apply_gmem_erase_logic(const char *filepath, const char *filename); - - static bool remove_old_gmem() - { - std::string refcstrRootDirectory; - tmp_folder(refcstrRootDirectory); - refcstrRootDirectory += "/"; - refcstrRootDirectory += get_lock_file_subdir_name(); - return for_each_file_in_dir(refcstrRootDirectory.c_str(), apply_gmem_erase_logic); - } -}; - -#if defined(BOOST_INTERPROCESS_WINDOWS) - -template<> -struct managed_sh_dependant<windows_managed_global_memory> -{ - static void apply_gmem_erase_logic(const char *, const char *){} - - static bool remove_old_gmem() - { return true; } -}; - - -struct locking_file_serial_id -{ - int fd; - unsigned long dwVolumeSerialNumber; - unsigned long nFileIndexHigh; - unsigned long nFileIndexLow; - //This reference count counts the number of modules attached - //to the shared memory and lock file. This serves to unlink - //the locking file and shared memory when all modules are - //done with the global memory (shared memory) - volatile boost::uint32_t modules_attached_to_gmem_count; -}; - -inline bool lock_locking_file(int fd) -{ - int ret = 0; - while(ret != 0 && errno == EDEADLK){ - ret = _locking(fd, _LK_LOCK, 1/*lock_file_contents_length()*/); - } - return 0 == ret; -} - -inline bool try_lock_locking_file(int fd) -{ - return 0 == _locking(fd, _LK_NBLCK , 1); -} - -inline int open_or_create_and_lock_file(const char *name) -{ - permissions p; - p.set_unrestricted(); - while(1){ - file_handle_t handle = create_or_open_file(name, read_write, p); - int fd = _open_osfhandle((intptr_t)handle, _O_TEXT); - if(fd < 0){ - close_file(handle); - return fd; - } - if(!try_lock_locking_file(fd)){ - _close(fd); - return -1; - } - struct _stat s; - if(0 == _stat(name, &s)){ - return fd; - } - else{ - _close(fd); - } - } -} - -inline int try_open_and_lock_file(const char *name) -{ - file_handle_t handle = open_existing_file(name, read_write); - int fd = _open_osfhandle((intptr_t)handle, _O_TEXT); - if(fd < 0){ - close_file(handle); - return fd; - } - if(!try_lock_locking_file(fd)){ - _close(fd); - return -1; - } - return fd; -} - -inline void close_lock_file(int fd) -{ _close(fd); } - -inline bool is_valid_fd(int fd) -{ - struct _stat s; - return EBADF != _fstat(fd, &s); -} - -inline bool is_normal_file(int fd) -{ - if(_isatty(fd)) - return false; - struct _stat s; - if(0 != _fstat(fd, &s)) - return false; - return 0 != (s.st_mode & _S_IFREG); -} - -inline std::size_t get_size(int fd) -{ - struct _stat s; - if(0 != _fstat(fd, &s)) - return 0u; - return (std::size_t)s.st_size; -} - -inline bool fill_file_serial_id(int fd, locking_file_serial_id &id) -{ - winapi::interprocess_by_handle_file_information info; - if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info)) - return false; - id.fd = fd; - id.dwVolumeSerialNumber = info.dwVolumeSerialNumber; - id.nFileIndexHigh = info.nFileIndexHigh; - id.nFileIndexLow = info.nFileIndexLow; - id.modules_attached_to_gmem_count = 1; //Initialize attached count - return true; -} - -inline bool compare_file_serial(int fd, const locking_file_serial_id &id) -{ - winapi::interprocess_by_handle_file_information info; - if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info)) - return false; - - return id.dwVolumeSerialNumber == info.dwVolumeSerialNumber && - id.nFileIndexHigh == info.nFileIndexHigh && - id.nFileIndexLow == info.nFileIndexLow; -} - -#else //UNIX - -struct locking_file_serial_id -{ - int fd; - dev_t st_dev; - ino_t st_ino; - //This reference count counts the number of modules attached - //to the shared memory and lock file. This serves to unlink - //the locking file and shared memory when all modules are - //done with the global memory (shared memory) - volatile boost::uint32_t modules_attached_to_gmem_count; -}; - -inline bool lock_locking_file(int fd) -{ - int ret = 0; - while(ret != 0 && errno != EINTR){ - struct flock lock; - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 1; - ret = fcntl (fd, F_SETLKW, &lock); - } - return 0 == ret; -} - -inline bool try_lock_locking_file(int fd) -{ - struct flock lock; - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 1; - return 0 == fcntl (fd, F_SETLK, &lock); -} - -inline int open_or_create_and_lock_file(const char *name) -{ - permissions p; - p.set_unrestricted(); - while(1){ - int fd = create_or_open_file(name, read_write, p); - if(fd < 0){ - return fd; - } - if(!try_lock_locking_file(fd)){ - close(fd); - return -1; - } - struct stat s; - if(0 == stat(name, &s)){ - return fd; - } - else{ - close(fd); - } - } -} - -inline int try_open_and_lock_file(const char *name) -{ - int fd = open_existing_file(name, read_write); - if(fd < 0){ - return fd; - } - if(!try_lock_locking_file(fd)){ - close(fd); - return -1; - } - return fd; -} - -inline void close_lock_file(int fd) -{ close(fd); } - -inline bool is_valid_fd(int fd) -{ - struct stat s; - return EBADF != fstat(fd, &s); -} - -inline bool is_normal_file(int fd) -{ - struct stat s; - if(0 != fstat(fd, &s)) - return false; - return 0 != (s.st_mode & S_IFREG); -} - -inline std::size_t get_size(int fd) -{ - struct stat s; - if(0 != fstat(fd, &s)) - return 0u; - return (std::size_t)s.st_size; -} - -inline bool fill_file_serial_id(int fd, locking_file_serial_id &id) -{ - struct stat s; - if(0 != fstat(fd, &s)) - return false; - id.fd = fd; - id.st_dev = s.st_dev; - id.st_ino = s.st_ino; - id.modules_attached_to_gmem_count = 1; //Initialize attached count - return true; -} - -inline bool compare_file_serial(int fd, const locking_file_serial_id &id) -{ - struct stat info; - if(0 != fstat(fd, &info)) - return false; - - return id.st_dev == info.st_dev && - id.st_ino == info.st_ino; -} - -#endif - -template<class ManagedShMem> -struct gmem_erase_func -{ - gmem_erase_func(const char *shm_name, const char *singleton_lock_file_path, ManagedShMem & shm) - :shm_name_(shm_name), singleton_lock_file_path_(singleton_lock_file_path), shm_(shm) - {} - - void operator()() - { - locking_file_serial_id *pserial_id = shm_.template find<locking_file_serial_id>("lock_file_fd").first; - if(pserial_id){ - pserial_id->fd = GMemMarkToBeRemoved; - } - delete_file(singleton_lock_file_path_); - shared_memory_object::remove(shm_name_); - } - - const char * const shm_name_; - const char * const singleton_lock_file_path_; - ManagedShMem & shm_; -}; - -//This function applies shared memory erasure logic based on the passed lock file. -template<class ManagedShMem> -void managed_sh_dependant<ManagedShMem>:: - apply_gmem_erase_logic(const char *filepath, const char *filename) -{ - int fd = GMemMarkToBeRemoved; - try{ - std::string str; - //If the filename is current process lock file, then avoid it - if(file_locking_helpers::check_if_filename_complies_with_pid - (filename, get_lock_file_base_name(), get_current_process_id(), str, true)){ - return; - } - //Open and lock the other process' lock file - fd = try_open_and_lock_file(filepath); - if(fd < 0){ - return; - } - //If done, then the process is dead so take global shared memory name - //(the name is based on the lock file name) and try to apply erasure logic - str.insert(0, get_shm_base_name()); - try{ - ManagedShMem shm(open_only, str.c_str()); - gmem_erase_func<ManagedShMem> func(str.c_str(), filepath, shm); - shm.try_atomic_func(func); - } - catch(interprocess_exception &e){ - //If shared memory is not found erase the lock file - if(e.get_error_code() == not_found_error){ - delete_file(filepath); - } - } - } - catch(...){ - - } - if(fd >= 0){ - close_lock_file(fd); - } -} - -} //namespace intermodule_singleton_helpers { - - - -namespace intermodule_singleton_helpers { - -//The lock file logic creates uses a unique instance to a file -template <class ManagedShMem> -struct lock_file_logic -{ - lock_file_logic(ManagedShMem &shm) - : mshm(shm) - { shm.atomic_func(*this); } - - void operator()(void) - { - retry_with_new_shm = false; - - //First find the file locking descriptor id - locking_file_serial_id *pserial_id = - mshm.template find<locking_file_serial_id>("lock_file_fd").first; - - int fd; - //If not found schedule a creation - if(!pserial_id){ - fd = GMemNotPresent; - } - //Else get it - else{ - fd = pserial_id->fd; - } - //If we need to create a new one, do it - if(fd == GMemNotPresent){ - std::string lck_str; - //Create a unique current pid based lock file path - create_and_get_singleton_lock_file_path(lck_str); - //Open or create and lock file - int fd = intermodule_singleton_helpers::open_or_create_and_lock_file(lck_str.c_str()); - //If failed, write a bad file descriptor to notify other modules that - //something was wrong and unlink shared memory. Mark the function object - //to tell caller to retry with another shared memory - if(fd < 0){ - this->register_lock_file(GMemMarkToBeRemoved); - std::string s; - get_shm_name(s); - shared_memory_object::remove(s.c_str()); - retry_with_new_shm = true; - } - //If successful, register the file descriptor - else{ - this->register_lock_file(fd); - } - } - //If the fd was invalid (maybe a previous try failed) notify caller that - //should retry creation logic, since this shm might have been already - //unlinked since the shm was removed - else if (fd == GMemMarkToBeRemoved){ - retry_with_new_shm = true; - } - //If the stored fd is not valid (a open fd, a normal file with the - //expected size, or does not have the same file id number, - //then it's an old shm from an old process with the same pid. - //If that's the case, mark it as invalid - else if(!is_valid_fd(fd) || - !is_normal_file(fd) || - 0 != get_size(fd) || - !compare_file_serial(fd, *pserial_id)){ - pserial_id->fd = GMemMarkToBeRemoved; - std::string s; - get_shm_name(s); - shared_memory_object::remove(s.c_str()); - retry_with_new_shm = true; - } - else{ - //If the lock file is ok, increment reference count of - //attached modules to shared memory - atomic_inc32(&pserial_id->modules_attached_to_gmem_count); - } - } - - private: - locking_file_serial_id * register_lock_file(int fd) - { - locking_file_serial_id *pinfo = mshm.template construct<locking_file_serial_id>("lock_file_fd")(); - fill_file_serial_id(fd, *pinfo); - return pinfo; - } - - public: - ManagedShMem &mshm; - bool retry_with_new_shm; -}; - -#if defined(BOOST_INTERPROCESS_WINDOWS) - -template<> -struct lock_file_logic<windows_managed_global_memory> -{ - lock_file_logic(windows_managed_global_memory &) - : retry_with_new_shm(false) - {} - - void operator()(void){} - const bool retry_with_new_shm; -}; - -#endif - -} //namespace intermodule_singleton_helpers { - -//This class contains common code for all singleton types, so that we instantiate this -//code just once per module. This class also holds a reference counted shared memory -//to be used by all instances - -template<class ManagedShMem> -class intermodule_singleton_common -{ - public: - typedef void*(singleton_constructor_t)(ManagedShMem &); - typedef void (singleton_destructor_t)(void *, ManagedShMem &); - - static const ::boost::uint32_t Uninitialized = 0u; - static const ::boost::uint32_t Initializing = 1u; - static const ::boost::uint32_t Initialized = 2u; - static const ::boost::uint32_t Broken = 3u; - - static void finalize_singleton_logic(void *ptr, singleton_destructor_t destructor) - { - if(ptr) - destructor(ptr, get_shm()); - //If this is the last singleton of this module - //apply shm destruction. - //Note: singletons are destroyed when the module is unloaded - //so no threads should be executing or holding references - //to this module - if(1 == atomic_dec32(&this_module_singleton_count)){ - destroy_shm(); - } - } - - static void initialize_singleton_logic - (void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_constructor_t ini_func); - - private: - static ManagedShMem &get_shm() - { - return *static_cast<ManagedShMem *>(static_cast<void *>(&mem_holder.shm_mem)); - } - - static void initialize_shm(); - static void destroy_shm(); - //Static data, zero-initalized without any dependencies - //this_module_singleton_count is the number of singletons used by this module - static volatile boost::uint32_t this_module_singleton_count; - //this_module_shm_initialized is the state of this module's shm class object - static volatile boost::uint32_t this_module_shm_initialized; - static struct mem_holder_t - { - ::boost::detail::max_align aligner; - char shm_mem [sizeof(ManagedShMem)]; - } mem_holder; -}; - -template<class ManagedShMem> -volatile boost::uint32_t intermodule_singleton_common<ManagedShMem>::this_module_singleton_count; - -template<class ManagedShMem> -volatile boost::uint32_t intermodule_singleton_common<ManagedShMem>::this_module_shm_initialized; - -template<class ManagedShMem> -typename intermodule_singleton_common<ManagedShMem>::mem_holder_t - intermodule_singleton_common<ManagedShMem>::mem_holder; - -template<class ManagedShMem> -void intermodule_singleton_common<ManagedShMem>::initialize_shm() -{ - //Obtain unique shm name and size - std::string s; - while(1){ - //Try to pass shm state to initializing - ::boost::uint32_t tmp = atomic_cas32(&this_module_shm_initialized, Initializing, Uninitialized); - if(tmp >= Initialized){ - break; - } - //If some other thread is doing the work wait - else if(tmp == Initializing){ - thread_yield(); - } - else{ //(tmp == Uninitialized) - //If not initialized try it again? - try{ - //Remove old shared memory from the system - intermodule_singleton_helpers::managed_sh_dependant<ManagedShMem>::remove_old_gmem(); - // - if(s.empty()){ - intermodule_singleton_helpers::get_shm_name(s); - } - const char *ShmName = s.c_str(); - const std::size_t ShmSize = intermodule_singleton_helpers::get_shm_size();; - - //in-place construction of the shared memory class - ::new (&get_shm())ManagedShMem(open_or_create, ShmName, ShmSize); - //Use shared memory internal lock to initialize the lock file - //that will mark this gmem as "in use". - intermodule_singleton_helpers::lock_file_logic<ManagedShMem> f(get_shm()); - //If function failed (maybe a competing process has erased the shared - //memory between creation and file locking), retry with a new instance. - if(f.retry_with_new_shm){ - get_shm().~ManagedShMem(); - atomic_write32(&this_module_shm_initialized, Uninitialized); - } - else{ - //Locking succeeded, so this shared memory module-instance is ready - atomic_write32(&this_module_shm_initialized, Initialized); - break; - } - } - catch(...){ - // - throw; - } - } - } -} - -template<class ManagedShMem> -struct unlink_shmlogic -{ - unlink_shmlogic(ManagedShMem &mshm) - : mshm_(mshm) - { mshm.atomic_func(*this); } - void operator()() - { - intermodule_singleton_helpers::locking_file_serial_id *pserial_id = - mshm_.template find<intermodule_singleton_helpers::locking_file_serial_id> - ("lock_file_fd").first; - BOOST_ASSERT(0 != pserial_id); - if(1 == atomic_dec32(&pserial_id->modules_attached_to_gmem_count)){ - int fd = pserial_id->fd; - if(fd > 0){ - pserial_id->fd = intermodule_singleton_helpers::GMemMarkToBeRemoved; - std::string s; - intermodule_singleton_helpers::create_and_get_singleton_lock_file_path(s); - delete_file(s.c_str()); - intermodule_singleton_helpers::close_lock_file(fd); - intermodule_singleton_helpers::get_shm_name(s); - shared_memory_object::remove(s.c_str()); - } - } - } - ManagedShMem &mshm_; -}; - -#if defined(BOOST_INTERPROCESS_WINDOWS) - -template<> -struct unlink_shmlogic<windows_managed_global_memory> -{ - unlink_shmlogic(windows_managed_global_memory &) - {} - void operator()(){} -}; - -#endif - - -template<class ManagedShMem> -void intermodule_singleton_common<ManagedShMem>::destroy_shm() -{ - if(!atomic_read32(&this_module_singleton_count)){ - //This module is being unloaded, so destroy - //the shared memory object of this module - //and unlink the shared memory if it's the last - unlink_shmlogic<ManagedShMem> f(get_shm()); - (get_shm()).~ManagedShMem(); - atomic_write32(&this_module_shm_initialized, Uninitialized); - //Do some cleanup for other processes old gmem instances - intermodule_singleton_helpers::managed_sh_dependant<ManagedShMem>::remove_old_gmem(); - } -} - -//Initialize this_module_singleton_ptr, creates the shared memory if needed and also creates an unique -//opaque type in shared memory through a singleton_constructor_t function call, -//initializing the passed pointer to that unique instance. -// -//We have two concurrency types here. a)the shared memory/singleton creation must -//be safe between threads of this process but in different modules/dlls. b) -//the pointer to the singleton is per-module, so we have to protect this -//initization between threads of the same module. -// -//All static variables declared here are shared between inside a module -//so atomic operations will synchronize only threads of the same module. -template<class ManagedShMem> -void intermodule_singleton_common<ManagedShMem>::initialize_singleton_logic - (void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_constructor_t constructor) -{ - //If current module is not initialized enter to lock free logic - if(atomic_read32(&this_module_singleton_initialized) != Initialized){ - //Now a single thread of the module will succeed in this CAS. - //trying to pass from Uninitialized to Initializing - ::boost::uint32_t previous_module_singleton_initialized = atomic_cas32 - (&this_module_singleton_initialized, Initializing, Uninitialized); - //If the thread succeeded the CAS (winner) it will compete with other - //winner threads from other modules to create the shared memory - if(previous_module_singleton_initialized == Uninitialized){ - try{ - //Now initialize shm, this function solves concurrency issues - //between threads of several modules - initialize_shm(); - //Increment the module reference count that reflects how many - //singletons this module holds, so that we can safely destroy - //module shared memory object when no singleton is left - atomic_inc32(&this_module_singleton_count); - //Now try to create the singleton in shared memory. - //This function solves concurrency issues - //between threads of several modules - void *tmp = constructor(get_shm()); - //Insert a barrier before assigning the pointer to - //make sure this assignment comes after the initialization - atomic_write32(&this_module_singleton_initialized, Initializing); - //Assign the singleton address to the module-local pointer - ptr = tmp; - //Memory barrier inserted, all previous operations should complete - //before this one. Now marked as initialized - atomic_inc32(&this_module_singleton_initialized); - } - catch(...){ - //Mark singleton failed to initialize - atomic_write32(&this_module_singleton_initialized, Broken); - throw; - } - } - //If previous state was initializing, this means that another winner thread is - //trying to initialize the singleton. Just wait until completes its work. - else if(previous_module_singleton_initialized == Initializing){ - while(1){ - previous_module_singleton_initialized = atomic_read32(&this_module_singleton_initialized); - if(previous_module_singleton_initialized >= Initialized){ - //Already initialized, or exception thrown by initializer thread - break; - } - else if(previous_module_singleton_initialized == Initializing){ - thread_yield(); - } - else{ - //This can't be happening! - BOOST_ASSERT(0); - } - } - } - else if(previous_module_singleton_initialized == Initialized){ - //Nothing to do here, the singleton is ready - } - //If previous state was greater than initialized, then memory is broken - //trying to initialize the singleton. - else{//(previous_module_singleton_initialized > Initialized) - throw interprocess_exception("boost::interprocess::intermodule_singleton initialization failed"); - } - } - BOOST_ASSERT(ptr != 0); -} - -//Now this class is a singleton, initializing the singleton in -//the first get() function call if LazyInit is false. If true -//then the singleton will be initialized when loading the module. -template<typename C, bool LazyInit, class ManagedShMem> -class intermodule_singleton_impl -{ - public: - static C& get() //Let's make inlining easy - { - if(!this_module_singleton_ptr){ - if(lifetime.dummy_function()) //This forces lifetime instantiation, for reference counted destruction - intermodule_singleton_common<ManagedShMem>::initialize_singleton_logic - (this_module_singleton_ptr, this_module_singleton_initialized, singleton_constructor); - } - return *static_cast<C*>(this_module_singleton_ptr); - } - - private: - - struct ref_count_ptr - { - ref_count_ptr(C *p, boost::uint32_t count) - : ptr(p), singleton_ref_count(count) - {} - C *ptr; - //This reference count serves to count the number of attached - //modules to this singleton - volatile boost::uint32_t singleton_ref_count; - }; - - //These statics will be zero-initialized without any constructor call dependency - //this_module_singleton_ptr will be a module-local pointer to the singleton - static void* this_module_singleton_ptr; - //this_module_singleton_count will be used to synchronize threads of the same module - //for access to a singleton instance, and to flag the state of the - //singleton. - static volatile boost::uint32_t this_module_singleton_initialized; - - //This class destructor will trigger singleton destruction - struct lifetime_type_lazy - { - bool dummy_function() - { return m_dummy == 0; } - - ~lifetime_type_lazy() - { - intermodule_singleton_common<ManagedShMem>::finalize_singleton_logic - (this_module_singleton_ptr, singleton_destructor); - } - //Dummy volatile so that the compiler can't resolve its value at compile-time - //and can't avoid lifetime_type instantiation if dummy_function() is called. - static volatile int m_dummy; - }; - - struct lifetime_type_static - : public lifetime_type_lazy - { - lifetime_type_static() - { - intermodule_singleton_common<ManagedShMem>::initialize_singleton_logic - (this_module_singleton_ptr, this_module_singleton_initialized, singleton_constructor); - } - }; - - typedef typename if_c - <LazyInit, lifetime_type_lazy, lifetime_type_static>::type lifetime_type; - - static lifetime_type lifetime; - - //A functor to be executed inside shared memory lock that just - //searches for the singleton in shm and if not present creates a new one. - //If singleton constructor throws, the exception is propagated - struct init_atomic_func - { - init_atomic_func(ManagedShMem &m) - : mshm(m) - {} - - void operator()() - { - ref_count_ptr *rcount = mshm.template find<ref_count_ptr>(unique_instance).first; - if(!rcount){ - C *p = new C(); - try{ - rcount = mshm.template construct<ref_count_ptr>(unique_instance)(p, 0u); - } - catch(...){ - delete p; - throw; - } - } - atomic_inc32(&rcount->singleton_ref_count); - ret_ptr = rcount->ptr; - } - ManagedShMem &mshm; - void *ret_ptr; - }; - - //A functor to be executed inside shared memory lock that just - //deletes the singleton in shm if the attached count reaches to zero - struct fini_atomic_func - { - fini_atomic_func(ManagedShMem &m) - : mshm(m) - {} - - void operator()() - { - ref_count_ptr *rcount = mshm.template find<ref_count_ptr>(unique_instance).first; - //The object must exist - BOOST_ASSERT(rcount); - //Check if last reference - if(atomic_dec32(&rcount->singleton_ref_count) == 1){ - //If last, destroy the object - BOOST_ASSERT(rcount->ptr != 0); - delete rcount->ptr; - //Now destroy shm entry - bool destroyed = mshm.template destroy<ref_count_ptr>(unique_instance); - (void)destroyed; BOOST_ASSERT(destroyed == true); - } - } - ManagedShMem &mshm; - void *ret_ptr; - }; - - //A wrapper to execute init_atomic_func - static void *singleton_constructor(ManagedShMem &mshm) - { - init_atomic_func f(mshm); - mshm.atomic_func(f); - return f.ret_ptr; - } - - //A wrapper to execute fini_atomic_func - static void singleton_destructor(void *p, ManagedShMem &mshm) - { (void)p; - fini_atomic_func f(mshm); - mshm.atomic_func(f); - } -}; - -template <typename C, bool L, class ManagedShMem> -volatile int intermodule_singleton_impl<C, L, ManagedShMem>::lifetime_type_lazy::m_dummy = 0; - -//These will be zero-initialized by the loader -template <typename C, bool L, class ManagedShMem> -void *intermodule_singleton_impl<C, L, ManagedShMem>::this_module_singleton_ptr = 0; - -template <typename C, bool L, class ManagedShMem> -volatile boost::uint32_t intermodule_singleton_impl<C, L, ManagedShMem>::this_module_singleton_initialized = 0; - -template <typename C, bool L, class ManagedShMem> -typename intermodule_singleton_impl<C, L, ManagedShMem>::lifetime_type - intermodule_singleton_impl<C, L, ManagedShMem>::lifetime; - -template<typename C, bool LazyInit = false> -class portable_intermodule_singleton - : public intermodule_singleton_impl<C, LazyInit, managed_global_memory> -{}; - -#if defined(BOOST_INTERPROCESS_WINDOWS) - -template<typename C, bool LazyInit = false> -class windows_intermodule_singleton - : public intermodule_singleton_impl - < C - , LazyInit - , windows_managed_global_memory - > -{}; - -#endif - //Now this class is a singleton, initializing the singleton in //the first get() function call if LazyInit is false. If true //then the singleton will be initialized when loading the module. -template<typename C, bool LazyInit = false> +template<typename C, bool LazyInit = true, bool Phoenix = true> class intermodule_singleton #ifdef BOOST_INTERPROCESS_WINDOWS - : public windows_intermodule_singleton<C, LazyInit> + : public windows_intermodule_singleton<C, LazyInit, Phoenix> #else - : public portable_intermodule_singleton<C, LazyInit> + : public portable_intermodule_singleton<C, LazyInit, Phoenix> #endif {}; - } //namespace ipcdetail{ } //namespace interprocess{ } //namespace boost{ diff --git a/boost/interprocess/detail/intermodule_singleton_common.hpp b/boost/interprocess/detail/intermodule_singleton_common.hpp new file mode 100644 index 0000000000..0710c0bbc1 --- /dev/null +++ b/boost/interprocess/detail/intermodule_singleton_common.hpp @@ -0,0 +1,495 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_INTERMODULE_SINGLETON_COMMON_HPP +#define BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_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/atomic.hpp> +#include <boost/interprocess/detail/os_thread_functions.hpp> +#include <boost/type_traits/type_with_alignment.hpp> +#include <boost/interprocess/detail/mpl.hpp> +#include <boost/assert.hpp> +#include <cstddef> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <string> +#include <sstream> + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +namespace intermodule_singleton_helpers { + +inline void get_pid_creation_time_str(std::string &s) +{ + std::stringstream stream; + stream << get_current_process_id() << '_'; + stream.precision(6); + stream << std::fixed << get_current_process_creation_time(); + s = stream.str(); +} + +inline const char *get_map_base_name() +{ return "bip.gmem.map."; } + +inline void get_map_name(std::string &map_name) +{ + get_pid_creation_time_str(map_name); + map_name.insert(0, get_map_base_name()); +} + +inline std::size_t get_map_size() +{ return 65536; } + +template<class ThreadSafeGlobalMap> +struct thread_safe_global_map_dependant; + +} //namespace intermodule_singleton_helpers { + +//This class contains common code for all singleton types, so that we instantiate this +//code just once per module. This class also holds a thread soafe global map +//to be used by all instances protected with a reference count +template<class ThreadSafeGlobalMap> +class intermodule_singleton_common +{ + public: + typedef void*(singleton_constructor_t)(ThreadSafeGlobalMap &); + typedef void (singleton_destructor_t)(void *, ThreadSafeGlobalMap &); + + static const ::boost::uint32_t Uninitialized = 0u; + static const ::boost::uint32_t Initializing = 1u; + static const ::boost::uint32_t Initialized = 2u; + static const ::boost::uint32_t Broken = 3u; + static const ::boost::uint32_t Destroyed = 4u; + + //Initialize this_module_singleton_ptr, creates the global map if needed and also creates an unique + //opaque type in global map through a singleton_constructor_t function call, + //initializing the passed pointer to that unique instance. + // + //We have two concurrency types here. a)the global map/singleton creation must + //be safe between threads of this process but in different modules/dlls. b) + //the pointer to the singleton is per-module, so we have to protect this + //initization between threads of the same module. + // + //All static variables declared here are shared between inside a module + //so atomic operations will synchronize only threads of the same module. + static void initialize_singleton_logic + (void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_constructor_t constructor, bool phoenix) + { + //If current module is not initialized enter to lock free logic + if(atomic_read32(&this_module_singleton_initialized) != Initialized){ + //Now a single thread of the module will succeed in this CAS. + //trying to pass from Uninitialized to Initializing + ::boost::uint32_t previous_module_singleton_initialized = atomic_cas32 + (&this_module_singleton_initialized, Initializing, Uninitialized); + //If the thread succeeded the CAS (winner) it will compete with other + //winner threads from other modules to create the global map + if(previous_module_singleton_initialized == Destroyed){ + //Trying to resurrect a dead Phoenix singleton. Just try to + //mark it as uninitialized and start again + if(phoenix){ + atomic_cas32(&this_module_singleton_initialized, Uninitialized, Destroyed); + previous_module_singleton_initialized = atomic_cas32 + (&this_module_singleton_initialized, Initializing, Uninitialized); + } + //Trying to resurrect a non-Phoenix dead singleton is an error + else{ + throw interprocess_exception("Boost.Interprocess: Dead reference on non-Phoenix singleton of type"); + } + } + if(previous_module_singleton_initialized == Uninitialized){ + try{ + //Now initialize the global map, this function must solve concurrency + //issues between threads of several modules + initialize_global_map_handle(); + //Now try to create the singleton in global map. + //This function solves concurrency issues + //between threads of several modules + void *tmp = constructor(get_map()); + //Increment the module reference count that reflects how many + //singletons this module holds, so that we can safely destroy + //module global map object when no singleton is left + atomic_inc32(&this_module_singleton_count); + //Insert a barrier before assigning the pointer to + //make sure this assignment comes after the initialization + atomic_write32(&this_module_singleton_initialized, Initializing); + //Assign the singleton address to the module-local pointer + ptr = tmp; + //Memory barrier inserted, all previous operations should complete + //before this one. Now marked as initialized + atomic_write32(&this_module_singleton_initialized, Initialized); + } + catch(...){ + //Mark singleton failed to initialize + atomic_write32(&this_module_singleton_initialized, Broken); + throw; + } + } + //If previous state was initializing, this means that another winner thread is + //trying to initialize the singleton. Just wait until completes its work. + else if(previous_module_singleton_initialized == Initializing){ + while(1){ + previous_module_singleton_initialized = atomic_read32(&this_module_singleton_initialized); + if(previous_module_singleton_initialized >= Initialized){ + //Already initialized, or exception thrown by initializer thread + break; + } + else if(previous_module_singleton_initialized == Initializing){ + thread_yield(); + } + else{ + //This can't be happening! + BOOST_ASSERT(0); + } + } + } + else if(previous_module_singleton_initialized == Initialized){ + //Nothing to do here, the singleton is ready + } + //If previous state was greater than initialized, then memory is broken + //trying to initialize the singleton. + else{//(previous_module_singleton_initialized > Initialized) + throw interprocess_exception("boost::interprocess::intermodule_singleton initialization failed"); + } + } + BOOST_ASSERT(ptr != 0); + } + + static void finalize_singleton_logic(void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_destructor_t destructor) + { + //Protect destruction against lazy singletons not initialized in this execution + if(ptr){ + //Note: this destructor might provoke a Phoenix singleton + //resurrection. This means that this_module_singleton_count + //might change after this call. + destructor(ptr, get_map()); + ptr = 0; + + //Memory barrier to make sure pointer is nulled. + //Mark this singleton as destroyed. + atomic_write32(&this_module_singleton_initialized, Destroyed); + + //If this is the last singleton of this module + //apply map destruction. + //Note: singletons are destroyed when the module is unloaded + //so no threads should be executing or holding references + //to this module + if(1 == atomic_dec32(&this_module_singleton_count)){ + destroy_global_map_handle(); + } + } + } + + private: + static ThreadSafeGlobalMap &get_map() + { + return *static_cast<ThreadSafeGlobalMap *>(static_cast<void *>(&mem_holder.map_mem)); + } + + static void initialize_global_map_handle() + { + //Obtain unique map name and size + while(1){ + //Try to pass map state to initializing + ::boost::uint32_t tmp = atomic_cas32(&this_module_map_initialized, Initializing, Uninitialized); + if(tmp == Initialized || tmp == Broken){ + break; + } + else if(tmp == Destroyed){ + tmp = atomic_cas32(&this_module_map_initialized, Uninitialized, Destroyed); + continue; + } + //If some other thread is doing the work wait + else if(tmp == Initializing){ + thread_yield(); + } + else{ //(tmp == Uninitialized) + //If not initialized try it again? + try{ + //Remove old global map from the system + intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem(); + //in-place construction of the global map class + intermodule_singleton_helpers::thread_safe_global_map_dependant + <ThreadSafeGlobalMap>::construct_map(static_cast<void*>(&get_map())); + //Use global map's internal lock to initialize the lock file + //that will mark this gmem as "in use". + typename intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>:: + lock_file_logic f(get_map()); + //If function failed (maybe a competing process has erased the shared + //memory between creation and file locking), retry with a new instance. + if(f.retry()){ + get_map().~ThreadSafeGlobalMap(); + atomic_write32(&this_module_map_initialized, Destroyed); + } + else{ + //Locking succeeded, so this global map module-instance is ready + atomic_write32(&this_module_map_initialized, Initialized); + break; + } + } + catch(...){ + // + throw; + } + } + } + } + + static void destroy_global_map_handle() + { + if(!atomic_read32(&this_module_singleton_count)){ + //This module is being unloaded, so destroy + //the global map object of this module + //and unlink the global map if it's the last + typename intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>:: + unlink_map_logic f(get_map()); + (get_map()).~ThreadSafeGlobalMap(); + atomic_write32(&this_module_map_initialized, Destroyed); + //Do some cleanup for other processes old gmem instances + intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem(); + } + } + + //Static data, zero-initalized without any dependencies + //this_module_singleton_count is the number of singletons used by this module + static volatile boost::uint32_t this_module_singleton_count; + + //this_module_map_initialized is the state of this module's map class object. + //Values: Uninitialized, Initializing, Initialized, Broken + static volatile boost::uint32_t this_module_map_initialized; + + //Raw memory to construct the global map manager + static struct mem_holder_t + { + ::boost::detail::max_align aligner; + char map_mem [sizeof(ThreadSafeGlobalMap)]; + } mem_holder; +}; + +template<class ThreadSafeGlobalMap> +volatile boost::uint32_t intermodule_singleton_common<ThreadSafeGlobalMap>::this_module_singleton_count; + +template<class ThreadSafeGlobalMap> +volatile boost::uint32_t intermodule_singleton_common<ThreadSafeGlobalMap>::this_module_map_initialized; + +template<class ThreadSafeGlobalMap> +typename intermodule_singleton_common<ThreadSafeGlobalMap>::mem_holder_t + intermodule_singleton_common<ThreadSafeGlobalMap>::mem_holder; + +//A reference count to be stored in global map holding the number +//of singletons (one per module) attached to the instance pointed by +//the internal ptr. +struct ref_count_ptr +{ + ref_count_ptr(void *p, boost::uint32_t count) + : ptr(p), singleton_ref_count(count) + {} + void *ptr; + //This reference count serves to count the number of attached + //modules to this singleton + volatile boost::uint32_t singleton_ref_count; +}; + + +//Now this class is a singleton, initializing the singleton in +//the first get() function call if LazyInit is false. If true +//then the singleton will be initialized when loading the module. +template<typename C, bool LazyInit, bool Phoenix, class ThreadSafeGlobalMap> +class intermodule_singleton_impl +{ + public: + + static C& get() //Let's make inlining easy + { + if(!this_module_singleton_ptr){ + if(lifetime.dummy_function()){ //This forces lifetime instantiation, for reference counted destruction + atentry_work(); + } + } + return *static_cast<C*>(this_module_singleton_ptr); + } + + private: + + static void atentry_work() + { + intermodule_singleton_common<ThreadSafeGlobalMap>::initialize_singleton_logic + (this_module_singleton_ptr, this_module_singleton_initialized, singleton_constructor, Phoenix); + } + + static void atexit_work() + { + intermodule_singleton_common<ThreadSafeGlobalMap>::finalize_singleton_logic + (this_module_singleton_ptr, this_module_singleton_initialized, singleton_destructor); + } + + //These statics will be zero-initialized without any constructor call dependency + //this_module_singleton_ptr will be a module-local pointer to the singleton + static void* this_module_singleton_ptr; + + //this_module_singleton_count will be used to synchronize threads of the same module + //for access to a singleton instance, and to flag the state of the + //singleton. + static volatile boost::uint32_t this_module_singleton_initialized; + + //This class destructor will trigger singleton destruction + struct lifetime_type_lazy + { + bool dummy_function() + { return m_dummy == 0; } + + ~lifetime_type_lazy() + { + if(!Phoenix){ + atexit_work(); + } + } + + //Dummy volatile so that the compiler can't resolve its value at compile-time + //and can't avoid lifetime_type instantiation if dummy_function() is called. + static volatile int m_dummy; + }; + + struct lifetime_type_static + : public lifetime_type_lazy + { + lifetime_type_static() + { atentry_work(); } + }; + + typedef typename if_c + <LazyInit, lifetime_type_lazy, lifetime_type_static>::type lifetime_type; + + static lifetime_type lifetime; + + //A functor to be executed inside global map lock that just + //searches for the singleton in map and if not present creates a new one. + //If singleton constructor throws, the exception is propagated + struct init_atomic_func + { + init_atomic_func(ThreadSafeGlobalMap &m) + : m_map(m) + {} + + void operator()() + { + ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant + <ThreadSafeGlobalMap>::find(m_map, typeid(C).name()); + if(!rcount){ + C *p = new C; + try{ + ref_count_ptr val(p, 0u); + rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant + <ThreadSafeGlobalMap>::insert(m_map, typeid(C).name(), val); + } + catch(...){ + intermodule_singleton_helpers::thread_safe_global_map_dependant + <ThreadSafeGlobalMap>::erase(m_map, typeid(C).name()); + delete p; + throw; + } + } + if(Phoenix){ + std::atexit(&atexit_work); + } + atomic_inc32(&rcount->singleton_ref_count); + ret_ptr = rcount->ptr; + } + void *data() const + { return ret_ptr; } + + private: + ThreadSafeGlobalMap &m_map; + void *ret_ptr; + }; + + //A functor to be executed inside global map lock that just + //deletes the singleton in map if the attached count reaches to zero + struct fini_atomic_func + { + fini_atomic_func(ThreadSafeGlobalMap &m) + : m_map(m) + {} + + void operator()() + { + ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant + <ThreadSafeGlobalMap>::find(m_map, typeid(C).name()); + //The object must exist + BOOST_ASSERT(rcount); + BOOST_ASSERT(rcount->singleton_ref_count > 0); + //Check if last reference + if(atomic_dec32(&rcount->singleton_ref_count) == 1){ + //If last, destroy the object + BOOST_ASSERT(rcount->ptr != 0); + C *pc = static_cast<C*>(rcount->ptr); + //Now destroy map entry + bool destroyed = intermodule_singleton_helpers::thread_safe_global_map_dependant + <ThreadSafeGlobalMap>::erase(m_map, typeid(C).name()); + (void)destroyed; BOOST_ASSERT(destroyed == true); + delete pc; + } + } + void *data() const + { return ret_ptr; } + + private: + ThreadSafeGlobalMap &m_map; + void *ret_ptr; + }; + + //A wrapper to execute init_atomic_func + static void *singleton_constructor(ThreadSafeGlobalMap &map) + { + init_atomic_func f(map); + intermodule_singleton_helpers::thread_safe_global_map_dependant + <ThreadSafeGlobalMap>::atomic_func(map, f); + return f.data(); + } + + //A wrapper to execute fini_atomic_func + static void singleton_destructor(void *p, ThreadSafeGlobalMap &map) + { (void)p; + fini_atomic_func f(map); + intermodule_singleton_helpers::thread_safe_global_map_dependant + <ThreadSafeGlobalMap>::atomic_func(map, f); + } +}; + +template <typename C, bool L, bool P, class ThreadSafeGlobalMap> +volatile int intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime_type_lazy::m_dummy = 0; + +//These will be zero-initialized by the loader +template <typename C, bool L, bool P, class ThreadSafeGlobalMap> +void *intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::this_module_singleton_ptr = 0; + +template <typename C, bool L, bool P, class ThreadSafeGlobalMap> +volatile boost::uint32_t intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::this_module_singleton_initialized = 0; + +template <typename C, bool L, bool P, class ThreadSafeGlobalMap> +typename intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime_type + intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime; + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_HPP diff --git a/boost/interprocess/detail/intersegment_ptr.hpp b/boost/interprocess/detail/intersegment_ptr.hpp index 92970923d0..16d3505883 100644 --- a/boost/interprocess/detail/intersegment_ptr.hpp +++ b/boost/interprocess/detail/intersegment_ptr.hpp @@ -68,8 +68,8 @@ struct intersegment_base static const std::size_t begin_bits = max_segment_size_bits - align_bits; static const std::size_t pow_size_bits_helper = static_log2<max_segment_size_bits>::value; - static const std::size_t pow_size_bits = - (max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ? + static const std::size_t pow_size_bits = + (max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ? pow_size_bits_helper : pow_size_bits_helper + 1; static const std::size_t frc_size_bits = size_t_bits - ctrl_bits - begin_bits - pow_size_bits; @@ -177,7 +177,7 @@ struct intersegment_base void set_mode(std::size_t mode) { - BOOST_ASSERT(mode < is_max_mode); + BOOST_ASSERT(mode < is_max_mode); members.direct.ctrl = mode; } @@ -185,7 +185,7 @@ struct intersegment_base //!null pointer bool is_null() const { - return (this->get_mode() < is_relative) && + return (this->get_mode() < is_relative) && !members.direct.dummy && !members.direct.addr; } @@ -309,13 +309,13 @@ struct flat_map_intersegment void *ptr_base; void *this_base; get_segment_info_and_offset(this, this_info, this_offset, this_base); - + if(!this_info.group){ this->set_mode(is_in_stack); this->members.direct.addr = const_cast<void*>(ptr); } else{ - get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base); + get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base); if(ptr_info.group != this_info.group){ this->set_mode(is_pointee_outside); @@ -340,7 +340,7 @@ struct flat_map_intersegment } } - //!Sets the object internals to represent the address pointed + //!Sets the object internals to represent the address pointed //!by another flat_map_intersegment void set_from_other(const self_t &other) { @@ -383,7 +383,7 @@ struct flat_map_intersegment }; vector<segment_data> m_segments; multi_segment_services &m_ms_services; - + public: segment_group_t(multi_segment_services &ms_services) : m_ms_services(ms_services) @@ -434,7 +434,7 @@ struct flat_map_intersegment typedef set<segment_group_t> segment_groups_t; typedef boost::interprocess::flat_map - <const void * + <const void * ,segment_info_t ,std::less<const void *> > ptr_to_segment_info_t; @@ -443,9 +443,9 @@ struct flat_map_intersegment //!Mutex to preserve integrity in multi-threaded //!enviroments typedef Mutex mutex_type; - //!Maps base addresses and segment information + //!Maps base addresses and segment information //!(size and segment group and id)* - + ptr_to_segment_info_t m_ptr_to_segment_info; ~mappings_t() @@ -476,7 +476,7 @@ struct flat_map_intersegment return; } //Find the first base address greater than ptr - typename ptr_to_segment_info_t::iterator it + typename ptr_to_segment_info_t::iterator it = s_map.m_ptr_to_segment_info.upper_bound(ptr); if(it == s_map.m_ptr_to_segment_info.begin()){ segment = segment_info_t(); @@ -486,7 +486,7 @@ struct flat_map_intersegment --it; char * segment_base = const_cast<char*>(reinterpret_cast<const char*>(it->first)); std::size_t segment_size = it->second.size; - + if(segment_base <= reinterpret_cast<const char*>(ptr) && (segment_base + segment_size) >= reinterpret_cast<const char*>(ptr)){ segment = it->second; @@ -552,7 +552,7 @@ struct flat_map_intersegment s_groups.insert(segment_group_t(*services)); BOOST_ASSERT(ret.second); return &*ret.first; - } + } } static bool delete_group(segment_group_id id) @@ -574,23 +574,23 @@ struct flat_map_intersegment } } return success; - } + } } }; //!Static map-segment_info associated with //!flat_map_intersegment<> template <class Mutex> -typename flat_map_intersegment<Mutex>::mappings_t +typename flat_map_intersegment<Mutex>::mappings_t flat_map_intersegment<Mutex>::s_map; //!Static segment group container associated with //!flat_map_intersegment<> template <class Mutex> -typename flat_map_intersegment<Mutex>::segment_groups_t +typename flat_map_intersegment<Mutex>::segment_groups_t flat_map_intersegment<Mutex>::s_groups; -//!A smart pointer that can point to a pointee that resides in another memory +//!A smart pointer that can point to a pointee that resides in another memory //!memory mapped or shared memory segment. template <class T> class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> @@ -623,13 +623,13 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> //!Constructor from other intersegment_ptr //!Never throws - intersegment_ptr(const intersegment_ptr& ptr) + intersegment_ptr(const intersegment_ptr& ptr) { base_t::set_from_other(ptr); } - //!Constructor from other intersegment_ptr. If pointers of pointee types are + //!Constructor from other intersegment_ptr. If pointers of pointee types are //!convertible, intersegment_ptrs will be convertibles. Never throws. template<class T2> - intersegment_ptr(const intersegment_ptr<T2> &ptr) + intersegment_ptr(const intersegment_ptr<T2> &ptr) { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); } //!Emulates static_cast operator. @@ -663,17 +663,17 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> //!Pointer-like -> operator. It can return 0 pointer. //!Never throws. - pointer operator->() const + pointer operator->() const { return self_t::get(); } - //!Dereferencing operator, if it is a null intersegment_ptr behavior + //!Dereferencing operator, if it is a null intersegment_ptr behavior //!is undefined. Never throws. - reference operator* () const + reference operator* () const { return *(self_t::get()); } //!Indexing operator. //!Never throws. - reference operator[](std::ptrdiff_t idx) const + reference operator[](std::ptrdiff_t idx) const { return self_t::get()[idx]; } //!Assignment from pointer (saves extra conversion). @@ -686,19 +686,19 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> intersegment_ptr& operator= (const intersegment_ptr &ptr) { base_t::set_from_other(ptr); return *this; } - //!Assignment from related intersegment_ptr. If pointers of pointee types + //!Assignment from related intersegment_ptr. If pointers of pointee types //!are assignable, intersegment_ptrs will be assignable. Never throws. template <class T2> intersegment_ptr& operator= (const intersegment_ptr<T2> & ptr) - { - pointer p(ptr.get()); (void)p; - base_t::set_from_other(ptr); return *this; + { + pointer p(ptr.get()); (void)p; + base_t::set_from_other(ptr); return *this; } - + //!intersegment_ptr + std::ptrdiff_t. //!Never throws. - intersegment_ptr operator+ (std::ptrdiff_t idx) const - { + intersegment_ptr operator+ (std::ptrdiff_t idx) const + { intersegment_ptr result (*this); result.inc_offset(idx*sizeof(T)); return result; @@ -706,8 +706,8 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> //!intersegment_ptr - std::ptrdiff_t. //!Never throws. - intersegment_ptr operator- (std::ptrdiff_t idx) const - { + intersegment_ptr operator- (std::ptrdiff_t idx) const + { intersegment_ptr result (*this); result.dec_offset(idx*sizeof(T)); return result; @@ -727,7 +727,7 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> //!Never throws. intersegment_ptr& operator++ (void) { base_t::inc_offset(sizeof(T)); return *this; } - + //!intersegment_ptr++. //!Never throws. intersegment_ptr operator++ (int) @@ -745,10 +745,10 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> //!Safe bool conversion operator. //!Never throws. - operator unspecified_bool_type() const + operator unspecified_bool_type() const { return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func; } - //!Not operator. Not needed in theory, but improves portability. + //!Not operator. Not needed in theory, but improves portability. //!Never throws. bool operator! () const { return base_t::is_null(); } @@ -784,12 +784,12 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> template <class T1, class T2> inline bool operator ==(const intersegment_ptr<T1> &left, const intersegment_ptr<T2> &right) -{ +{ //Make sure both pointers can be compared bool e = typename intersegment_ptr<T1>::pointer(0) == typename intersegment_ptr<T2>::pointer(0); (void)e; - return left._equal(right); + return left._equal(right); } //!Returns true if *this is less than other. @@ -798,74 +798,74 @@ bool operator ==(const intersegment_ptr<T1> &left, template <class T1, class T2> inline bool operator <(const intersegment_ptr<T1> &left, const intersegment_ptr<T2> &right) -{ +{ //Make sure both pointers can be compared bool e = typename intersegment_ptr<T1>::pointer(0) < typename intersegment_ptr<T2>::pointer(0); (void)e; - return left._less(right); + return left._less(right); } template<class T1, class T2> inline -bool operator!= (const intersegment_ptr<T1> &pt1, +bool operator!= (const intersegment_ptr<T1> &pt1, const intersegment_ptr<T2> &pt2) { return !(pt1 ==pt2); } //!intersegment_ptr<T1> <= intersegment_ptr<T2>. //!Never throws. template<class T1, class T2> inline -bool operator<= (const intersegment_ptr<T1> &pt1, +bool operator<= (const intersegment_ptr<T1> &pt1, const intersegment_ptr<T2> &pt2) { return !(pt1 > pt2); } //!intersegment_ptr<T1> > intersegment_ptr<T2>. //!Never throws. template<class T1, class T2> inline -bool operator> (const intersegment_ptr<T1> &pt1, +bool operator> (const intersegment_ptr<T1> &pt1, const intersegment_ptr<T2> &pt2) { return (pt2 < pt1); } //!intersegment_ptr<T1> >= intersegment_ptr<T2>. //!Never throws. template<class T1, class T2> inline -bool operator>= (const intersegment_ptr<T1> &pt1, +bool operator>= (const intersegment_ptr<T1> &pt1, const intersegment_ptr<T2> &pt2) { return !(pt1 < pt2); } //!operator<< template<class E, class T, class U> inline -std::basic_ostream<E, T> & operator<< +std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, const intersegment_ptr<U> & p) { return os << p.get(); } //!operator>> template<class E, class T, class U> inline -std::basic_istream<E, T> & operator>> +std::basic_istream<E, T> & operator>> (std::basic_istream<E, T> & os, intersegment_ptr<U> & p) { U * tmp; return os >> tmp; p = tmp; } -//!std::ptrdiff_t + intersegment_ptr. +//!std::ptrdiff_t + intersegment_ptr. //!The result is another pointer of the same segment template<class T> inline intersegment_ptr<T> operator+ (std::ptrdiff_t diff, const intersegment_ptr<T>& right) { return right + diff; } -//!intersegment_ptr - intersegment_ptr. +//!intersegment_ptr - intersegment_ptr. //!This only works with two intersegment_ptr-s that point to the //!same segment template <class T, class T2> inline -std::ptrdiff_t operator- (const intersegment_ptr<T> &pt, +std::ptrdiff_t operator- (const intersegment_ptr<T> &pt, const intersegment_ptr<T2> &pt2) { return pt._diff(pt2)/sizeof(T); } //! swap specialization template<class T> inline -void swap (boost::interprocess::intersegment_ptr<T> &pt, +void swap (boost::interprocess::intersegment_ptr<T> &pt, boost::interprocess::intersegment_ptr<T> &pt2) { pt.swap(pt2); } -//!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr. +//!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr. //!Never throws. template<class T> inline T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p) @@ -873,19 +873,19 @@ T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p) //!Simulation of static_cast between pointers. //!Never throws. -template<class T, class U> inline +template<class T, class U> inline boost::interprocess::intersegment_ptr<T> static_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r) { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::static_cast_tag()); } //!Simulation of const_cast between pointers. //!Never throws. -template<class T, class U> inline +template<class T, class U> inline boost::interprocess::intersegment_ptr<T> const_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r) { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::const_cast_tag()); } //!Simulation of dynamic_cast between pointers. //!Never throws. -template<class T, class U> inline +template<class T, class U> inline boost::interprocess::intersegment_ptr<T> dynamic_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r) { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::dynamic_cast_tag()); } @@ -895,7 +895,7 @@ template<class T, class U> inline boost::interprocess::intersegment_ptr<T> reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r) { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::reinterpret_cast_tag()); } -//!Trait class to detect if an smart pointer has +//!Trait class to detect if an smart pointer has //!multi-segment addressing capabilities. template <class T> struct is_multisegment_ptr @@ -907,7 +907,7 @@ struct is_multisegment_ptr } //namespace interprocess { #if defined(_MSC_VER) && (_MSC_VER < 1400) -//!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr. +//!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr. //!Never throws. template<class T> inline T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p) @@ -918,14 +918,14 @@ T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p) //!for optimizations template <class T> struct has_trivial_constructor - < boost::interprocess::intersegment_ptr<T> > + < boost::interprocess::intersegment_ptr<T> > : public true_type{}; //!has_trivial_destructor<> == true_type specialization //!for optimizations template <class T> struct has_trivial_destructor - < boost::interprocess::intersegment_ptr<T> > + < boost::interprocess::intersegment_ptr<T> > : public true_type{}; } //namespace boost { @@ -950,7 +950,7 @@ struct has_trivial_destructor // std::size_t offset; //RELATIVE_SIZE_BITS = SIZE_T_BITS - -// MAX_SEGMENT_BITS - +// MAX_SEGMENT_BITS - // CTRL_BITS 10 10 //MAX_SEGMENT_SIZE = SIZE_T_BITS - ALIGN_BITS 20 52 diff --git a/boost/interprocess/detail/managed_global_memory.hpp b/boost/interprocess/detail/managed_global_memory.hpp new file mode 100644 index 0000000000..39dd0b1e6d --- /dev/null +++ b/boost/interprocess/detail/managed_global_memory.hpp @@ -0,0 +1,115 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_BASIC_GLOBAL_MEMORY_HPP +#define BOOST_INTERPROCESS_BASIC_GLOBAL_MEMORY_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/offset_ptr.hpp> +#include <boost/interprocess/sync/spin/mutex.hpp> +#include <boost/interprocess/sync/spin/recursive_mutex.hpp> +#include <boost/interprocess/detail/managed_memory_impl.hpp> +#include <boost/interprocess/detail/managed_open_or_create_impl.hpp> +#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp> +#include <boost/interprocess/indexes/iset_index.hpp> +#include <boost/interprocess/creation_tags.hpp> +#include <boost/interprocess/permissions.hpp> + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +struct intermodule_singleton_mutex_family +{ + typedef boost::interprocess::ipcdetail::spin_mutex mutex_type; + typedef boost::interprocess::ipcdetail::spin_recursive_mutex recursive_mutex_type; +}; + +struct intermodule_types +{ + //We must use offset_ptr since a loaded DLL can map the singleton holder shared memory + //at a different address than other DLLs or the main executable + typedef rbtree_best_fit<intermodule_singleton_mutex_family, offset_ptr<void> > mem_algo; + template<class Device, bool FileBased> + struct open_or_create + { + typedef managed_open_or_create_impl + <Device, mem_algo::Alignment, FileBased> type; + }; +}; + +//we must implement our own managed shared memory to avoid circular dependencies +template<class Device, bool FileBased> +class basic_managed_global_memory + : public basic_managed_memory_impl + < char + , intermodule_types::mem_algo + , iset_index + , intermodule_types::open_or_create<Device, FileBased>::type::ManagedOpenOrCreateUserOffset + > + , private intermodule_types::open_or_create<Device, FileBased>::type +{ + /// @cond + typedef typename intermodule_types::template open_or_create<Device, FileBased>::type base2_t; + + typedef basic_managed_memory_impl + < char + , intermodule_types::mem_algo + , iset_index + , base2_t::ManagedOpenOrCreateUserOffset + > base_t; + + typedef create_open_func<base_t> create_open_func_t; + + basic_managed_global_memory *get_this_pointer() + { return this; } + + public: + typedef typename base_t::size_type size_type; + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_global_memory) + /// @endcond + + public: //functions + + basic_managed_global_memory (open_or_create_t open_or_create, + const char *name, size_type size, + const void *addr = 0, const permissions& perm = permissions()) + : base_t() + , base2_t(open_or_create, name, size, read_write, addr, + create_open_func_t(get_this_pointer(), + DoOpenOrCreate), perm) + {} + + basic_managed_global_memory (open_only_t open_only, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, read_write, addr, + create_open_func_t(get_this_pointer(), + DoOpen)) + {} +}; + + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_BASIC_GLOBAL_MEMORY_HPP diff --git a/boost/interprocess/detail/managed_memory_impl.hpp b/boost/interprocess/detail/managed_memory_impl.hpp index 31c3804439..f9ecb8a860 100644 --- a/boost/interprocess/detail/managed_memory_impl.hpp +++ b/boost/interprocess/detail/managed_memory_impl.hpp @@ -34,7 +34,7 @@ #include <boost/assert.hpp> //!\file -//!Describes a named shared memory allocation user class. +//!Describes a named shared memory allocation user class. //! namespace boost { @@ -45,7 +45,7 @@ template<class BasicManagedMemoryImpl> class create_open_func; template< - class CharType, + class CharType, class MemoryAlgorithm, template<class IndexConfig> class IndexType > @@ -54,14 +54,14 @@ struct segment_manager_type typedef segment_manager<CharType, MemoryAlgorithm, IndexType> type; }; -//!This class is designed to be a base class to classes that manage -//!creation of objects in a fixed size memory buffer. Apart -//!from allocating raw memory, the user can construct named objects. To +//!This class is designed to be a base class to classes that manage +//!creation of objects in a fixed size memory buffer. Apart +//!from allocating raw memory, the user can construct named objects. To //!achieve this, this class uses the reserved space provided by the allocation //!algorithm to place a named_allocator_algo, who takes care of name mappings. //!The class can be customized with the char type used for object names //!and the memory allocation algorithm to be used.*/ -template < class CharType +template < class CharType , class MemoryAlgorithm , template<class IndexConfig> class IndexType , std::size_t Offset = 0 @@ -92,7 +92,7 @@ class basic_managed_memory_impl /// @cond - typedef typename + typedef typename segment_manager::char_ptr_holder_t char_ptr_holder_t; //Experimental. Don't use. @@ -153,7 +153,7 @@ class basic_managed_memory_impl } //!Constructor. Allocates basic resources. Never throws. - basic_managed_memory_impl() + basic_managed_memory_impl() : mp_header(0){} //!Destructor. Calls close. Never throws. @@ -169,19 +169,19 @@ class basic_managed_memory_impl if(size < segment_manager::get_min_size()) return false; - //This function should not throw. The index construction can + //This function should not throw. The index construction can //throw if constructor allocates memory. So we must catch it. BOOST_TRY{ - //Let's construct the allocator in memory + //Let's construct the allocator in memory mp_header = new(addr) segment_manager(size); } BOOST_CATCH(...){ return false; } BOOST_CATCH_END - return true; + return true; } - + //!Connects to a segment manager in the reserved buffer. Never throws. bool open_impl (void *addr, size_type) { @@ -192,7 +192,7 @@ class basic_managed_memory_impl //!Frees resources. Never throws. bool close_impl() - { + { bool ret = mp_header != 0; mp_header = 0; return ret; @@ -249,40 +249,40 @@ class basic_managed_memory_impl void zero_free_memory() { mp_header->zero_free_memory(); } - //!Transforms an absolute address into an offset from base address. + //!Transforms an absolute address into an offset from base address. //!The address must belong to the memory segment. Never throws. handle_t get_handle_from_address (const void *ptr) const { - return (handle_t)(reinterpret_cast<const char*>(ptr) - - reinterpret_cast<const char*>(this->get_address())); + return (handle_t)(reinterpret_cast<const char*>(ptr) - + reinterpret_cast<const char*>(this->get_address())); } //!Returns true if the address belongs to the managed memory segment bool belongs_to_segment (const void *ptr) const - { - return ptr >= this->get_address() && + { + return ptr >= this->get_address() && ptr < (reinterpret_cast<const char*>(this->get_address()) + this->get_size()); } - //!Transforms previously obtained offset into an absolute address in the + //!Transforms previously obtained offset into an absolute address in the //!process space of the current process. Never throws.*/ void * get_address_from_handle (handle_t offset) const { return reinterpret_cast<char*>(this->get_address()) + offset; } //!Searches for nbytes of free memory in the segment, marks the - //!memory as used and return the pointer to the memory. If no + //!memory as used and return the pointer to the memory. If no //!memory is available throws a boost::interprocess::bad_alloc exception void* allocate (size_type nbytes) { return mp_header->allocate(nbytes); } - //!Searches for nbytes of free memory in the segment, marks the - //!memory as used and return the pointer to the memory. If no memory + //!Searches for nbytes of free memory in the segment, marks the + //!memory as used and return the pointer to the memory. If no memory //!is available returns 0. Never throws. void* allocate (size_type nbytes, std::nothrow_t nothrow) { return mp_header->allocate(nbytes, nothrow); } //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" - //!must be power of two. If no memory + //!must be power of two. If no memory //!is available returns 0. Never throws. void * allocate_aligned (size_type nbytes, size_type alignment, std::nothrow_t nothrow) { return mp_header->allocate_aligned(nbytes, alignment, nothrow); } @@ -292,13 +292,13 @@ class basic_managed_memory_impl allocation_command (boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size,size_type &received_size, T *reuse_ptr = 0) - { + { return mp_header->allocation_command (command, limit_size, preferred_size, received_size, reuse_ptr); } //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" - //!must be power of two. If no + //!must be power of two. If no //!memory is available throws a boost::interprocess::bad_alloc exception void * allocate_aligned(size_type nbytes, size_type alignment) { return mp_header->allocate_aligned(nbytes, alignment); } @@ -342,18 +342,18 @@ class basic_managed_memory_impl //!Creates a named object or array in memory //! - //!Allocates and constructs a T object or an array of T in memory, - //!associates this with the given name and returns a pointer to the + //!Allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the //!created object. If an array is being constructed all objects are //!created using the same parameters given to this function. //! //!-> If the name was previously used, returns 0. //! - //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //!-> Throws boost::interprocess::bad_alloc if there is no available memory //! //!-> If T's constructor throws, the function throws that exception. //! - //!Memory is freed automatically if T's constructor throws and if an + //!Memory is freed automatically if T's constructor throws and if an //!array was being constructed, destructors of created objects are called //!before freeing the memory. template <class T> @@ -363,18 +363,18 @@ class basic_managed_memory_impl //!Finds or creates a named object or array in memory //! - //!Tries to find an object with the given name in memory. If - //!found, returns the pointer to this pointer. If the object is not found, - //!allocates and constructs a T object or an array of T in memory, - //!associates this with the given name and returns a pointer to the + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the //!created object. If an array is being constructed all objects are //!created using the same parameters given to this function. //! - //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //!-> Throws boost::interprocess::bad_alloc if there is no available memory //! //!-> If T's constructor throws, the function throws that exception. //! - //!Memory is freed automatically if T's constructor throws and if an + //!Memory is freed automatically if T's constructor throws and if an //!array was being constructed, destructors of created objects are called //!before freeing the memory. template <class T> @@ -384,18 +384,18 @@ class basic_managed_memory_impl //!Creates a named object or array in memory //! - //!Allocates and constructs a T object or an array of T in memory, - //!associates this with the given name and returns a pointer to the + //!Allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the //!created object. If an array is being constructed all objects are //!created using the same parameters given to this function. //! //!-> If the name was previously used, returns 0. //! - //!-> Returns 0 if there is no available memory + //!-> Returns 0 if there is no available memory //! //!-> If T's constructor throws, the function throws that exception. //! - //!Memory is freed automatically if T's constructor throws and if an + //!Memory is freed automatically if T's constructor throws and if an //!array was being constructed, destructors of created objects are called //!before freeing the memory. template <class T> @@ -405,18 +405,18 @@ class basic_managed_memory_impl //!Finds or creates a named object or array in memory //! - //!Tries to find an object with the given name in memory. If - //!found, returns the pointer to this pointer. If the object is not found, - //!allocates and constructs a T object or an array of T in memory, - //!associates this with the given name and returns a pointer to the + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the //!created object. If an array is being constructed all objects are //!created using the same parameters given to this function. //! - //!-> Returns 0 if there is no available memory + //!-> Returns 0 if there is no available memory //! //!-> If T's constructor throws, the function throws that exception. //! - //!Memory is freed automatically if T's constructor throws and if an + //!Memory is freed automatically if T's constructor throws and if an //!array was being constructed, destructors of created objects are called //!before freeing the memory. template <class T> @@ -424,54 +424,54 @@ class basic_managed_memory_impl find_or_construct(char_ptr_holder_t name, std::nothrow_t nothrow) { return mp_header->template find_or_construct<T>(name, nothrow); } - //!Creates a named array from iterators in memory + //!Creates a named array from iterators in memory //! - //!Allocates and constructs an array of T in memory, - //!associates this with the given name and returns a pointer to the + //!Allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the //!created object. Each element in the array is created using the //!objects returned when dereferencing iterators as parameters //!and incrementing all iterators for each element. //! //!-> If the name was previously used, returns 0. //! - //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //!-> Throws boost::interprocess::bad_alloc if there is no available memory //! //!-> If T's constructor throws, the function throws that exception. //! - //!Memory is freed automatically if T's constructor throws and + //!Memory is freed automatically if T's constructor throws and //!destructors of created objects are called before freeing the memory. template <class T> typename segment_manager::template construct_iter_proxy<T>::type construct_it(char_ptr_holder_t name) { return mp_header->template construct_it<T>(name); } - //!Finds or creates a named array from iterators in memory + //!Finds or creates a named array from iterators in memory //! - //!Tries to find an object with the given name in memory. If - //!found, returns the pointer to this pointer. If the object is not found, - //!allocates and constructs an array of T in memory, - //!associates this with the given name and returns a pointer to the + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the //!created object. Each element in the array is created using the //!objects returned when dereferencing iterators as parameters //!and incrementing all iterators for each element. //! //!-> If the name was previously used, returns 0. //! - //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //!-> Throws boost::interprocess::bad_alloc if there is no available memory //! //!-> If T's constructor throws, the function throws that exception. //! - //!Memory is freed automatically if T's constructor throws and + //!Memory is freed automatically if T's constructor throws and //!destructors of created objects are called before freeing the memory. template <class T> typename segment_manager::template construct_iter_proxy<T>::type find_or_construct_it(char_ptr_holder_t name) { return mp_header->template find_or_construct_it<T>(name); } - //!Creates a named array from iterators in memory + //!Creates a named array from iterators in memory //! - //!Allocates and constructs an array of T in memory, - //!associates this with the given name and returns a pointer to the + //!Allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the //!created object. Each element in the array is created using the //!objects returned when dereferencing iterators as parameters //!and incrementing all iterators for each element. @@ -482,19 +482,19 @@ class basic_managed_memory_impl //! //!-> If T's constructor throws, the function throws that exception. //! - //!Memory is freed automatically if T's constructor throws and + //!Memory is freed automatically if T's constructor throws and //!destructors of created objects are called before freeing the memory.*/ template <class T> typename segment_manager::template construct_iter_proxy<T>::type construct_it(char_ptr_holder_t name, std::nothrow_t nothrow) { return mp_header->template construct_it<T>(name, nothrow); } - //!Finds or creates a named array from iterators in memory + //!Finds or creates a named array from iterators in memory //! - //!Tries to find an object with the given name in memory. If - //!found, returns the pointer to this pointer. If the object is not found, - //!allocates and constructs an array of T in memory, - //!associates this with the given name and returns a pointer to the + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the //!created object. Each element in the array is created using the //!objects returned when dereferencing iterators as parameters //!and incrementing all iterators for each element. @@ -505,7 +505,7 @@ class basic_managed_memory_impl //! //!-> If T's constructor throws, the function throws that exception. //! - //!Memory is freed automatically if T's constructor throws and + //!Memory is freed automatically if T's constructor throws and //!destructors of created objects are called before freeing the memory.*/ template <class T> typename segment_manager::template construct_iter_proxy<T>::type @@ -537,11 +537,11 @@ class basic_managed_memory_impl //! //!Exception Handling: //! - //!When deleting a dynamically object or array, the Standard + //!When deleting a dynamically object or array, the Standard //!does not guarantee that dynamically allocated memory, will be released. - //!Also, when deleting arrays, the Standard doesn't require calling - //!destructors for the rest of the objects if for one of them the destructor - //!terminated with an exception. + //!Also, when deleting arrays, the Standard doesn't require calling + //!destructors for the rest of the objects if for one of them the destructor + //!terminated with an exception. //! //!Destroying an object: //! @@ -550,13 +550,13 @@ class basic_managed_memory_impl //! //!Destroying an array: //! - //!When destroying an array, if a destructor throws, the rest of + //!When destroying an array, if a destructor throws, the rest of //!destructors are called. If any of these throws, the exceptions are //!ignored. The name association will be erased, memory will be freed and //!the first exception will be thrown. This guarantees the unlocking of //!mutexes and other resources. //! - //!For all theses reasons, classes with throwing destructors are not + //!For all theses reasons, classes with throwing destructors are not //!recommended. template <class T> bool destroy(const CharType *name) @@ -568,7 +568,7 @@ class basic_managed_memory_impl //! //!Exception Handling: //! - //!When deleting a dynamically object, the Standard does not + //!When deleting a dynamically object, the Standard does not //!guarantee that dynamically allocated memory will be released. //! //!Destroying an object: @@ -576,7 +576,7 @@ class basic_managed_memory_impl //!If the destructor throws, the memory will be freed and that exception //!will be thrown. //! - //!For all theses reasons, classes with throwing destructors are not + //!For all theses reasons, classes with throwing destructors are not //!recommended for memory. template <class T> bool destroy(const unique_instance_t *const ) @@ -588,7 +588,7 @@ class basic_managed_memory_impl //! //!Exception Handling: //! - //!When deleting a dynamically object, the Standard does not + //!When deleting a dynamically object, the Standard does not //!guarantee that dynamically allocated memory will be released. //! //!Destroying an object: @@ -596,7 +596,7 @@ class basic_managed_memory_impl //!If the destructor throws, the memory will be freed and that exception //!will be thrown. //! - //!For all theses reasons, classes with throwing destructors are not + //!For all theses reasons, classes with throwing destructors are not //!recommended for memory. template <class T> void destroy_ptr(const T *ptr) @@ -620,13 +620,13 @@ class basic_managed_memory_impl static size_type get_instance_length(const T *ptr) { return segment_manager::get_instance_length(ptr); } - //!Preallocates needed index resources to optimize the + //!Preallocates needed index resources to optimize the //!creation of "num" named objects in the memory segment. //!Can throw boost::interprocess::bad_alloc if there is no enough memory. void reserve_named_objects(size_type num) { mp_header->reserve_named_objects(num); } - //!Preallocates needed index resources to optimize the + //!Preallocates needed index resources to optimize the //!creation of "num" unique objects in the memory segment. //!Can throw boost::interprocess::bad_alloc if there is no enough memory. void reserve_unique_objects(size_type num) @@ -652,7 +652,7 @@ class basic_managed_memory_impl const_named_iterator named_begin() const { return mp_header->named_begin(); } - //!Returns a constant iterator to the end of the index + //!Returns a constant iterator to the end of the index //!storing the named allocations. NOT thread-safe. Never throws. const_named_iterator named_end() const { return mp_header->named_end(); } @@ -662,7 +662,7 @@ class basic_managed_memory_impl const_unique_iterator unique_begin() const { return mp_header->unique_begin(); } - //!Returns a constant iterator to the end of the index + //!Returns a constant iterator to the end of the index //!storing the unique allocations. NOT thread-safe. Never throws. const_unique_iterator unique_end() const { return mp_header->unique_end(); } @@ -724,8 +724,8 @@ class create_open_func : m_frontend(frontend), m_type(type){} bool operator()(void *addr, typename BasicManagedMemoryImpl::size_type size, bool created) const - { - if(((m_type == DoOpen) && created) || + { + if(((m_type == DoOpen) && created) || ((m_type == DoCreate) && !created)) return false; diff --git a/boost/interprocess/detail/managed_multi_shared_memory.hpp b/boost/interprocess/detail/managed_multi_shared_memory.hpp index 579d1ad6ff..654c8bb9f3 100644 --- a/boost/interprocess/detail/managed_multi_shared_memory.hpp +++ b/boost/interprocess/detail/managed_multi_shared_memory.hpp @@ -36,7 +36,7 @@ #include <boost/assert.hpp> //These includes needed to fulfill default template parameters of //predeclarations in interprocess_fwd.hpp -#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp> +#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp> #include <boost/interprocess/sync/mutex_family.hpp> //!\file @@ -51,25 +51,25 @@ namespace interprocess { //-Use GetSecurityInfo? //-Change everything to use only a shared memory object expanded via truncate()? -//!A basic shared memory named object creation class. Initializes the -//!shared memory segment. Inherits all basic functionality from +//!A basic shared memory named object creation class. Initializes the +//!shared memory segment. Inherits all basic functionality from //!basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType> template < - class CharType, - class MemoryAlgorithm, + class CharType, + class MemoryAlgorithm, template<class IndexConfig> class IndexType > -class basic_managed_multi_shared_memory +class basic_managed_multi_shared_memory : public ipcdetail::basic_managed_memory_impl <CharType, MemoryAlgorithm, IndexType> { typedef basic_managed_multi_shared_memory <CharType, MemoryAlgorithm, IndexType> self_t; - typedef ipcdetail::basic_managed_memory_impl + typedef ipcdetail::basic_managed_memory_impl <CharType, MemoryAlgorithm, IndexType> base_t; - + typedef typename MemoryAlgorithm::void_pointer void_pointer; typedef typename ipcdetail:: managed_open_or_create_impl<shared_memory_object, MemoryAlgorithm::Alignment> managed_impl; @@ -91,7 +91,7 @@ class basic_managed_multi_shared_memory // { // public: // segment_creator(shared_memory &shmem, -// const char *mem_name, +// const char *mem_name, // const void *addr) // : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){} // @@ -99,8 +99,8 @@ class basic_managed_multi_shared_memory // { // if(!m_shmem.create(m_mem_name, size, m_addr)) // return 0; -// return m_shmem.get_address(); -// } +// return m_shmem.get_address(); +// } // private: // shared_memory &m_shmem; // const char *m_mem_name; @@ -113,7 +113,7 @@ class basic_managed_multi_shared_memory public: typedef std::pair<void *, size_type> result_type; typedef basic_managed_multi_shared_memory frontend_t; - typedef typename + typedef typename basic_managed_multi_shared_memory::void_pointer void_pointer; typedef typename void_pointer::segment_group_id segment_group_id; group_services(frontend_t *const frontend) @@ -127,14 +127,14 @@ class basic_managed_multi_shared_memory alloc_size += 1; //If requested size is less than minimum, update that - alloc_size = (m_min_segment_size > alloc_size) ? + alloc_size = (m_min_segment_size > alloc_size) ? m_min_segment_size : alloc_size; if(mp_frontend->priv_new_segment(create_open_func::DoCreate, alloc_size, 0, permissions())){ typename shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin(); return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1); }*/ - return result_type(static_cast<void *>(0), 0); + return result_type(static_cast<void *>(0), 0); } virtual bool update_segments () @@ -166,7 +166,7 @@ class basic_managed_multi_shared_memory struct create_open_func { enum type_t { DoCreate, DoOpen, DoOpenOrCreate }; - typedef typename + typedef typename basic_managed_multi_shared_memory::void_pointer void_pointer; create_open_func(self_t * const frontend, @@ -174,8 +174,8 @@ class basic_managed_multi_shared_memory : mp_frontend(frontend), m_type(type), m_segment_number(segment_number){} bool operator()(void *addr, size_type size, bool created) const - { - if(((m_type == DoOpen) && created) || + { + if(((m_type == DoOpen) && created) || ((m_type == DoCreate) && !created)) return false; segment_group_id group = mp_frontend->m_group_services.get_group(); @@ -191,7 +191,7 @@ class basic_managed_multi_shared_memory //Check if this is the master segment if(!m_segment_number){ //Create or open the Interprocess machinery - if((impl_done = created ? + if((impl_done = created ? mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){ return true; } @@ -219,14 +219,14 @@ class basic_managed_multi_shared_memory //!Functor to execute atomically when closing a shared memory segment. struct close_func { - typedef typename + typedef typename basic_managed_multi_shared_memory::void_pointer void_pointer; close_func(self_t * const frontend) : mp_frontend(frontend){} void operator()(const mapped_region ®ion, bool last) const - { + { if(last) mp_frontend->destroy_impl(); else mp_frontend->close_impl(); } @@ -251,7 +251,7 @@ class basic_managed_multi_shared_memory const permissions &perm = permissions()) : m_group_services(get_this_pointer()) { - priv_open_or_create(create_open_func::DoCreate,name, size, perm); + priv_open_or_create(create_open_func::DoCreate,name, size, perm); } basic_managed_multi_shared_memory(open_or_create_t, @@ -273,7 +273,7 @@ class basic_managed_multi_shared_memory { this->priv_close(); } private: - bool priv_open_or_create(typename create_open_func::type_t type, + bool priv_open_or_create(typename create_open_func::type_t type, const char *name, size_type size, const permissions &perm) @@ -301,7 +301,7 @@ class basic_managed_multi_shared_memory if(group){ void_pointer::delete_group(group); } - return false; + return false; } bool priv_new_segment(typename create_open_func::type_t type, @@ -312,7 +312,7 @@ class basic_managed_multi_shared_memory BOOST_TRY{ //Get the number of groups of this multi_segment group size_type segment_id = m_shmem_list.size(); - //Format the name of the shared memory: append segment number. + //Format the name of the shared memory: append segment number. boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter; //Pre-reserve string size size_type str_size = m_root_name.length()+10; @@ -368,7 +368,7 @@ class basic_managed_multi_shared_memory //!Frees resources. Never throws. void priv_close() - { + { if(!m_shmem_list.empty()){ bool ret; //Obtain group identifier @@ -385,7 +385,7 @@ class basic_managed_multi_shared_memory m_shmem_list.clear(); } } - + private: shmem_list_t m_shmem_list; group_services m_group_services; diff --git a/boost/interprocess/detail/managed_open_or_create_impl.hpp b/boost/interprocess/detail/managed_open_or_create_impl.hpp index 4d6997f330..a4f1f15817 100644 --- a/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -48,12 +48,12 @@ class xsi_key; template<> struct managed_open_or_create_impl_device_id_t<xsi_shared_memory_file_wrapper> -{ +{ typedef xsi_key type; }; #endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS - + /// @endcond namespace ipcdetail { @@ -79,7 +79,7 @@ class managed_open_or_create_impl_device_holder<true, DeviceAbstraction> const DeviceAbstraction &get_device() const { return dev; } - + private: DeviceAbstraction dev; }; @@ -94,16 +94,16 @@ class managed_open_or_create_impl typedef typename managed_open_or_create_impl_device_id_t<DeviceAbstraction>::type device_id_t; typedef managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction> DevHolder; enum - { - UninitializedSegment, - InitializingSegment, + { + UninitializedSegment, + InitializingSegment, InitializedSegment, CorruptedSegment }; public: static const std::size_t - ManagedOpenOrCreateUserOffset = + ManagedOpenOrCreateUserOffset = ct_rounded_size < sizeof(boost::uint32_t) , MemAlignment ? (MemAlignment) : @@ -113,7 +113,7 @@ class managed_open_or_create_impl managed_open_or_create_impl() {} - managed_open_or_create_impl(create_only_t, + managed_open_or_create_impl(create_only_t, const device_id_t & id, std::size_t size, mode_t mode, @@ -130,7 +130,7 @@ class managed_open_or_create_impl , null_mapped_region_function()); } - managed_open_or_create_impl(open_only_t, + managed_open_or_create_impl(open_only_t, const device_id_t & id, mode_t mode, const void *addr) @@ -146,7 +146,7 @@ class managed_open_or_create_impl } - managed_open_or_create_impl(open_or_create_t, + managed_open_or_create_impl(open_or_create_t, const device_id_t & id, std::size_t size, mode_t mode, @@ -164,7 +164,7 @@ class managed_open_or_create_impl } template <class ConstructFunc> - managed_open_or_create_impl(create_only_t, + managed_open_or_create_impl(create_only_t, const device_id_t & id, std::size_t size, mode_t mode, @@ -183,7 +183,7 @@ class managed_open_or_create_impl } template <class ConstructFunc> - managed_open_or_create_impl(open_only_t, + managed_open_or_create_impl(open_only_t, const device_id_t & id, mode_t mode, const void *addr, @@ -200,7 +200,7 @@ class managed_open_or_create_impl } template <class ConstructFunc> - managed_open_or_create_impl(open_or_create_t, + managed_open_or_create_impl(open_or_create_t, const device_id_t & id, std::size_t size, mode_t mode, @@ -222,10 +222,10 @@ class managed_open_or_create_impl { this->swap(moved); } managed_open_or_create_impl &operator=(BOOST_RV_REF(managed_open_or_create_impl) moved) - { + { managed_open_or_create_impl tmp(boost::move(moved)); this->swap(tmp); - return *this; + return *this; } ~managed_open_or_create_impl() @@ -298,10 +298,10 @@ class managed_open_or_create_impl tmp.swap(dev); } - template <class ConstructFunc> inline + template <class ConstructFunc> inline void priv_open_or_create - (create_enum_t type, - const device_id_t & id, + (create_enum_t type, + const device_id_t & id, std::size_t size, mode_t mode, const void *addr, const permissions &perm, @@ -396,7 +396,8 @@ class managed_open_or_create_impl if(previous == UninitializedSegment){ try{ - construct_func(static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset, size - ManagedOpenOrCreateUserOffset, true); + construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset + , size - ManagedOpenOrCreateUserOffset, true); //All ok, just move resources to the external mapped region m_mapped_region.swap(region); } diff --git a/boost/interprocess/detail/math_functions.hpp b/boost/interprocess/detail/math_functions.hpp index 08274160db..2fc457c683 100644 --- a/boost/interprocess/detail/math_functions.hpp +++ b/boost/interprocess/detail/math_functions.hpp @@ -4,7 +4,7 @@ // (C) Copyright Ion Gaztanaga 2007-2011. // // Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at +// (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. @@ -93,7 +93,7 @@ inline std::size_t floor_log2 (std::size_t x) std::size_t n = x; std::size_t log2 = 0; - + for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ std::size_t tmp = n >> shift; if (tmp) diff --git a/boost/interprocess/detail/min_max.hpp b/boost/interprocess/detail/min_max.hpp index 75aa00f87b..1f4ebdfc33 100644 --- a/boost/interprocess/detail/min_max.hpp +++ b/boost/interprocess/detail/min_max.hpp @@ -21,7 +21,7 @@ #include <boost/interprocess/detail/workaround.hpp> namespace boost { -namespace interprocess { +namespace interprocess { template<class T> const T &max_value(const T &a, const T &b) @@ -31,7 +31,7 @@ template<class T> const T &min_value(const T &a, const T &b) { return a < b ? a : b; } -} //namespace interprocess { +} //namespace interprocess { } //namespace boost { #include <boost/interprocess/detail/config_end.hpp> diff --git a/boost/interprocess/detail/mpl.hpp b/boost/interprocess/detail/mpl.hpp index c5b6f90ef1..e2c7f52d24 100644 --- a/boost/interprocess/detail/mpl.hpp +++ b/boost/interprocess/detail/mpl.hpp @@ -20,7 +20,7 @@ #include <cstddef> namespace boost { -namespace interprocess { +namespace interprocess { namespace ipcdetail { template <class T, T val> @@ -105,24 +105,24 @@ struct if_ template <class Pair> -struct select1st -// : public std::unary_function<Pair, typename Pair::first_type> +struct select1st +// : public std::unary_function<Pair, typename Pair::first_type> { template<class OtherPair> - const typename Pair::first_type& operator()(const OtherPair& x) const + const typename Pair::first_type& operator()(const OtherPair& x) const { return x.first; } - const typename Pair::first_type& operator()(const typename Pair::first_type& x) const + const typename Pair::first_type& operator()(const typename Pair::first_type& x) const { return x; } }; // identity is an extension: it is not part of the standard. template <class T> -struct identity -// : public std::unary_function<T,T> +struct identity +// : public std::unary_function<T,T> { typedef T type; - const T& operator()(const T& x) const + const T& operator()(const T& x) const { return x; } }; @@ -144,8 +144,8 @@ struct ls_zeros<1> static const std::size_t value = 0; }; -} //namespace ipcdetail { -} //namespace interprocess { +} //namespace ipcdetail { +} //namespace interprocess { } //namespace boost { #endif //#ifndef BOOST_INTERPROCESS_DETAIL_MPL_HPP diff --git a/boost/interprocess/detail/multi_segment_services.hpp b/boost/interprocess/detail/multi_segment_services.hpp index 4b6cafc742..d1451d3379 100644 --- a/boost/interprocess/detail/multi_segment_services.hpp +++ b/boost/interprocess/detail/multi_segment_services.hpp @@ -20,7 +20,7 @@ /*!\file - Describes a named shared memory allocation user class. + Describes a named shared memory allocation user class. */ namespace boost { diff --git a/boost/interprocess/detail/named_proxy.hpp b/boost/interprocess/detail/named_proxy.hpp index 604d7881ea..c2aafed9ac 100644 --- a/boost/interprocess/detail/named_proxy.hpp +++ b/boost/interprocess/detail/named_proxy.hpp @@ -24,7 +24,7 @@ #include <boost/interprocess/detail/mpl.hpp> #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -#include <boost/interprocess/detail/preprocessor.hpp> +#include <boost/interprocess/detail/preprocessor.hpp> #else #include <boost/move/move.hpp> #include <boost/interprocess/detail/variadic_templates_tools.hpp> @@ -34,7 +34,7 @@ //!Describes a proxy class that implements named allocation syntax. namespace boost { -namespace interprocess { +namespace interprocess { namespace ipcdetail { #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING @@ -83,7 +83,7 @@ struct CtorNArg : public placement_destroy<T> { this->expansion_helper(++get<IdxPack>(args_)...); } - + template<class ...ExpansionArgs> void expansion_helper(ExpansionArgs &&...) {} @@ -93,11 +93,11 @@ struct CtorNArg : public placement_destroy<T> {} tuple<Args&...> args_; -}; +}; //!Describes a proxy class that implements named //!allocation syntax. -template +template < class SegmentManager //segment manager to construct the object , class T //type of object to build , bool is_iterator //passing parameters are normal object or iterators? @@ -119,10 +119,10 @@ class named_proxy template<class ...Args> T *operator()(Args &&...args) const - { + { CtorNArg<T, is_iterator, Args...> &&ctor_obj = CtorNArg<T, is_iterator, Args...> (boost::forward<Args>(args)...); - return mp_mngr->template + return mp_mngr->template generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj); } @@ -199,7 +199,7 @@ struct Ctor0Arg : public placement_destroy<T> // private: // void construct(void *mem, true_) // { new((void*)mem)T(*m_p1, *m_p2); } -// +// // void construct(void *mem, false_) // { new((void*)mem)T(m_p1, m_p2); } // @@ -270,7 +270,7 @@ struct Ctor0Arg : public placement_destroy<T> //!Describes a proxy class that implements named //!allocation syntax. -template +template < class SegmentManager //segment manager to construct the object , class T //type of object to build , bool is_iterator //passing parameters are normal object or iterators? @@ -293,9 +293,9 @@ class named_proxy //!makes a named allocation and calls the //!default constructor T *operator()() const - { + { Ctor0Arg<T> ctor_obj; - return mp_mngr->template + return mp_mngr->template generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj); } //! @@ -322,7 +322,7 @@ class named_proxy //////////////////////////////////////////////////////////////////////// // // template <class P1, class P2> - // T *operator()(P1 &p1, P2 &p2) const + // T *operator()(P1 &p1, P2 &p2) const // { // typedef Ctor2Arg // <T, is_iterator, P1, P2> diff --git a/boost/interprocess/detail/os_file_functions.hpp b/boost/interprocess/detail/os_file_functions.hpp index b680c57132..08decd9bc4 100644 --- a/boost/interprocess/detail/os_file_functions.hpp +++ b/boost/interprocess/detail/os_file_functions.hpp @@ -32,7 +32,7 @@ # include <cstdio> # include <dirent.h> # if 0 -# include <sys/file.h> +# include <sys/file.h> # endif # else # error Unknown platform @@ -58,7 +58,7 @@ typedef enum { read_only = winapi::generic_read , read_write = winapi::generic_read | winapi::generic_write , copy_on_write , read_private - , invalid_mode = 0xffff + , invalid_mode = 0xffff } mode_t; typedef enum { file_begin = winapi::file_begin @@ -96,28 +96,28 @@ inline const char *get_temporary_path() inline file_handle_t create_new_file (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) -{ +{ unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; return winapi::create_file ( name, (unsigned int)mode, winapi::create_new, attr - , (winapi::interprocess_security_attributes*)perm.get_permissions()); + , (winapi::interprocess_security_attributes*)perm.get_permissions()); } inline file_handle_t create_or_open_file (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) -{ +{ unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; return winapi::create_file ( name, (unsigned int)mode, winapi::open_always, attr - , (winapi::interprocess_security_attributes*)perm.get_permissions()); + , (winapi::interprocess_security_attributes*)perm.get_permissions()); } inline file_handle_t open_existing_file (const char *name, mode_t mode, bool temporary = false) -{ +{ unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; return winapi::create_file - (name, (unsigned int)mode, winapi::open_existing, attr, 0); + (name, (unsigned int)mode, winapi::open_existing, attr, 0); } inline bool delete_file(const char *name) @@ -140,7 +140,7 @@ inline bool truncate_file (file_handle_t hnd, std::size_t size) if(offset_t(size) > filesize){ if(!winapi::set_file_pointer_ex(hnd, filesize, 0, winapi::file_begin)){ return false; - } + } //We will write zeros in the end of the file //since set_end_of_file does not guarantee this for(std::size_t remaining = size - filesize, write_size = 0 @@ -177,7 +177,7 @@ inline bool get_file_pointer(file_handle_t hnd, offset_t &off) { return winapi::set_file_pointer_ex(hnd, 0, &off, winapi::file_current); } inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata) -{ +{ unsigned long written; return 0 != winapi::write_file(hnd, data, (unsigned long)numdata, &written, 0); } @@ -189,9 +189,9 @@ inline bool close_file(file_handle_t hnd) { return 0 != winapi::close_handle(hnd); } inline bool acquire_file_lock(file_handle_t hnd) -{ +{ static winapi::interprocess_overlapped overlapped; - const unsigned long len = 0xffffffff; + const unsigned long len = ~((unsigned long)(0u)); // winapi::interprocess_overlapped overlapped; // std::memset(&overlapped, 0, sizeof(overlapped)); return winapi::lock_file_ex @@ -199,44 +199,44 @@ inline bool acquire_file_lock(file_handle_t hnd) } inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired) -{ - const unsigned long len = 0xffffffff; +{ + const unsigned long len = ~((unsigned long)(0u)); winapi::interprocess_overlapped overlapped; std::memset(&overlapped, 0, sizeof(overlapped)); if(!winapi::lock_file_ex - (hnd, winapi::lockfile_exclusive_lock | winapi::lockfile_fail_immediately, + (hnd, winapi::lockfile_exclusive_lock | winapi::lockfile_fail_immediately, 0, len, len, &overlapped)){ - return winapi::get_last_error() == winapi::error_lock_violation ? + return winapi::get_last_error() == winapi::error_lock_violation ? acquired = false, true : false; - + } return (acquired = true); } inline bool release_file_lock(file_handle_t hnd) -{ - const unsigned long len = 0xffffffff; +{ + const unsigned long len = ~((unsigned long)(0u)); winapi::interprocess_overlapped overlapped; std::memset(&overlapped, 0, sizeof(overlapped)); return winapi::unlock_file_ex(hnd, 0, len, len, &overlapped); } inline bool acquire_file_lock_sharable(file_handle_t hnd) -{ - const unsigned long len = 0xffffffff; +{ + const unsigned long len = ~((unsigned long)(0u)); winapi::interprocess_overlapped overlapped; std::memset(&overlapped, 0, sizeof(overlapped)); return winapi::lock_file_ex(hnd, 0, 0, len, len, &overlapped); } inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) -{ - const unsigned long len = 0xffffffff; +{ + const unsigned long len = ~((unsigned long)(0u)); winapi::interprocess_overlapped overlapped; std::memset(&overlapped, 0, sizeof(overlapped)); if(!winapi::lock_file_ex (hnd, winapi::lockfile_fail_immediately, 0, len, len, &overlapped)){ - return winapi::get_last_error() == winapi::error_lock_violation ? + return winapi::get_last_error() == winapi::error_lock_violation ? acquired = false, true : false; } return (acquired = true); @@ -367,7 +367,7 @@ typedef enum { read_only = O_RDONLY , read_write = O_RDWR , copy_on_write , read_private - , invalid_mode = 0xffff + , invalid_mode = 0xffff } mode_t; typedef enum { file_begin = SEEK_SET @@ -406,7 +406,7 @@ inline const char *get_temporary_path() inline file_handle_t create_new_file (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) -{ +{ (void)temporary; int ret = ::open(name, ((int)mode) | O_EXCL | O_CREAT, perm.get_permissions()); if(ret >= 0){ @@ -439,7 +439,7 @@ inline file_handle_t create_or_open_file inline file_handle_t open_existing_file (const char *name, mode_t mode, bool temporary = false) -{ +{ (void)temporary; return ::open(name, (int)mode); } @@ -459,7 +459,7 @@ inline bool truncate_file (file_handle_t hnd, std::size_t size) } inline bool get_file_size(file_handle_t hnd, offset_t &size) -{ +{ struct stat data; bool ret = 0 == ::fstat(hnd, &data); if(ret){ @@ -472,7 +472,7 @@ inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos) { return ((off_t)(-1)) != ::lseek(hnd, off, (int)pos); } inline bool get_file_pointer(file_handle_t hnd, offset_t &off) -{ +{ off = ::lseek(hnd, 0, SEEK_CUR); return off != ((off_t)-1); } @@ -522,7 +522,7 @@ inline bool release_file_lock(file_handle_t hnd) } inline bool acquire_file_lock_sharable(file_handle_t hnd) -{ +{ struct ::flock lock; lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; @@ -532,7 +532,7 @@ inline bool acquire_file_lock_sharable(file_handle_t hnd) } inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) -{ +{ struct flock lock; lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; @@ -540,7 +540,7 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) lock.l_len = 0; int ret = ::fcntl(hnd, F_SETLK, &lock); if(ret == -1){ - return (errno == EAGAIN || errno == EACCES) ? + return (errno == EAGAIN || errno == EACCES) ? acquired = false, true : false; } return (acquired = true); @@ -601,7 +601,7 @@ inline bool delete_subdirectories_recursive || (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){ continue; } - if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){ + if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){ continue; } fn = refcstrRootDirectory; diff --git a/boost/interprocess/detail/os_thread_functions.hpp b/boost/interprocess/detail/os_thread_functions.hpp index e49e82c8e0..8d769fc4e9 100644 --- a/boost/interprocess/detail/os_thread_functions.hpp +++ b/boost/interprocess/detail/os_thread_functions.hpp @@ -104,7 +104,7 @@ typedef pthread_t OS_thread_id_t; typedef pid_t OS_process_id_t; struct OS_systemwide_thread_id_t -{ +{ OS_systemwide_thread_id_t() : pid(), tid() {} @@ -153,7 +153,7 @@ inline OS_thread_id_t get_current_thread_id() { return ::pthread_self(); } inline OS_thread_id_t get_invalid_thread_id() -{ +{ static pthread_t invalid_id; return invalid_id; } diff --git a/boost/interprocess/detail/pointer_type.hpp b/boost/interprocess/detail/pointer_type.hpp index 7c45be085e..549b23fa6c 100644 --- a/boost/interprocess/detail/pointer_type.hpp +++ b/boost/interprocess/detail/pointer_type.hpp @@ -61,11 +61,11 @@ template <class T, class D> struct pointer_type { typedef typename pointer_type_imp::pointer_type<T, - typename ipcdetail::remove_reference<D>::type>::type type; + typename remove_reference<D>::type>::type type; }; } //namespace ipcdetail { -} //namespace interprocess { +} //namespace interprocess { } //namespace boost { #include <boost/interprocess/detail/config_end.hpp> diff --git a/boost/interprocess/detail/portable_intermodule_singleton.hpp b/boost/interprocess/detail/portable_intermodule_singleton.hpp new file mode 100644 index 0000000000..eb2a13e104 --- /dev/null +++ b/boost/interprocess/detail/portable_intermodule_singleton.hpp @@ -0,0 +1,356 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PORTABLE_INTERMODULE_SINGLETON_HPP +#define BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_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/managed_global_memory.hpp> +#include <boost/interprocess/detail/intermodule_singleton_common.hpp> +#include <boost/interprocess/shared_memory_object.hpp> +#include <boost/interprocess/detail/atomic.hpp> +#include <boost/interprocess/detail/os_thread_functions.hpp> +#include <boost/interprocess/detail/tmp_dir_helpers.hpp> +#include <boost/interprocess/detail/os_file_functions.hpp> +#include <boost/interprocess/detail/file_locking_helpers.hpp> +#include <boost/assert.hpp> +#include <cstddef> +#include <cstdio> +#include <cstring> +#include <string> + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +typedef basic_managed_global_memory<shared_memory_object, true> managed_global_memory; + +namespace intermodule_singleton_helpers { + +static void create_tmp_subdir_and_get_pid_based_filepath + (const char *subdir_name, const char *file_prefix, OS_process_id_t pid, std::string &s, bool creation_time = false) +{ + //Let's create a lock file for each process gmem that will mark if + //the process is alive or not + create_tmp_and_clean_old(s); + s += "/"; + s += subdir_name; + if(!open_or_create_directory(s.c_str())){ + throw interprocess_exception(error_info(system_error_code())); + } + s += "/"; + s += file_prefix; + if(creation_time){ + std::string sstamp; + get_pid_creation_time_str(sstamp); + s += sstamp; + } + else{ + pid_str_t pid_str; + get_pid_str(pid_str, pid); + s += pid_str; + } +} + +static bool check_if_filename_complies_with_pid + (const char *filename, const char *prefix, OS_process_id_t pid, std::string &file_suffix, bool creation_time = false) +{ + //Check if filename complies with lock file name pattern + std::string fname(filename); + std::string fprefix(prefix); + if(fname.size() <= fprefix.size()){ + return false; + } + fname.resize(fprefix.size()); + if(fname != fprefix){ + return false; + } + + //If not our lock file, delete it if we can lock it + fname = filename; + fname.erase(0, fprefix.size()); + pid_str_t pid_str; + get_pid_str(pid_str, pid); + file_suffix = pid_str; + if(creation_time){ + std::size_t p = fname.find('_'); + if (p == std::string::npos){ + return false; + } + std::string save_suffix(fname); + fname.erase(p); + fname.swap(file_suffix); + bool ret = (file_suffix == fname); + file_suffix.swap(save_suffix); + return ret; + } + else{ + fname.swap(file_suffix); + return (file_suffix == fname); + } +} + +template<> +struct thread_safe_global_map_dependant<managed_global_memory> +{ + private: + static const int GMemMarkToBeRemoved = -1; + static const int GMemNotPresent = -2; + + static const char *get_lock_file_subdir_name() + { return "gmem"; } + + static const char *get_lock_file_base_name() + { return "lck"; } + + static void create_and_get_singleton_lock_file_path(std::string &s) + { + create_tmp_subdir_and_get_pid_based_filepath + (get_lock_file_subdir_name(), get_lock_file_base_name(), get_current_process_id(), s, true); + } + + struct gmem_erase_func + { + gmem_erase_func(const char *shm_name, const char *singleton_lock_file_path, managed_global_memory & shm) + :shm_name_(shm_name), singleton_lock_file_path_(singleton_lock_file_path), shm_(shm) + {} + + void operator()() + { + locking_file_serial_id *pserial_id = shm_.find<locking_file_serial_id>("lock_file_fd").first; + if(pserial_id){ + pserial_id->fd = GMemMarkToBeRemoved; + } + delete_file(singleton_lock_file_path_); + shared_memory_object::remove(shm_name_); + } + + const char * const shm_name_; + const char * const singleton_lock_file_path_; + managed_global_memory & shm_; + }; + + //This function applies shared memory erasure logic based on the passed lock file. + static void apply_gmem_erase_logic(const char *filepath, const char *filename) + { + int fd = GMemMarkToBeRemoved; + try{ + std::string str; + //If the filename is current process lock file, then avoid it + if(check_if_filename_complies_with_pid + (filename, get_lock_file_base_name(), get_current_process_id(), str, true)){ + return; + } + //Open and lock the other process' lock file + fd = try_open_and_lock_file(filepath); + if(fd < 0){ + return; + } + //If done, then the process is dead so take global shared memory name + //(the name is based on the lock file name) and try to apply erasure logic + str.insert(0, get_map_base_name()); + try{ + managed_global_memory shm(open_only, str.c_str()); + gmem_erase_func func(str.c_str(), filepath, shm); + shm.try_atomic_func(func); + } + catch(interprocess_exception &e){ + //If shared memory is not found erase the lock file + if(e.get_error_code() == not_found_error){ + delete_file(filepath); + } + } + } + catch(...){ + + } + if(fd >= 0){ + close_lock_file(fd); + } + } + + public: + + static bool remove_old_gmem() + { + std::string refcstrRootDirectory; + tmp_folder(refcstrRootDirectory); + refcstrRootDirectory += "/"; + refcstrRootDirectory += get_lock_file_subdir_name(); + return for_each_file_in_dir(refcstrRootDirectory.c_str(), apply_gmem_erase_logic); + } + + struct lock_file_logic + { + lock_file_logic(managed_global_memory &shm) + : mshm(shm) + { shm.atomic_func(*this); } + + void operator()(void) + { + retry_with_new_map = false; + + //First find the file locking descriptor id + locking_file_serial_id *pserial_id = + mshm.find<locking_file_serial_id>("lock_file_fd").first; + + int fd; + //If not found schedule a creation + if(!pserial_id){ + fd = GMemNotPresent; + } + //Else get it + else{ + fd = pserial_id->fd; + } + //If we need to create a new one, do it + if(fd == GMemNotPresent){ + std::string lck_str; + //Create a unique current pid based lock file path + create_and_get_singleton_lock_file_path(lck_str); + //Open or create and lock file + int fd = open_or_create_and_lock_file(lck_str.c_str()); + //If failed, write a bad file descriptor to notify other modules that + //something was wrong and unlink shared memory. Mark the function object + //to tell caller to retry with another shared memory + if(fd < 0){ + this->register_lock_file(GMemMarkToBeRemoved); + std::string s; + get_map_name(s); + shared_memory_object::remove(s.c_str()); + retry_with_new_map = true; + } + //If successful, register the file descriptor + else{ + this->register_lock_file(fd); + } + } + //If the fd was invalid (maybe a previous try failed) notify caller that + //should retry creation logic, since this shm might have been already + //unlinked since the shm was removed + else if (fd == GMemMarkToBeRemoved){ + retry_with_new_map = true; + } + //If the stored fd is not valid (a open fd, a normal file with the + //expected size, or does not have the same file id number, + //then it's an old shm from an old process with the same pid. + //If that's the case, mark it as invalid + else if(!is_valid_fd(fd) || + !is_normal_file(fd) || + 0 != get_size(fd) || + !compare_file_serial(fd, *pserial_id)){ + pserial_id->fd = GMemMarkToBeRemoved; + std::string s; + get_map_name(s); + shared_memory_object::remove(s.c_str()); + retry_with_new_map = true; + } + else{ + //If the lock file is ok, increment reference count of + //attached modules to shared memory + atomic_inc32(&pserial_id->modules_attached_to_gmem_count); + } + } + + bool retry() const { return retry_with_new_map; } + + private: + locking_file_serial_id * register_lock_file(int fd) + { + locking_file_serial_id *pinfo = mshm.construct<locking_file_serial_id>("lock_file_fd")(); + fill_file_serial_id(fd, *pinfo); + return pinfo; + } + + managed_global_memory &mshm; + bool retry_with_new_map; + }; + + static void construct_map(void *addr) + { + std::string s; + intermodule_singleton_helpers::get_map_name(s); + const char *MapName = s.c_str(); + const std::size_t MapSize = intermodule_singleton_helpers::get_map_size();; + ::new (addr)managed_global_memory(open_or_create, MapName, MapSize); + } + + struct unlink_map_logic + { + unlink_map_logic(managed_global_memory &mshm) + : mshm_(mshm) + { mshm.atomic_func(*this); } + + void operator()() + { + locking_file_serial_id *pserial_id = + mshm_.find<locking_file_serial_id> + ("lock_file_fd").first; + BOOST_ASSERT(0 != pserial_id); + if(1 == atomic_dec32(&pserial_id->modules_attached_to_gmem_count)){ + int fd = pserial_id->fd; + if(fd > 0){ + pserial_id->fd = GMemMarkToBeRemoved; + std::string s; + create_and_get_singleton_lock_file_path(s); + delete_file(s.c_str()); + close_lock_file(fd); + intermodule_singleton_helpers::get_map_name(s); + shared_memory_object::remove(s.c_str()); + } + } + } + + private: + managed_global_memory &mshm_; + }; + + static ref_count_ptr *find(managed_global_memory &map, const char *name) + { + return map.find<ref_count_ptr>(name).first; + } + + static ref_count_ptr *insert(managed_global_memory &map, const char *name, const ref_count_ptr &ref) + { + return map.construct<ref_count_ptr>(name)(ref); + } + + static bool erase(managed_global_memory &map, const char *name) + { + return map.destroy<ref_count_ptr>(name); + } + + template<class F> + static void atomic_func(managed_global_memory &map, F &f) + { + map.atomic_func(f); + } +}; + +} //namespace intermodule_singleton_helpers { + +template<typename C, bool LazyInit = true, bool Phoenix = true> +class portable_intermodule_singleton + : public intermodule_singleton_impl<C, LazyInit, Phoenix, managed_global_memory> +{}; + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP diff --git a/boost/interprocess/detail/posix_time_types_wrk.hpp b/boost/interprocess/detail/posix_time_types_wrk.hpp index c1276f0f26..e4df85a572 100644 --- a/boost/interprocess/detail/posix_time_types_wrk.hpp +++ b/boost/interprocess/detail/posix_time_types_wrk.hpp @@ -15,7 +15,7 @@ #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN #endif //#ifndef WIN32_LEAN_AND_MEAN #endif //#ifdef _WIN32 diff --git a/boost/interprocess/detail/preprocessor.hpp b/boost/interprocess/detail/preprocessor.hpp index 4af2686452..47b591c901 100644 --- a/boost/interprocess/detail/preprocessor.hpp +++ b/boost/interprocess/detail/preprocessor.hpp @@ -21,7 +21,7 @@ #error "This file is not needed when perfect forwarding is available" #endif -#include <boost/preprocessor/iteration/local.hpp> +#include <boost/preprocessor/iteration/local.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/repetition/enum.hpp> @@ -57,28 +57,30 @@ #ifndef BOOST_NO_RVALUE_REFERENCES -#ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES + #if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) -#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ - BOOST_PP_CAT(m_p, n) (BOOST_INTERPROCESS_MOVE_NAMESPACE::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) )) \ -//! + #define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \ + //! -#else -#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ - BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \ -//! + #else //#if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) -#endif + #define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) )) \ + //! -#else -#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ - BOOST_PP_CAT(m_p, n) (const_cast<BOOST_PP_CAT(P, n) &>(BOOST_PP_CAT(p, n))) \ -//! + #endif //#if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + +#else //#ifndef BOOST_NO_RVALUE_REFERENCES + + #define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (const_cast<BOOST_PP_CAT(P, n) &>(BOOST_PP_CAT(p, n))) \ + //! #endif #define BOOST_INTERPROCESS_PP_PARAM_INC(z, n, data) \ - BOOST_PP_CAT(++m_p, n) \ + BOOST_PP_CAT(++m_p, n) \ //! #ifndef BOOST_NO_RVALUE_REFERENCES diff --git a/boost/interprocess/detail/ptime_wrk.hpp b/boost/interprocess/detail/ptime_wrk.hpp index 4a4709e3a8..8cda3a445d 100644 --- a/boost/interprocess/detail/ptime_wrk.hpp +++ b/boost/interprocess/detail/ptime_wrk.hpp @@ -15,7 +15,7 @@ #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN #endif //#ifndef WIN32_LEAN_AND_MEAN #endif //#ifdef _WIN32 diff --git a/boost/interprocess/detail/robust_emulation.hpp b/boost/interprocess/detail/robust_emulation.hpp index b2097d0ad7..1feb42dc35 100644 --- a/boost/interprocess/detail/robust_emulation.hpp +++ b/boost/interprocess/detail/robust_emulation.hpp @@ -68,7 +68,7 @@ inline void robust_lock_path(std::string &s) inline void create_and_get_robust_lock_file_path(std::string &s, OS_process_id_t pid) { - file_locking_helpers::create_tmp_subdir_and_get_pid_based_filepath + intermodule_singleton_helpers::create_tmp_subdir_and_get_pid_based_filepath (robust_lock_subdir_path(), robust_lock_prefix(), pid, s); } @@ -132,7 +132,7 @@ class robust_mutex_lock_file throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: create_file filed with unexpected error"); } } - } + } ~robust_mutex_lock_file() { @@ -154,7 +154,7 @@ class robust_mutex_lock_file { std::string pid_str; //If the lock file is not our own lock file, then try to do the cleanup - if(!file_locking_helpers::check_if_filename_complies_with_pid + if(!intermodule_singleton_helpers::check_if_filename_complies_with_pid (filename, robust_lock_prefix(), get_current_process_id(), pid_str)){ remove_if_can_lock_file(filepath); } @@ -324,7 +324,7 @@ inline bool robust_spin_mutex<Mutex>::robust_check() return false; } atomic_write32(&this->state, fixing_state); - return true; + return true; } template<class Mutex> @@ -424,7 +424,7 @@ template<class Mutex> inline bool robust_spin_mutex<Mutex>::lock_own_unique_file() { //This function forces instantiation of the singleton - robust_emulation_helpers::robust_mutex_lock_file* dummy = + robust_emulation_helpers::robust_mutex_lock_file* dummy = &ipcdetail::intermodule_singleton <robust_emulation_helpers::robust_mutex_lock_file>::get(); return dummy != 0; diff --git a/boost/interprocess/detail/segment_manager_helper.hpp b/boost/interprocess/detail/segment_manager_helper.hpp index ea820b3881..2b715d8f5e 100644 --- a/boost/interprocess/detail/segment_manager_helper.hpp +++ b/boost/interprocess/detail/segment_manager_helper.hpp @@ -91,7 +91,7 @@ struct block_header , m_num_char((unsigned short)num_char) , m_value_alignment((unsigned char)value_alignment) , m_alloc_type_sizeof_char - ( (alloc_type << 5u) | + ( (alloc_type << 5u) | ((unsigned char)sizeof_char & 0x1F) ) {}; @@ -130,7 +130,7 @@ struct block_header template<class CharType> CharType *name() const - { + { return const_cast<CharType*>(reinterpret_cast<const CharType*> (reinterpret_cast<const char*>(this) + name_offset())); } @@ -139,7 +139,7 @@ struct block_header { return m_num_char; } size_type name_offset() const - { + { return this->value_offset() + get_rounded_size(size_type(m_value_bytes), size_type(sizeof_char())); } @@ -157,7 +157,7 @@ struct block_header bool less_comp(const block_header<size_type> &b) const { return m_num_char < b.m_num_char || - (m_num_char < b.m_num_char && + (m_num_char < b.m_num_char && std::char_traits<CharType>::compare (name<CharType>(), b.name<CharType>(), m_num_char) < 0); } @@ -175,10 +175,10 @@ struct block_header { return block_header_from_value(value, sizeof(T), ::boost::alignment_of<T>::value); } static block_header<size_type> *block_header_from_value(const void *value, std::size_t sz, std::size_t algn) - { - block_header * hdr = + { + block_header * hdr = const_cast<block_header*> - (reinterpret_cast<const block_header*>(reinterpret_cast<const char*>(value) - + (reinterpret_cast<const block_header*>(reinterpret_cast<const char*>(value) - get_rounded_size(sizeof(block_header), algn))); (void)sz; //Some sanity checks @@ -189,9 +189,9 @@ struct block_header template<class Header> static block_header<size_type> *from_first_header(Header *header) - { - block_header<size_type> * hdr = - reinterpret_cast<block_header<size_type>*>(reinterpret_cast<char*>(header) + + { + block_header<size_type> * hdr = + reinterpret_cast<block_header<size_type>*>(reinterpret_cast<char*>(header) + get_rounded_size(size_type(sizeof(Header)), size_type(::boost::alignment_of<block_header<size_type> >::value))); //Some sanity checks return hdr; @@ -199,9 +199,9 @@ struct block_header template<class Header> static Header *to_first_header(block_header<size_type> *bheader) - { - Header * hdr = - reinterpret_cast<Header*>(reinterpret_cast<char*>(bheader) - + { + Header * hdr = + reinterpret_cast<Header*>(reinterpret_cast<char*>(bheader) - get_rounded_size(size_type(sizeof(Header)), size_type(::boost::alignment_of<block_header<size_type> >::value))); //Some sanity checks return hdr; @@ -311,15 +311,15 @@ template<class CharType> class char_ptr_holder { public: - char_ptr_holder(const CharType *name) + char_ptr_holder(const CharType *name) : m_name(name) {} - char_ptr_holder(const anonymous_instance_t *) + char_ptr_holder(const anonymous_instance_t *) : m_name(static_cast<CharType*>(0)) {} - char_ptr_holder(const unique_instance_t *) + char_ptr_holder(const unique_instance_t *) : m_name(reinterpret_cast<CharType*>(-1)) {} @@ -330,7 +330,7 @@ class char_ptr_holder const CharType *m_name; }; -//!The key of the the named allocation information index. Stores an offset pointer +//!The key of the the named allocation information index. Stores an offset pointer //!to a null terminated string and the length of the string to speed up sorting template<class CharT, class VoidPointer> struct index_key @@ -356,9 +356,9 @@ struct index_key //!Less than function for index ordering bool operator < (const index_key & right) const { - return (m_len < right.m_len) || - (m_len == right.m_len && - std::char_traits<char_type>::compare + return (m_len < right.m_len) || + (m_len == right.m_len && + std::char_traits<char_type>::compare (to_raw_pointer(mp_str) ,to_raw_pointer(right.mp_str), m_len) < 0); } @@ -366,8 +366,8 @@ struct index_key //!Equal to function for index ordering bool operator == (const index_key & right) const { - return m_len == right.m_len && - std::char_traits<char_type>::compare + return m_len == right.m_len && + std::char_traits<char_type>::compare (to_raw_pointer(mp_str), to_raw_pointer(right.mp_str), m_len) == 0; } @@ -478,14 +478,14 @@ struct segment_manager_iterator_transform , segment_manager_iterator_value_adaptor<Iterator, intrusive> > { typedef segment_manager_iterator_value_adaptor<Iterator, intrusive> result_type; - + result_type operator()(const typename Iterator::value_type &arg) const { return result_type(arg); } }; } //namespace ipcdetail { -//These pointers are the ones the user will use to +//These pointers are the ones the user will use to //indicate previous allocation types static const ipcdetail::anonymous_instance_t * anonymous_instance = 0; static const ipcdetail::unique_instance_t * unique_instance = 0; diff --git a/boost/interprocess/detail/tmp_dir_helpers.hpp b/boost/interprocess/detail/tmp_dir_helpers.hpp index 38aafb2beb..28e7341406 100644 --- a/boost/interprocess/detail/tmp_dir_helpers.hpp +++ b/boost/interprocess/detail/tmp_dir_helpers.hpp @@ -18,80 +18,87 @@ #include <boost/interprocess/exceptions.hpp> #include <string> -#if defined(BOOST_INTERPROCESS_WINDOWS) - //#define BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME - //#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME - //#include <boost/interprocess/detail/win32_api.hpp> -#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) - //#include <sys/sysctl.h> - //#if defined(CTL_KERN) && defined (KERN_BOOTTIME) - //#define BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME - //#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME - //#endif +#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) && defined(BOOST_INTERPROCESS_WINDOWS) + #include <boost/interprocess/detail/windows_intermodule_singleton.hpp> #endif namespace boost { namespace interprocess { namespace ipcdetail { -#if defined (BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME) -inline void get_bootstamp(std::string &s, bool add = false) -{ - std::string bootstamp; - winapi::get_last_bootup_time(bootstamp); - if(add){ - s += bootstamp; - } - else{ - s.swap(bootstamp); - } -} -#elif defined(BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME) -inline void get_bootstamp(std::string &s, bool add = false) -{ - // FreeBSD specific: sysctl "kern.boottime" - int request[2] = { CTL_KERN, KERN_BOOTTIME }; - struct ::timeval result; - std::size_t result_len = sizeof result; - - if (::sysctl (request, 2, &result, &result_len, NULL, 0) < 0) - return; - - char bootstamp_str[256]; - - const char Characters [] = - { '0', '1', '2', '3', '4', '5', '6', '7' - , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - - std::size_t char_counter = 0; - //32 bit values to allow 32 and 64 bit process IPC - boost::uint32_t fields[2] = { boost::uint32_t(result.tv_sec), boost::uint32_t(result.tv_usec) }; - for(std::size_t field = 0; field != 2; ++field){ - for(std::size_t i = 0; i != sizeof(fields[0]); ++i){ - const char *ptr = (const char *)&fields[field]; - bootstamp_str[char_counter++] = Characters[(ptr[i]&0xF0)>>4]; - bootstamp_str[char_counter++] = Characters[(ptr[i]&0x0F)]; +#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + #if defined(BOOST_INTERPROCESS_WINDOWS) + //This type will initialize the stamp + struct windows_bootstamp + { + windows_bootstamp() + { + winapi::get_last_bootup_time(stamp); + } + //Use std::string. Even if this will be constructed in shared memory, all + //modules/dlls are from this process so internal raw pointers to heap are always valid + std::string stamp; + }; + + inline void get_bootstamp(std::string &s, bool add = false) + { + const windows_bootstamp &bootstamp = windows_intermodule_singleton<windows_bootstamp>::get(); + if(add){ + s += bootstamp.stamp; + } + else{ + s = bootstamp.stamp; + } } - } - bootstamp_str[char_counter] = 0; - if(add){ - s += bootstamp_str; - } - else{ - s = bootstamp_str; - } -} -#endif + #elif defined(BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME) + inline void get_bootstamp(std::string &s, bool add = false) + { + // FreeBSD specific: sysctl "kern.boottime" + int request[2] = { CTL_KERN, KERN_BOOTTIME }; + struct ::timeval result; + std::size_t result_len = sizeof result; + + if (::sysctl (request, 2, &result, &result_len, NULL, 0) < 0) + return; + + char bootstamp_str[256]; + + const char Characters [] = + { '0', '1', '2', '3', '4', '5', '6', '7' + , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + std::size_t char_counter = 0; + //32 bit values to allow 32 and 64 bit process IPC + boost::uint32_t fields[2] = { boost::uint32_t(result.tv_sec), boost::uint32_t(result.tv_usec) }; + for(std::size_t field = 0; field != 2; ++field){ + for(std::size_t i = 0; i != sizeof(fields[0]); ++i){ + const char *ptr = (const char *)&fields[field]; + bootstamp_str[char_counter++] = Characters[(ptr[i]&0xF0)>>4]; + bootstamp_str[char_counter++] = Characters[(ptr[i]&0x0F)]; + } + } + bootstamp_str[char_counter] = 0; + if(add){ + s += bootstamp_str; + } + else{ + s = bootstamp_str; + } + } + #else + #error "BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME defined with no known implementation" + #endif +#endif //#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) inline void get_tmp_base_dir(std::string &tmp_name) { #if defined (BOOST_INTERPROCESS_WINDOWS) - winapi::get_shared_documents_folder(tmp_name); - if(tmp_name.empty() || !winapi::is_directory(tmp_name.c_str())){ - tmp_name = get_temporary_path(); - } + winapi::get_shared_documents_folder(tmp_name); + if(tmp_name.empty() || !winapi::is_directory(tmp_name.c_str())){ + tmp_name = get_temporary_path(); + } #else - tmp_name = get_temporary_path(); + tmp_name = get_temporary_path(); #endif if(tmp_name.empty()){ error_info err = system_error_code(); @@ -104,9 +111,9 @@ inline void get_tmp_base_dir(std::string &tmp_name) inline void tmp_folder(std::string &tmp_name) { get_tmp_base_dir(tmp_name); - #ifdef BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME - tmp_name += "/"; - get_bootstamp(tmp_name, true); + #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + tmp_name += "/"; + get_bootstamp(tmp_name, true); #endif } @@ -131,22 +138,22 @@ inline void create_tmp_and_clean_old(std::string &tmp_name) } } - #ifdef BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME - tmp_folder(tmp_name); + #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + tmp_folder(tmp_name); - //If fails, check that it's because already exists - if(!create_directory(tmp_name.c_str())){ - error_info info(system_error_code()); - if(info.get_error_code() != already_exists_error){ - throw interprocess_exception(info); + //If fails, check that it's because already exists + if(!create_directory(tmp_name.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } } - } - //Now erase all old directories created in the previous boot sessions - std::string subdir = tmp_name; - subdir.erase(0, root_tmp_name.size()+1); - delete_subdirectories(root_tmp_name, subdir.c_str()); + //Now erase all old directories created in the previous boot sessions + std::string subdir = tmp_name; + subdir.erase(0, root_tmp_name.size()+1); + delete_subdirectories(root_tmp_name, subdir.c_str()); #else - tmp_name = root_tmp_name; + tmp_name = root_tmp_name; #endif } diff --git a/boost/interprocess/detail/transform_iterator.hpp b/boost/interprocess/detail/transform_iterator.hpp index ef646fbefe..922c875d6d 100644 --- a/boost/interprocess/detail/transform_iterator.hpp +++ b/boost/interprocess/detail/transform_iterator.hpp @@ -27,7 +27,7 @@ #include <boost/interprocess/detail/type_traits.hpp> namespace boost { -namespace interprocess { +namespace interprocess { template <class PseudoReference> struct operator_arrow_proxy @@ -77,7 +77,7 @@ class transform_iterator {} //Constructors - transform_iterator& operator++() + transform_iterator& operator++() { increment(); return *this; } transform_iterator operator++(int) @@ -87,7 +87,7 @@ class transform_iterator return result; } - transform_iterator& operator--() + transform_iterator& operator--() { decrement(); return *this; } transform_iterator operator--(int) @@ -186,7 +186,7 @@ make_transform_iterator(Iterator it, UnaryFunc fun) return transform_iterator<Iterator, UnaryFunc>(it, fun); } -} //namespace interprocess { +} //namespace interprocess { } //namespace boost { #include <boost/interprocess/detail/config_end.hpp> diff --git a/boost/interprocess/detail/type_traits.hpp b/boost/interprocess/detail/type_traits.hpp index 2cfa0be291..7a582fee5c 100644 --- a/boost/interprocess/detail/type_traits.hpp +++ b/boost/interprocess/detail/type_traits.hpp @@ -20,7 +20,7 @@ #include <boost/interprocess/detail/config_begin.hpp> namespace boost { -namespace interprocess { +namespace interprocess { namespace ipcdetail { struct nat{}; @@ -137,7 +137,7 @@ struct is_same }; } // namespace ipcdetail -} //namespace interprocess { +} //namespace interprocess { } //namespace boost { #include <boost/interprocess/detail/config_end.hpp> diff --git a/boost/interprocess/detail/utilities.hpp b/boost/interprocess/detail/utilities.hpp index 625a9159d3..fcb211fb09 100644 --- a/boost/interprocess/detail/utilities.hpp +++ b/boost/interprocess/detail/utilities.hpp @@ -35,7 +35,7 @@ #include <algorithm> namespace boost { -namespace interprocess { +namespace interprocess { namespace ipcdetail { template <class T> @@ -138,9 +138,9 @@ template<class Cont> class value_eraser { public: - value_eraser(Cont & cont, typename Cont::iterator it) + value_eraser(Cont & cont, typename Cont::iterator it) : m_cont(cont), m_index_it(it), m_erase(true){} - ~value_eraser() + ~value_eraser() { if(m_erase) m_cont.erase(m_index_it); } void release() { m_erase = false; } @@ -151,7 +151,7 @@ class value_eraser bool m_erase; }; -} //namespace interprocess { +} //namespace interprocess { } //namespace boost { #include <boost/interprocess/detail/config_end.hpp> diff --git a/boost/interprocess/detail/variadic_templates_tools.hpp b/boost/interprocess/detail/variadic_templates_tools.hpp index 1e6c4216e3..482a0056a7 100644 --- a/boost/interprocess/detail/variadic_templates_tools.hpp +++ b/boost/interprocess/detail/variadic_templates_tools.hpp @@ -21,7 +21,7 @@ #include <cstddef> //std::size_t namespace boost { -namespace interprocess { +namespace interprocess { namespace ipcdetail { template<typename... Values> @@ -136,7 +136,7 @@ struct index_tuple{}; template<std::size_t Num, typename Tuple = index_tuple<> > struct build_number_seq; -template<std::size_t Num, int... Indexes> +template<std::size_t Num, int... Indexes> struct build_number_seq<Num, index_tuple<Indexes...> > : build_number_seq<Num - 1, index_tuple<Indexes..., sizeof...(Indexes)> > {}; diff --git a/boost/interprocess/detail/win32_api.hpp b/boost/interprocess/detail/win32_api.hpp index b420c3d67b..c53725ca3b 100644 --- a/boost/interprocess/detail/win32_api.hpp +++ b/boost/interprocess/detail/win32_api.hpp @@ -46,6 +46,7 @@ namespace winapi { //Some used constants static const unsigned long infinite_time = 0xFFFFFFFF; static const unsigned long error_already_exists = 183L; +static const unsigned long error_invalid_handle = 6L; static const unsigned long error_sharing_violation = 32L; static const unsigned long error_file_not_found = 2u; static const unsigned long error_no_more_files = 18u; @@ -137,7 +138,14 @@ static const unsigned long lang_neutral = (unsigned long)0x00; static const unsigned long sublang_default = (unsigned long)0x01; static const unsigned long invalid_file_size = (unsigned long)0xFFFFFFFF; static const unsigned long invalid_file_attributes = ((unsigned long)-1); -static void * const invalid_handle_value = (void*)(long)(-1); +static void * const invalid_handle_value = ((void*)(long)(-1)); + +static const unsigned long file_type_char = 0x0002L; +static const unsigned long file_type_disk = 0x0001L; +static const unsigned long file_type_pipe = 0x0003L; +static const unsigned long file_type_remote = 0x8000L; +static const unsigned long file_type_unknown = 0x0000L; + static const unsigned long create_new = 1; static const unsigned long create_always = 2; static const unsigned long open_existing = 3; @@ -159,7 +167,6 @@ static const long BootAndSystemstampLength = 16; static const long BootstampLength = 8; static const unsigned long MaxPath = 260; - //Keys static void * const hkey_local_machine = (void*)(unsigned long*)(long)(0x80000002); static unsigned long key_query_value = 0x0001; @@ -179,6 +186,27 @@ const signed long WBEM_INFINITE_BIPC = 0xffffffffL; const signed long RPC_E_TOO_LATE_BIPC = 0x80010119L; const signed long S_OK_BIPC = 0L; const signed long S_FALSE_BIPC = 1; +const signed long RPC_E_CHANGED_MODE_BIPC = 0x80010106L; +const unsigned long COINIT_APARTMENTTHREADED_BIPC = 0x2; +const unsigned long COINIT_MULTITHREADED_BIPC = 0x0; +const unsigned long COINIT_DISABLE_OLE1DDE_BIPC = 0x4; +const unsigned long COINIT_SPEED_OVER_MEMORY_BIPC = 0x4; + +//If the user needs to change default COM initialization model, +//it can define BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL to one of these: +// +// COINIT_APARTMENTTHREADED_BIPC +// COINIT_MULTITHREADED_BIPC +// COINIT_DISABLE_OLE1DDE_BIPC +// COINIT_SPEED_OVER_MEMORY_BIPC +#if !defined(BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL) + #define BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL COINIT_APARTMENTTHREADED_BIPC +#elif (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_APARTMENTTHREADED_BIPC) &&\ + (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_MULTITHREADED_BIPC) &&\ + (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_DISABLE_OLE1DDE_BIPC) &&\ + (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_SPEED_OVER_MEMORY_BIPC) + #error "Wrong value for BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL macro" +#endif } //namespace winapi { } //namespace interprocess { @@ -214,158 +242,158 @@ struct wchar_variant struct IUnknown_BIPC { public: - virtual long __stdcall QueryInterface( + virtual long __stdcall QueryInterface( /* [in] */ const GUID_BIPC &riid, /* [iid_is][out] */ void **ppvObject) = 0; - + virtual unsigned long __stdcall AddRef( void) = 0; - + virtual unsigned long __stdcall Release( void) = 0; }; struct IWbemClassObject_BIPC : public IUnknown_BIPC { public: - virtual long __stdcall GetQualifierSet( + virtual long __stdcall GetQualifierSet( /* [out] */ void **ppQualSet) = 0; - - virtual long __stdcall Get( + + virtual long __stdcall Get( /* [string][in] */ const wchar_t * wszName, /* [in] */ long lFlags, /* [unique][in][out] */ wchar_variant *pVal, /* [unique][in][out] */ long *pType, /* [unique][in][out] */ long *plFlavor) = 0; - - virtual long __stdcall Put( + + virtual long __stdcall Put( /* [string][in] */ const wchar_t * wszName, /* [in] */ long lFlags, /* [in] */ wchar_variant *pVal, /* [in] */ long Type) = 0; - - virtual long __stdcall Delete( + + virtual long __stdcall Delete( /* [string][in] */ const wchar_t * wszName) = 0; - - virtual long __stdcall GetNames( + + virtual long __stdcall GetNames( /* [string][in] */ const wchar_t * wszQualifierName, /* [in] */ long lFlags, /* [in] */ wchar_variant *pQualifierVal, /* [out] */ void * *pNames) = 0; - - virtual long __stdcall BeginEnumeration( + + virtual long __stdcall BeginEnumeration( /* [in] */ long lEnumFlags) = 0; - - virtual long __stdcall Next( + + virtual long __stdcall Next( /* [in] */ long lFlags, /* [unique][in][out] */ wchar_t * *strName, /* [unique][in][out] */ wchar_variant *pVal, /* [unique][in][out] */ long *pType, /* [unique][in][out] */ long *plFlavor) = 0; - + virtual long __stdcall EndEnumeration( void) = 0; - - virtual long __stdcall GetPropertyQualifierSet( + + virtual long __stdcall GetPropertyQualifierSet( /* [string][in] */ const wchar_t * wszProperty, /* [out] */ void **ppQualSet) = 0; - - virtual long __stdcall Clone( + + virtual long __stdcall Clone( /* [out] */ IWbemClassObject_BIPC **ppCopy) = 0; - - virtual long __stdcall GetObjectText( + + virtual long __stdcall GetObjectText( /* [in] */ long lFlags, /* [out] */ wchar_t * *pstrObjectText) = 0; - - virtual long __stdcall SpawnDerivedClass( + + virtual long __stdcall SpawnDerivedClass( /* [in] */ long lFlags, /* [out] */ IWbemClassObject_BIPC **ppNewClass) = 0; - - virtual long __stdcall SpawnInstance( + + virtual long __stdcall SpawnInstance( /* [in] */ long lFlags, /* [out] */ IWbemClassObject_BIPC **ppNewInstance) = 0; - - virtual long __stdcall CompareTo( + + virtual long __stdcall CompareTo( /* [in] */ long lFlags, /* [in] */ IWbemClassObject_BIPC *pCompareTo) = 0; - - virtual long __stdcall GetPropertyOrigin( + + virtual long __stdcall GetPropertyOrigin( /* [string][in] */ const wchar_t * wszName, /* [out] */ wchar_t * *pstrClassName) = 0; - - virtual long __stdcall InheritsFrom( + + virtual long __stdcall InheritsFrom( /* [in] */ const wchar_t * strAncestor) = 0; - - virtual long __stdcall GetMethod( + + virtual long __stdcall GetMethod( /* [string][in] */ const wchar_t * wszName, /* [in] */ long lFlags, /* [out] */ IWbemClassObject_BIPC **ppInSignature, /* [out] */ IWbemClassObject_BIPC **ppOutSignature) = 0; - - virtual long __stdcall PutMethod( + + virtual long __stdcall PutMethod( /* [string][in] */ const wchar_t * wszName, /* [in] */ long lFlags, /* [in] */ IWbemClassObject_BIPC *pInSignature, /* [in] */ IWbemClassObject_BIPC *pOutSignature) = 0; - - virtual long __stdcall DeleteMethod( + + virtual long __stdcall DeleteMethod( /* [string][in] */ const wchar_t * wszName) = 0; - - virtual long __stdcall BeginMethodEnumeration( + + virtual long __stdcall BeginMethodEnumeration( /* [in] */ long lEnumFlags) = 0; - - virtual long __stdcall NextMethod( + + virtual long __stdcall NextMethod( /* [in] */ long lFlags, /* [unique][in][out] */ wchar_t * *pstrName, /* [unique][in][out] */ IWbemClassObject_BIPC **ppInSignature, /* [unique][in][out] */ IWbemClassObject_BIPC **ppOutSignature) = 0; - + virtual long __stdcall EndMethodEnumeration( void) = 0; - - virtual long __stdcall GetMethodQualifierSet( + + virtual long __stdcall GetMethodQualifierSet( /* [string][in] */ const wchar_t * wszMethod, /* [out] */ void **ppQualSet) = 0; - - virtual long __stdcall GetMethodOrigin( + + virtual long __stdcall GetMethodOrigin( /* [string][in] */ const wchar_t * wszMethodName, /* [out] */ wchar_t * *pstrClassName) = 0; - + }; struct IWbemContext_BIPC : public IUnknown_BIPC { public: - virtual long __stdcall Clone( + virtual long __stdcall Clone( /* [out] */ IWbemContext_BIPC **ppNewCopy) = 0; - - virtual long __stdcall GetNames( + + virtual long __stdcall GetNames( /* [in] */ long lFlags, /* [out] */ void * *pNames) = 0; - - virtual long __stdcall BeginEnumeration( + + virtual long __stdcall BeginEnumeration( /* [in] */ long lFlags) = 0; - - virtual long __stdcall Next( + + virtual long __stdcall Next( /* [in] */ long lFlags, /* [out] */ wchar_t * *pstrName, /* [out] */ wchar_variant *pValue) = 0; - + virtual long __stdcall EndEnumeration( void) = 0; - - virtual long __stdcall SetValue( + + virtual long __stdcall SetValue( /* [string][in] */ const wchar_t * wszName, /* [in] */ long lFlags, /* [in] */ wchar_variant *pValue) = 0; - - virtual long __stdcall GetValue( + + virtual long __stdcall GetValue( /* [string][in] */ const wchar_t * wszName, /* [in] */ long lFlags, /* [out] */ wchar_variant *pValue) = 0; - - virtual long __stdcall DeleteValue( + + virtual long __stdcall DeleteValue( /* [string][in] */ const wchar_t * wszName, /* [in] */ long lFlags) = 0; - + virtual long __stdcall DeleteAll( void) = 0; - + }; @@ -373,157 +401,157 @@ struct IEnumWbemClassObject_BIPC : public IUnknown_BIPC { public: virtual long __stdcall Reset( void) = 0; - - virtual long __stdcall Next( + + virtual long __stdcall Next( /* [in] */ long lTimeout, /* [in] */ unsigned long uCount, /* [length_is][size_is][out] */ IWbemClassObject_BIPC **apObjects, /* [out] */ unsigned long *puReturned) = 0; - - virtual long __stdcall NextAsync( + + virtual long __stdcall NextAsync( /* [in] */ unsigned long uCount, /* [in] */ void *pSink) = 0; - - virtual long __stdcall Clone( + + virtual long __stdcall Clone( /* [out] */ void **ppEnum) = 0; - - virtual long __stdcall Skip( + + virtual long __stdcall Skip( /* [in] */ long lTimeout, /* [in] */ unsigned long nCount) = 0; - + }; struct IWbemServices_BIPC : public IUnknown_BIPC { public: - virtual long __stdcall OpenNamespace( + virtual long __stdcall OpenNamespace( /* [in] */ const wchar_t * strNamespace, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [unique][in][out] */ void **ppWorkingNamespace, /* [unique][in][out] */ void **ppResult) = 0; - - virtual long __stdcall CancelAsyncCall( + + virtual long __stdcall CancelAsyncCall( /* [in] */ void *pSink) = 0; - - virtual long __stdcall QueryObjectSink( + + virtual long __stdcall QueryObjectSink( /* [in] */ long lFlags, /* [out] */ void **ppResponseHandler) = 0; - - virtual long __stdcall GetObject( + + virtual long __stdcall GetObject( /* [in] */ const wchar_t * strObjectPath, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [unique][in][out] */ void **ppObject, /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall GetObjectAsync( + + virtual long __stdcall GetObjectAsync( /* [in] */ const wchar_t * strObjectPath, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall PutClass( + + virtual long __stdcall PutClass( /* [in] */ IWbemClassObject_BIPC *pObject, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall PutClassAsync( + + virtual long __stdcall PutClassAsync( /* [in] */ IWbemClassObject_BIPC *pObject, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall DeleteClass( + + virtual long __stdcall DeleteClass( /* [in] */ const wchar_t * strClass, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall DeleteClassAsync( + + virtual long __stdcall DeleteClassAsync( /* [in] */ const wchar_t * strClass, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall CreateClassEnum( + + virtual long __stdcall CreateClassEnum( /* [in] */ const wchar_t * strSuperclass, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [out] */ void **ppEnum) = 0; - - virtual long __stdcall CreateClassEnumAsync( + + virtual long __stdcall CreateClassEnumAsync( /* [in] */ const wchar_t * strSuperclass, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall PutInstance( + + virtual long __stdcall PutInstance( /* [in] */ void *pInst, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall PutInstanceAsync( + + virtual long __stdcall PutInstanceAsync( /* [in] */ void *pInst, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall DeleteInstance( + + virtual long __stdcall DeleteInstance( /* [in] */ const wchar_t * strObjectPath, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall DeleteInstanceAsync( + + virtual long __stdcall DeleteInstanceAsync( /* [in] */ const wchar_t * strObjectPath, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall CreateInstanceEnum( + + virtual long __stdcall CreateInstanceEnum( /* [in] */ const wchar_t * strFilter, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [out] */ void **ppEnum) = 0; - - virtual long __stdcall CreateInstanceEnumAsync( + + virtual long __stdcall CreateInstanceEnumAsync( /* [in] */ const wchar_t * strFilter, /* [in] */ long lFlags, /* [in] */ void *pCtx, /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall ExecQuery( + + virtual long __stdcall ExecQuery( /* [in] */ const wchar_t * strQueryLanguage, /* [in] */ const wchar_t * strQuery, /* [in] */ long lFlags, /* [in] */ IWbemContext_BIPC *pCtx, /* [out] */ IEnumWbemClassObject_BIPC **ppEnum) = 0; - virtual long __stdcall ExecQueryAsync( + virtual long __stdcall ExecQueryAsync( /* [in] */ const wchar_t * strQueryLanguage, /* [in] */ const wchar_t * strQuery, /* [in] */ long lFlags, /* [in] */ IWbemContext_BIPC *pCtx, /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall ExecNotificationQuery( + + virtual long __stdcall ExecNotificationQuery( /* [in] */ const wchar_t * strQueryLanguage, /* [in] */ const wchar_t * strQuery, /* [in] */ long lFlags, /* [in] */ IWbemContext_BIPC *pCtx, /* [out] */ void **ppEnum) = 0; - - virtual long __stdcall ExecNotificationQueryAsync( + + virtual long __stdcall ExecNotificationQueryAsync( /* [in] */ const wchar_t * strQueryLanguage, /* [in] */ const wchar_t * strQuery, /* [in] */ long lFlags, /* [in] */ IWbemContext_BIPC *pCtx, /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall ExecMethod( + + virtual long __stdcall ExecMethod( /* [in] */ const wchar_t * strObjectPath, /* [in] */ const wchar_t * strMethodName, /* [in] */ long lFlags, @@ -531,21 +559,21 @@ public: /* [in] */ IWbemClassObject_BIPC *pInParams, /* [unique][in][out] */ IWbemClassObject_BIPC **ppOutParams, /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall ExecMethodAsync( + + virtual long __stdcall ExecMethodAsync( /* [in] */ const wchar_t * strObjectPath, /* [in] */ const wchar_t * strMethodName, /* [in] */ long lFlags, /* [in] */ IWbemContext_BIPC *pCtx, /* [in] */ IWbemClassObject_BIPC *pInParams, /* [in] */ void *pResponseHandler) = 0; - + }; struct IWbemLocator_BIPC : public IUnknown_BIPC { public: - virtual long __stdcall ConnectServer( + virtual long __stdcall ConnectServer( /* [in] */ const wchar_t * strNetworkResource, /* [in] */ const wchar_t * strUser, /* [in] */ const wchar_t * strPassword, @@ -554,12 +582,12 @@ public: /* [in] */ const wchar_t * strAuthority, /* [in] */ void *pCtx, /* [out] */ IWbemServices_BIPC **ppNamespace) = 0; - + }; - -struct interprocess_overlapped + +struct interprocess_overlapped { unsigned long *internal; unsigned long *internal_high; @@ -574,9 +602,22 @@ struct interprocess_overlapped void *h_event; }; +struct interprocess_semaphore_basic_information +{ + unsigned int count; // current semaphore count + unsigned int limit; // max semaphore count +}; + +struct interprocess_section_basic_information +{ + void * base_address; + unsigned long section_attributes; + __int64 section_size; +}; + struct interprocess_filetime -{ - unsigned long dwLowDateTime; +{ + unsigned long dwLowDateTime; unsigned long dwHighDateTime; }; @@ -620,16 +661,16 @@ struct system_info { unsigned short wProcessorRevision; }; -struct interprocess_memory_basic_information +typedef struct _interprocess_memory_basic_information { - void * BaseAddress; + void * BaseAddress; void * AllocationBase; unsigned long AllocationProtect; unsigned long RegionSize; unsigned long State; unsigned long Protect; unsigned long Type; -}; +} interprocess_memory_basic_information; typedef struct _interprocess_acl { @@ -695,6 +736,10 @@ enum file_information_class_t { file_maximum_information }; +enum semaphore_information_class { + semaphore_basic_information = 0 +}; + struct file_name_information_t { unsigned long FileNameLength; wchar_t FileName[1]; @@ -779,6 +824,12 @@ enum object_information_class object_data_information }; +enum section_information_class +{ + section_basic_information, + section_image_information +}; + struct object_name_information_t { unicode_string_t Name; @@ -803,6 +854,7 @@ extern "C" __declspec(dllimport) int __stdcall DuplicateHandle , void *hTargetProcessHandle, void **lpTargetHandle , unsigned long dwDesiredAccess, int bInheritHandle , unsigned long dwOptions); +extern "C" __declspec(dllimport) long __stdcall GetFileType(void *hFile); extern "C" __declspec(dllimport) void *__stdcall FindFirstFileA(const char *lpFileName, win32_find_data_t *lpFindFileData); extern "C" __declspec(dllimport) int __stdcall FindNextFileA(void *hFindFile, win32_find_data_t *lpFindFileData); extern "C" __declspec(dllimport) int __stdcall FindClose(void *hFindFile); @@ -827,8 +879,8 @@ extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile (void *, std::siz extern "C" __declspec(dllimport) int __stdcall FlushFileBuffers (void *); extern "C" __declspec(dllimport) int __stdcall GetFileSizeEx (void *, __int64 *size); extern "C" __declspec(dllimport) unsigned long __stdcall FormatMessageA - (unsigned long dwFlags, const void *lpSource, unsigned long dwMessageId, - unsigned long dwLanguageId, char *lpBuffer, unsigned long nSize, + (unsigned long dwFlags, const void *lpSource, unsigned long dwMessageId, + unsigned long dwLanguageId, char *lpBuffer, unsigned long nSize, std::va_list *Arguments); extern "C" __declspec(dllimport) void *__stdcall LocalFree (void *); extern "C" __declspec(dllimport) unsigned long __stdcall GetFileAttributesA(const char *); @@ -844,6 +896,7 @@ extern "C" __declspec(dllimport) int __stdcall UnlockFile(void *hnd, unsigned lo extern "C" __declspec(dllimport) int __stdcall LockFileEx(void *hnd, unsigned long flags, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped* overlapped); extern "C" __declspec(dllimport) int __stdcall UnlockFileEx(void *hnd, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped* overlapped); extern "C" __declspec(dllimport) int __stdcall WriteFile(void *hnd, const void *buffer, unsigned long bytes_to_write, unsigned long *bytes_written, interprocess_overlapped* overlapped); +extern "C" __declspec(dllimport) int __stdcall ReadFile(void *hnd, void *buffer, unsigned long bytes_to_read, unsigned long *bytes_read, interprocess_overlapped* overlapped); extern "C" __declspec(dllimport) int __stdcall InitializeSecurityDescriptor(interprocess_security_descriptor *pSecurityDescriptor, unsigned long dwRevision); extern "C" __declspec(dllimport) int __stdcall SetSecurityDescriptorDacl(interprocess_security_descriptor *pSecurityDescriptor, int bDaclPresent, interprocess_acl *pDacl, int bDaclDefaulted); extern "C" __declspec(dllimport) void *__stdcall LoadLibraryA(const char *); @@ -858,17 +911,17 @@ extern "C" __declspec(dllimport) long __stdcall RegCloseKey(void *); extern "C" __declspec(dllimport) int __stdcall QueryPerformanceCounter(__int64 *lpPerformanceCount); //COM API -extern "C" __declspec(dllimport) long __stdcall CoInitialize(void *pvReserved); +extern "C" __declspec(dllimport) long __stdcall CoInitializeEx(void *pvReserved, unsigned long dwCoInit); extern "C" __declspec(dllimport) long __stdcall CoInitializeSecurity( - void* pSecDesc, - long cAuthSvc, - void *asAuthSvc, - void *pReserved1, - unsigned long dwAuthnLevel, - unsigned long dwImpLevel, - void *pAuthList, - unsigned long dwCapabilities, - void *pReserved3 ); + void* pSecDesc, + long cAuthSvc, + void * asAuthSvc, + void *pReserved1, + unsigned long dwAuthnLevel, + unsigned long dwImpLevel, + void *pAuthList, + unsigned long dwCapabilities, + void *pReserved3 ); extern "C" __declspec(dllimport) long __stdcall CoSetProxyBlanket( IUnknown_BIPC *pProxy, @@ -889,10 +942,12 @@ extern "C" __declspec(dllimport) void __stdcall CoUninitialize(void); //API function typedefs //Pointer to functions -typedef long (__stdcall *NtDeleteFile_t)(object_attributes_t *ObjectAttributes); -typedef long (__stdcall *NtSetInformationFile_t)(void *FileHandle, io_status_block_t *IoStatusBlock, void *FileInformation, unsigned long Length, int FileInformationClass ); -typedef long (__stdcall * NtQuerySystemInformation_t)(int, void*, unsigned long, unsigned long *); -typedef long (__stdcall * NtQueryObject_t)(void*, object_information_class, void *, unsigned long, unsigned long *); +typedef long (__stdcall *NtDeleteFile_t)(object_attributes_t *ObjectAttributes); +typedef long (__stdcall *NtSetInformationFile_t)(void *FileHandle, io_status_block_t *IoStatusBlock, void *FileInformation, unsigned long Length, int FileInformationClass ); +typedef long (__stdcall *NtQuerySystemInformation_t)(int, void*, unsigned long, unsigned long *); +typedef long (__stdcall *NtQueryObject_t)(void*, object_information_class, void *, unsigned long, unsigned long *); +typedef long (__stdcall *NtQuerySemaphore_t)(void*, unsigned int info_class, interprocess_semaphore_basic_information *pinfo, unsigned int info_size, unsigned int *ret_len); +typedef long (__stdcall *NtQuerySection_t)(void*, section_information_class, interprocess_section_basic_information *pinfo, unsigned long info_size, unsigned long *ret_len); typedef long (__stdcall *NtQueryInformationFile_t)(void *,io_status_block_t *,void *, long, int); typedef long (__stdcall *NtOpenFile_t)(void*,unsigned long ,object_attributes_t*,io_status_block_t*,unsigned long,unsigned long); typedef long (__stdcall *NtClose_t) (void*); @@ -977,6 +1032,12 @@ inline bool duplicate_current_process_handle , lpTargetHandle, 0, 0 , duplicate_same_access); } + +inline long get_file_type(void *hFile) +{ + return GetFileType(hFile); +} + /* inline void get_system_time_as_file_time(interprocess_filetime *filetime) { GetSystemTimeAsFileTime(filetime); } @@ -1000,13 +1061,16 @@ inline int unmap_view_of_file(void *address) inline void *open_or_create_semaphore(const char *name, long initial_count, long maximum_count, interprocess_security_attributes *attr) { return CreateSemaphoreA(attr, initial_count, maximum_count, name); } +inline void *open_semaphore(const char *name) +{ return OpenSemaphoreA(semaphore_all_access, 0, name); } + inline int release_semaphore(void *handle, long release_count, long *prev_count) { return ReleaseSemaphore(handle, release_count, prev_count); } class interprocess_all_access_security { interprocess_security_attributes sa; - interprocess_security_descriptor sd; + interprocess_security_descriptor sd; bool initialized; public: @@ -1027,16 +1091,21 @@ class interprocess_all_access_security { return &sa; } }; -inline void * create_file_mapping (void * handle, unsigned long access, unsigned long high_size, unsigned long low_size, const char * name, interprocess_security_attributes *psec) +inline void * create_file_mapping (void * handle, unsigned long access, unsigned __int64 file_offset, const char * name, interprocess_security_attributes *psec) { - return CreateFileMappingA (handle, psec, access, high_size, low_size, name); + const unsigned long high_size(file_offset >> 32), low_size((boost::uint32_t)file_offset); + return CreateFileMappingA (handle, psec, access, high_size, low_size, name); } inline void * open_file_mapping (unsigned long access, const char *name) { return OpenFileMappingA (access, 0, name); } -inline void *map_view_of_file_ex(void *handle, unsigned long file_access, unsigned long highoffset, unsigned long lowoffset, std::size_t numbytes, void *base_addr) -{ return MapViewOfFileEx(handle, file_access, highoffset, lowoffset, numbytes, base_addr); } +inline void *map_view_of_file_ex(void *handle, unsigned long file_access, unsigned __int64 offset, std::size_t numbytes, void *base_addr) +{ + const unsigned long offset_low = (unsigned long)(offset & ((unsigned __int64)0xFFFFFFFF)); + const unsigned long offset_high = offset >> 32; + return MapViewOfFileEx(handle, file_access, offset_high, offset_low, numbytes, base_addr); +} inline void *create_file(const char *name, unsigned long access, unsigned long creation_flags, unsigned long attributes, interprocess_security_attributes *psec) { @@ -1051,7 +1120,7 @@ inline void *create_file(const char *name, unsigned long access, unsigned long c if (error_sharing_violation != get_last_error()){ return handle; } - Sleep(error_sharing_violation_sleep_ms); + sleep(error_sharing_violation_sleep_ms); } return invalid_handle_value; } @@ -1075,9 +1144,9 @@ inline bool get_file_size(void *handle, __int64 &size) { return 0 != GetFileSizeEx(handle, &size); } inline bool create_directory(const char *name) -{ +{ interprocess_all_access_security sec; - return 0 != CreateDirectoryA(name, sec.get_attributes()); + return 0 != CreateDirectoryA(name, sec.get_attributes()); } inline bool remove_directory(const char *lpPathName) @@ -1101,6 +1170,9 @@ inline bool unlock_file_ex(void *hnd, unsigned long reserved, unsigned long size inline bool write_file(void *hnd, const void *buffer, unsigned long bytes_to_write, unsigned long *bytes_written, interprocess_overlapped* overlapped) { return 0 != WriteFile(hnd, buffer, bytes_to_write, bytes_written, overlapped); } +inline bool read_file(void *hnd, void *buffer, unsigned long bytes_to_read, unsigned long *bytes_read, interprocess_overlapped* overlapped) +{ return 0 != ReadFile(hnd, buffer, bytes_to_read, bytes_read, overlapped); } + inline bool get_file_information_by_handle(void *hnd, interprocess_by_handle_file_information *info) { return 0 != GetFileInformationByHandle(hnd, info); } @@ -1176,7 +1248,7 @@ inline void rtl_init_empty_unicode_string(unicode_string_t *ucStr, wchar_t *buf, template<int Dummy> struct function_address_holder { - enum { NtSetInformationFile, NtQuerySystemInformation, NtQueryObject, NumFunction }; + enum { NtSetInformationFile, NtQuerySystemInformation, NtQueryObject, NtQuerySemaphore, NtQuerySection, NumFunction }; enum { NtDll_dll, NumModule }; private: @@ -1213,7 +1285,7 @@ struct function_address_holder static void *get_address_from_dll(const unsigned int id) { assert(id < (unsigned int)NumFunction); - const char *function[] = { "NtSetInformationFile", "NtQuerySystemInformation", "NtQueryObject" }; + const char *function[] = { "NtSetInformationFile", "NtQuerySystemInformation", "NtQueryObject", "NtQuerySemaphore", "NtQuerySection" }; bool compile_check[sizeof(function)/sizeof(function[0]) == NumFunction]; (void)compile_check; return get_proc_address(get_module(NtDll_dll), function[id]); @@ -1264,7 +1336,7 @@ struct library_unloader //pszFilename must have room for at least MaxPath+1 characters inline bool get_file_name_from_handle_function - (void * hFile, wchar_t *pszFilename, std::size_t length, std::size_t &out_length) + (void * hFile, wchar_t *pszFilename, std::size_t length, std::size_t &out_length) { if(length <= MaxPath){ return false; @@ -1285,17 +1357,17 @@ inline bool get_file_name_from_handle_function bool bSuccess = false; // Create a file mapping object. - void * hFileMap = create_file_mapping(hFile, page_readonly, 0, 1, 0, 0); + void * hFileMap = create_file_mapping(hFile, page_readonly, 1, 0, 0); if(hFileMap){ // Create a file mapping to get the file name. - void* pMem = map_view_of_file_ex(hFileMap, file_map_read, 0, 0, 1, 0); + void* pMem = map_view_of_file_ex(hFileMap, file_map_read, 0, 1, 0); if (pMem){ //out_length = pfGMFN(get_current_process(), pMem, pszFilename, MaxPath); out_length = get_mapped_file_name(get_current_process(), pMem, pszFilename, MaxPath); if(out_length){ bSuccess = true; - } + } unmap_view_of_file(pMem); } close_handle(hFileMap); @@ -1307,7 +1379,6 @@ inline bool get_file_name_from_handle_function inline bool get_system_time_of_day_information(system_timeofday_information &info) { NtQuerySystemInformation_t pNtQuerySystemInformation = (NtQuerySystemInformation_t) - //get_proc_address(get_module_handle("ntdll.dll"), "NtQuerySystemInformation"); dll_func::get(dll_func::NtQuerySystemInformation); unsigned long res; long status = pNtQuerySystemInformation(system_time_of_day_information, &info, sizeof(info), &res); @@ -1384,9 +1455,12 @@ inline bool get_boot_and_system_time_wstr(wchar_t *bootsystemstamp, std::size_t class handle_closer { void *handle_; + handle_closer(const handle_closer &); + handle_closer& operator=(const handle_closer &); public: - handle_closer(void *handle) : handle_(handle){} - ~handle_closer(){ close_handle(handle_); } + explicit handle_closer(void *handle) : handle_(handle){} + ~handle_closer() + { close_handle(handle_); } }; union ntquery_mem_t @@ -1401,81 +1475,92 @@ union ntquery_mem_t inline bool unlink_file(const char *filename) { - if(!delete_file(filename)){ - try{ - NtSetInformationFile_t pNtSetInformationFile = - //(NtSetInformationFile_t)get_proc_address(get_module_handle("ntdll.dll"), "NtSetInformationFile"); - (NtSetInformationFile_t)dll_func::get(dll_func::NtSetInformationFile); - if(!pNtSetInformationFile){ - return false; - } + //Don't try to optimize doing a DeleteFile first + //as there are interactions with permissions and + //in-use files. + // + //if(!delete_file(filename)){ + // (...) + // + + //This functions tries to emulate UNIX unlink semantics in windows. + // + //- Open the file and mark the handle as delete-on-close + //- Rename the file to an arbitrary name based on a random number + //- Close the handle. If there are no file users, it will be deleted. + // Otherwise it will be used by already connected handles but the + // file name can't be used to open this file again + try{ + NtSetInformationFile_t pNtSetInformationFile = + (NtSetInformationFile_t)dll_func::get(dll_func::NtSetInformationFile); + if(!pNtSetInformationFile){ + return false; + } - NtQueryObject_t pNtQueryObject = - //(NtQueryObject_t)get_proc_address(get_module_handle("ntdll.dll"), "NtQueryObject"); - (NtQueryObject_t)dll_func::get(dll_func::NtQueryObject); + NtQueryObject_t pNtQueryObject = + (NtQueryObject_t)dll_func::get(dll_func::NtQueryObject); - //First step: Obtain a handle to the file using Win32 rules. This resolves relative paths - void *fh = create_file(filename, generic_read | delete_access, open_existing, - file_flag_backup_semantics | file_flag_delete_on_close, 0); - if(fh == invalid_handle_value){ - return false; - } + //First step: Obtain a handle to the file using Win32 rules. This resolves relative paths + void *fh = create_file(filename, generic_read | delete_access, open_existing, + file_flag_backup_semantics | file_flag_delete_on_close, 0); + if(fh == invalid_handle_value){ + return false; + } - handle_closer h_closer(fh); + handle_closer h_closer(fh); - std::auto_ptr<ntquery_mem_t> pmem(new ntquery_mem_t); - file_rename_information_t *pfri = &pmem->ren.info; - const std::size_t RenMaxNumChars = - ((char*)pmem.get() - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t); + std::auto_ptr<ntquery_mem_t> pmem(new ntquery_mem_t); + file_rename_information_t *pfri = &pmem->ren.info; + const std::size_t RenMaxNumChars = + ((char*)pmem.get() - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t); - //Obtain file name - unsigned long size; - if(pNtQueryObject(fh, object_name_information, pmem.get(), sizeof(ntquery_mem_t), &size)){ - return false; - } + //Obtain file name + unsigned long size; + if(pNtQueryObject(fh, object_name_information, pmem.get(), sizeof(ntquery_mem_t), &size)){ + return false; + } - //Copy filename to the rename member - std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length); - std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t); + //Copy filename to the rename member + std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length); + std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t); - //Second step: obtain the complete native-nt filename - //if(!get_file_name_from_handle_function(fh, pfri->FileName, RenMaxNumChars, filename_string_length)){ - //return 0; - //} + //Second step: obtain the complete native-nt filename + //if(!get_file_name_from_handle_function(fh, pfri->FileName, RenMaxNumChars, filename_string_length)){ + //return 0; + //} - //Add trailing mark - if((RenMaxNumChars-filename_string_length) < (SystemTimeOfDayInfoLength*2)){ - return false; - } + //Add trailing mark + if((RenMaxNumChars-filename_string_length) < (SystemTimeOfDayInfoLength*2)){ + return false; + } - //Search '\\' character to replace it - for(std::size_t i = filename_string_length; i != 0; --filename_string_length){ - if(pmem->ren.info.FileName[--i] == L'\\') - break; - } + //Search '\\' character to replace it + for(std::size_t i = filename_string_length; i != 0; --filename_string_length){ + if(pmem->ren.info.FileName[--i] == L'\\') + break; + } - //Add random number - std::size_t s = RenMaxNumChars - filename_string_length; - if(!get_boot_and_system_time_wstr(&pfri->FileName[filename_string_length], s)){ - return false; - } - filename_string_length += s; + //Add random number + std::size_t s = RenMaxNumChars - filename_string_length; + if(!get_boot_and_system_time_wstr(&pfri->FileName[filename_string_length], s)){ + return false; + } + filename_string_length += s; - //Fill rename information (FileNameLength is in bytes) - pfri->FileNameLength = static_cast<unsigned long>(sizeof(wchar_t)*(filename_string_length)); - pfri->Replace = 1; - pfri->RootDir = 0; + //Fill rename information (FileNameLength is in bytes) + pfri->FileNameLength = static_cast<unsigned long>(sizeof(wchar_t)*(filename_string_length)); + pfri->Replace = 1; + pfri->RootDir = 0; - //Final step: change the name of the in-use file: - io_status_block_t io; - if(0 != pNtSetInformationFile(fh, &io, pfri, sizeof(ntquery_mem_t::ren_t), file_rename_information)){ - return false; - } - return true; - } - catch(...){ + //Final step: change the name of the in-use file: + io_status_block_t io; + if(0 != pNtSetInformationFile(fh, &io, pfri, sizeof(ntquery_mem_t::ren_t), file_rename_information)){ return false; } + return true; + } + catch(...){ + return false; } return true; } @@ -1493,116 +1578,77 @@ struct reg_closer inline void get_shared_documents_folder(std::string &s) { s.clear(); - //void *hAdvapi = load_library("Advapi32.dll"); - //if (hAdvapi){ - //library_unloader unloader(hAdvapi); - // Pointer to function RegOpenKeyA - //RegOpenKeyEx_t pRegOpenKey = - //(RegOpenKeyEx_t)get_proc_address(hAdvapi, "RegOpenKeyExA"); - //if (pRegOpenKey){ - // Pointer to function RegCloseKey - //RegCloseKey_t pRegCloseKey = - //(RegCloseKey_t)get_proc_address(hAdvapi, "RegCloseKey"); - //if (pRegCloseKey){ - // Pointer to function RegQueryValueA - //RegQueryValueEx_t pRegQueryValue = - //(RegQueryValueEx_t)get_proc_address(hAdvapi, "RegQueryValueExA"); - //if (pRegQueryValue){ - //Open the key - void *key; - //if ((*pRegOpenKey)( hkey_local_machine - //, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" - //, 0 - //, key_query_value - //, &key) == 0){ - //reg_closer key_closer(pRegCloseKey, key); - if (reg_open_key_ex( hkey_local_machine - , "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" - , 0 - , key_query_value - , &key) == 0){ - reg_closer key_closer(key); - - //Obtain the value - unsigned long size; - unsigned long type; - const char *const reg_value = "Common AppData"; - //long err = (*pRegQueryValue)( key, reg_value, 0, &type, 0, &size); - long err = reg_query_value_ex( key, reg_value, 0, &type, 0, &size); - if(!err){ - //Size includes terminating NULL - s.resize(size); - //err = (*pRegQueryValue)( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); - err = reg_query_value_ex( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); - if(!err) - s.erase(s.end()-1); - (void)err; - } - } - //} - //} - //} - //} + void *key; + if (reg_open_key_ex( hkey_local_machine + , "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" + , 0 + , key_query_value + , &key) == 0){ + reg_closer key_closer(key); + + //Obtain the value + unsigned long size; + unsigned long type; + const char *const reg_value = "Common AppData"; + //long err = (*pRegQueryValue)( key, reg_value, 0, &type, 0, &size); + long err = reg_query_value_ex( key, reg_value, 0, &type, 0, &size); + if(!err){ + //Size includes terminating NULL + s.resize(size); + //err = (*pRegQueryValue)( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + err = reg_query_value_ex( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + if(!err) + s.erase(s.end()-1); + (void)err; + } + } } - inline void get_registry_value(const char *folder, const char *value_key, std::vector<unsigned char> &s) { s.clear(); - //void *hAdvapi = load_library("Advapi32.dll"); - //if (hAdvapi){ - //library_unloader unloader(hAdvapi); - // Pointer to function RegOpenKeyA - //RegOpenKeyEx_t pRegOpenKey = - //(RegOpenKeyEx_t)get_proc_address(hAdvapi, "RegOpenKeyExA"); - //if (pRegOpenKey){ - // Pointer to function RegCloseKey - //RegCloseKey_t pRegCloseKey = - //(RegCloseKey_t)get_proc_address(hAdvapi, "RegCloseKey"); - //if (pRegCloseKey){ - // Pointer to function RegQueryValueA - //RegQueryValueEx_t pRegQueryValue = - //(RegQueryValueEx_t)get_proc_address(hAdvapi, "RegQueryValueExA"); - //if (pRegQueryValue){ - //Open the key - void *key; - //if ((*pRegOpenKey)( hkey_local_machine - //, folder - //, 0 - //, key_query_value - //, &key) == 0){ - //reg_closer key_closer(pRegCloseKey, key); - if (reg_open_key_ex( hkey_local_machine - , folder - , 0 - , key_query_value - , &key) == 0){ - reg_closer key_closer(key); - - //Obtain the value - unsigned long size; - unsigned long type; - const char *const reg_value = value_key; - //long err = (*pRegQueryValue)( key, reg_value, 0, &type, 0, &size); - long err = reg_query_value_ex( key, reg_value, 0, &type, 0, &size); - if(!err){ - //Size includes terminating NULL - s.resize(size); - //err = (*pRegQueryValue)( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); - err = reg_query_value_ex( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); - if(!err) - s.erase(s.end()-1); - (void)err; - } - } - //} - //} - //} - //} + void *key; + if (reg_open_key_ex( hkey_local_machine + , folder + , 0 + , key_query_value + , &key) == 0){ + reg_closer key_closer(key); + + //Obtain the value + unsigned long size; + unsigned long type; + const char *const reg_value = value_key; + //long err = (*pRegQueryValue)( key, reg_value, 0, &type, 0, &size); + long err = reg_query_value_ex( key, reg_value, 0, &type, 0, &size); + if(!err){ + //Size includes terminating NULL + s.resize(size); + //err = (*pRegQueryValue)( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + err = reg_query_value_ex( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + if(!err) + s.erase(s.end()-1); + (void)err; + } + } } struct co_uninitializer -{ ~co_uninitializer() { CoUninitialize(); } }; +{ + co_uninitializer(bool b_uninitialize) + : m_b_uninitialize(b_uninitialize) + {} + + ~co_uninitializer() + { + if(m_b_uninitialize){ + CoUninitialize(); + } + } + + private: + const bool m_b_uninitialize; +}; template<class Object> struct com_releaser @@ -1615,29 +1661,32 @@ struct com_releaser inline bool get_wmi_class_attribute( std::wstring& strValue, const wchar_t *wmi_class, const wchar_t *wmi_class_var) { //See example http://msdn.microsoft.com/en-us/library/aa390423%28v=VS.85%29.aspx - long co_init_ret = CoInitialize(0); - if(co_init_ret != S_OK_BIPC && co_init_ret != S_FALSE_BIPC) + // + //See BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL definition if you need to change the + //default value of this macro in your application + long co_init_ret = CoInitializeEx(0, BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL); + if(co_init_ret != S_OK_BIPC && co_init_ret != S_FALSE_BIPC && co_init_ret != RPC_E_CHANGED_MODE_BIPC) return false; - co_uninitializer co_initialize_end; + co_uninitializer co_initialize_end(co_init_ret != RPC_E_CHANGED_MODE_BIPC); (void)co_initialize_end; bool bRet = false; long sec_init_ret = CoInitializeSecurity - ( 0 //pVoid - ,-1 //cAuthSvc - , 0 //asAuthSvc - , 0 //pReserved1 - , RPC_C_AUTHN_LEVEL_PKT_BIPC //dwAuthnLevel - , RPC_C_IMP_LEVEL_IMPERSONATE_BIPC //dwImpLevel - , 0 //pAuthList - , EOAC_NONE_BIPC //dwCapabilities - , 0 //pReserved3 + ( 0 //pVoid + ,-1 //cAuthSvc + , 0 //asAuthSvc + , 0 //pReserved1 + , RPC_C_AUTHN_LEVEL_PKT_BIPC //dwAuthnLevel + , RPC_C_IMP_LEVEL_IMPERSONATE_BIPC //dwImpLevel + , 0 //pAuthList + , EOAC_NONE_BIPC //dwCapabilities + , 0 //pReserved3 ); if( 0 == sec_init_ret || RPC_E_TOO_LATE_BIPC == sec_init_ret) { IWbemLocator_BIPC * pIWbemLocator = 0; const wchar_t * bstrNamespace = L"root\\cimv2"; - + if( 0 != CoCreateInstance( CLSID_WbemAdministrativeLocator, 0, @@ -1645,7 +1694,7 @@ inline bool get_wmi_class_attribute( std::wstring& strValue, const wchar_t *wmi_ IID_IUnknown, (void **)&pIWbemLocator)){ return false; } - + com_releaser<IWbemLocator_BIPC> IWbemLocator_releaser(pIWbemLocator); IWbemServices_BIPC *pWbemServices = 0; @@ -1677,7 +1726,7 @@ inline bool get_wmi_class_attribute( std::wstring& strValue, const wchar_t *wmi_ ){ return false; } - + com_releaser<IWbemServices_BIPC> IWbemServices_releaser(pWbemServices); strValue.clear(); @@ -1757,9 +1806,40 @@ inline bool is_directory(const char *path) (attrib & file_attribute_directory)); } -} //namespace winapi +inline bool get_file_mapping_size(void *file_mapping_hnd, __int64 &size) +{ + NtQuerySection_t pNtQuerySection = + (NtQuerySection_t)dll_func::get(dll_func::NtQuerySection); + //Obtain file name + interprocess_section_basic_information info; + unsigned long ntstatus = + pNtQuerySection(file_mapping_hnd, section_basic_information, &info, sizeof(info), 0); + if(ntstatus){ + return false; + } + size = info.section_size; + return true; +} + +inline bool get_semaphore_info(void *handle, long &count, long &limit) +{ + winapi::interprocess_semaphore_basic_information info; + winapi::NtQuerySemaphore_t pNtQuerySemaphore = + (winapi::NtQuerySemaphore_t)dll_func::get(winapi::dll_func::NtQuerySemaphore); + unsigned int ret_len; + long status = pNtQuerySemaphore(handle, winapi::semaphore_basic_information, &info, sizeof(info), &ret_len); + if(status){ + return false; + } + count = info.count; + limit = info.limit; + return true; +} + + +} //namespace winapi } //namespace interprocess -} //namespace boost +} //namespace boost #include <boost/interprocess/detail/config_end.hpp> diff --git a/boost/interprocess/detail/windows_intermodule_singleton.hpp b/boost/interprocess/detail/windows_intermodule_singleton.hpp new file mode 100644 index 0000000000..a716e270a7 --- /dev/null +++ b/boost/interprocess/detail/windows_intermodule_singleton.hpp @@ -0,0 +1,306 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_WINDOWS_INTERMODULE_SINGLETON_HPP +#define BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP + +#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_WINDOWS) + #error "This header can't be included from non-windows operating systems" +#endif + +#include <boost/assert.hpp> +#include <boost/interprocess/detail/intermodule_singleton_common.hpp> +#include <boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp> +#include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/cstdint.hpp> +#include <string> +#include <map> + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +namespace intermodule_singleton_helpers { + +//This global map will be implemented using 3 sync primitives: +// +//1) A named mutex that will implement global mutual exclusion between +// threads from different modules/dlls +// +//2) A semaphore that will act as a global counter for modules attached to the global map +// so that the global map can be destroyed when the last module is detached. +// +//3) A semaphore that will be hacked to hold the address of a heap-allocated map in the +// max and current semaphore count. +class windows_semaphore_based_map +{ + typedef std::map<std::string, ref_count_ptr> map_type; + + public: + windows_semaphore_based_map() + { + map_type *m = new map_type; + boost::uint32_t initial_count = 0; + boost::uint32_t max_count = 0; + + //Windows user address space sizes: + //32 bit windows: [32 bit processes] 2GB or 3GB (31/32 bits) + //64 bit windows: [32 bit processes] 2GB or 4GB (31/32 bits) + // [64 bit processes] 2GB or 8TB (31/43 bits) + // + //Windows semaphores use 'long' parameters (32 bits in LLP64 data model) and + //those values can't be negative, so we have 31 bits to store something + //in max_count and initial count parameters. + //Also, max count must be bigger than 0 and bigger or equal than initial count. + if(sizeof(void*) == sizeof(boost::uint32_t)){ + //This means that for 32 bit processes, a semaphore count (31 usable bits) is + //enough to store 4 byte aligned memory (4GB -> 32 bits - 2 bits = 30 bits). + //The max count will hold the pointer value and current semaphore count + //will be zero. + // + //Relying in UB with a cast through union, but all known windows compilers + //accept this (C11 also accepts this). + union caster_union + { + void *addr; + boost::uint32_t addr_uint32; + } caster; + caster.addr = m; + //memory is at least 4 byte aligned in windows + BOOST_ASSERT((caster.addr_uint32 & boost::uint32_t(3)) == 0); + max_count = caster.addr_uint32 >> 2; + } + else if(sizeof(void*) == sizeof(boost::uint64_t)){ + //Relying in UB with a cast through union, but all known windows compilers + //accept this (C11 accepts this). + union caster_union + { + void *addr; + boost::uint64_t addr_uint64; + } caster; + caster.addr = m; + //We'll encode the address using 30 bits in each 32 bit high and low parts. + //High part will be the sem max count, low part will be the sem initial count. + //(restrictions: max count > 0, initial count >= 0 and max count >= initial count): + // + // - Low part will be shifted two times (4 byte alignment) so that top + // two bits are cleared (the top one for sign, the next one to + // assure low part value is always less than the high part value. + // - The top bit of the high part will be cleared and the next bit will be 1 + // (so high part is always bigger than low part due to the quasi-top bit). + // + // This means that the addresses we can store must be 4 byte aligned + // and less than 1 ExbiBytes ( 2^60 bytes, ~1 ExaByte). User-level address space in Windows 64 + // is much less than this (8TB, 2^43 bytes): "1 EByte (or it was 640K?) ought to be enough for anybody" ;-). + caster.addr = m; + BOOST_ASSERT((caster.addr_uint64 & boost::uint64_t(3)) == 0); + max_count = boost::uint32_t(caster.addr_uint64 >> 32); + initial_count = boost::uint32_t(caster.addr_uint64); + initial_count = initial_count/4; + //Make sure top two bits are zero + BOOST_ASSERT((max_count & boost::uint32_t(0xC0000000)) == 0); + //Set quasi-top bit + max_count |= boost::uint32_t(0x40000000); + } + bool created = false; + const permissions & perm = permissions(); + std::string pid_creation_time, name; + get_pid_creation_time_str(pid_creation_time); + name = "bipc_gmap_sem_lock_"; + name += pid_creation_time; + bool success = m_mtx_lock.open_or_create(name.c_str(), perm); + name = "bipc_gmap_sem_count_"; + name += pid_creation_time; + scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock); + { + success = success && m_sem_count.open_or_create + ( name.c_str(), static_cast<long>(0), winapi_semaphore_wrapper::MaxCount, perm, created); + name = "bipc_gmap_sem_map_"; + name += pid_creation_time; + success = success && m_sem_map.open_or_create + (name.c_str(), initial_count, max_count, perm, created); + if(!success){ + //winapi_xxx wrappers do the cleanup... + throw int(0); + } + if(!created){ + delete m; + } + else{ + BOOST_ASSERT(&get_map_unlocked() == m); + } + m_sem_count.post(); + } + } + + map_type &get_map_unlocked() + { + if(sizeof(void*) == sizeof(boost::uint32_t)){ + union caster_union + { + void *addr; + boost::uint32_t addr_uint32; + } caster; + caster.addr = 0; + caster.addr_uint32 = m_sem_map.limit(); + caster.addr_uint32 = caster.addr_uint32 << 2; + return *static_cast<map_type*>(caster.addr); + } + else{ + union caster_union + { + void *addr; + boost::uint64_t addr_uint64; + } caster; + boost::uint32_t max_count(m_sem_map.limit()), initial_count(m_sem_map.value()); + //Clear quasi-top bit + max_count &= boost::uint32_t(0xBFFFFFFF); + caster.addr_uint64 = max_count; + caster.addr_uint64 = caster.addr_uint64 << 32; + caster.addr_uint64 |= boost::uint64_t(initial_count) << 2; + return *static_cast<map_type*>(caster.addr); + } + } + + ref_count_ptr *find(const char *name) + { + scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock); + map_type &map = this->get_map_unlocked(); + map_type::iterator it = map.find(std::string(name)); + if(it != map.end()){ + return &it->second; + } + else{ + return 0; + } + } + + ref_count_ptr * insert(const char *name, const ref_count_ptr &ref) + { + scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock); + map_type &map = this->get_map_unlocked(); + map_type::iterator it = map.insert(map_type::value_type(std::string(name), ref)).first; + return &it->second; + } + + bool erase(const char *name) + { + scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock); + map_type &map = this->get_map_unlocked(); + return map.erase(std::string(name)) != 0; + } + + template<class F> + void atomic_func(F &f) + { + scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock); + f(); + } + + ~windows_semaphore_based_map() + { + scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock); + m_sem_count.wait(); + if(0 == m_sem_count.value()){ + delete &this->get_map_unlocked(); + } + //First close sems to protect this with the external mutex + m_sem_map.close(); + m_sem_count.close(); + //Once scoped_lock unlocks the mutex, the destructor will close the handle... + } + + private: + winapi_mutex_wrapper m_mtx_lock; + winapi_semaphore_wrapper m_sem_map; + winapi_semaphore_wrapper m_sem_count; +}; + +template<> +struct thread_safe_global_map_dependant<windows_semaphore_based_map> +{ + static void apply_gmem_erase_logic(const char *, const char *){} + + static bool remove_old_gmem() + { return true; } + + struct lock_file_logic + { + lock_file_logic(windows_semaphore_based_map &) + : retry_with_new_map(false) + {} + + void operator()(void){} + bool retry() const { return retry_with_new_map; } + private: + const bool retry_with_new_map; + }; + + static void construct_map(void *addr) + { + ::new (addr)windows_semaphore_based_map; + } + + struct unlink_map_logic + { + unlink_map_logic(windows_semaphore_based_map &) + {} + void operator()(){} + }; + + static ref_count_ptr *find(windows_semaphore_based_map &map, const char *name) + { + return map.find(name); + } + + static ref_count_ptr * insert(windows_semaphore_based_map &map, const char *name, const ref_count_ptr &ref) + { + return map.insert(name, ref); + } + + static bool erase(windows_semaphore_based_map &map, const char *name) + { + return map.erase(name); + } + + template<class F> + static void atomic_func(windows_semaphore_based_map &map, F &f) + { + map.atomic_func(f); + } +}; + +} //namespace intermodule_singleton_helpers { + +template<typename C, bool LazyInit = true, bool Phoenix = true> +class windows_intermodule_singleton + : public intermodule_singleton_impl + < C + , LazyInit + , Phoenix + , intermodule_singleton_helpers::windows_semaphore_based_map + > +{}; + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP diff --git a/boost/interprocess/detail/workaround.hpp b/boost/interprocess/detail/workaround.hpp index 896a2208a2..884b8680a6 100644 --- a/boost/interprocess/detail/workaround.hpp +++ b/boost/interprocess/detail/workaround.hpp @@ -13,43 +13,34 @@ #include <boost/interprocess/detail/config_begin.hpp> -#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) - -#define BOOST_INTERPROCESS_WINDOWS - -/* -#if !defined(_MSC_EXTENSIONS) -#error "Turn on Microsoft language extensions (_MSC_EXTENSIONS) to be able to call Windows API functions" -#endif -*/ - -#endif - -#if !defined(BOOST_INTERPROCESS_WINDOWS) - +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #define BOOST_INTERPROCESS_WINDOWS + #define BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION + #define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME +#else #include <unistd.h> - #if ((_POSIX_THREAD_PROCESS_SHARED - 0) > 0) - //Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it. - //Mac Os X >= Leopard defines _POSIX_THREAD_PROCESS_SHARED but does not seems to work. - # if !defined(__CYGWIN__) && !defined(__APPLE__) - # define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED - # endif + #if defined(_POSIX_THREAD_PROCESS_SHARED) && ((_POSIX_THREAD_PROCESS_SHARED - 0) > 0) + //Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it. + //Mac Os X >= Leopard defines _POSIX_THREAD_PROCESS_SHARED but does not seems to work. + #if !defined(__CYGWIN__) && !defined(__APPLE__) + #define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED + #endif + #endif + + #if defined(_POSIX_BARRIERS) && ((_POSIX_BARRIERS - 0) > 0) + #define BOOST_INTERPROCESS_POSIX_BARRIERS #endif - - #if ((_POSIX_BARRIERS - 0) > 0) - # define BOOST_INTERPROCESS_POSIX_BARRIERS - # endif - - #if ((_POSIX_SEMAPHORES - 0) > 0) - # define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES - # if defined(__CYGWIN__) - #define BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK - # endif + + #if defined(_POSIX_SEMAPHORES) && ((_POSIX_SEMAPHORES - 0) > 0) + #define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + #if defined(__CYGWIN__) + #define BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK + #endif //Some platforms have a limited (name length) named semaphore support #elif (defined(__FreeBSD__) && (__FreeBSD__ >= 4)) || defined(__APPLE__) - # define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES - #endif + #define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + #endif #if ((defined _V6_ILP32_OFFBIG) &&(_V6_ILP32_OFFBIG - 0 > 0)) ||\ ((defined _V6_LP64_OFF64) &&(_V6_LP64_OFF64 - 0 > 0)) ||\ @@ -60,87 +51,83 @@ ((defined _FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64))||\ ((defined _FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64)) #define BOOST_INTERPROCESS_UNIX_64_BIT_OR_BIGGER_OFF_T - #else #endif //Check for XSI shared memory objects. They are available in nearly all UNIX platforms #if !defined(__QNXNTO__) - # define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + #define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS #endif - #if ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0) - # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + #if defined(_POSIX_SHARED_MEMORY_OBJECTS) && ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0) + #define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS #else - //VMS and MACOS don't define it but the have shm_open/close interface - # if defined(__vms) - # if __CRTL_VER >= 70200000 - # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS - # endif - //Mac OS has some non-conformant features like names limited to SHM_NAME_MAX - # elif defined (__APPLE__) -// # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS -// # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS_NO_GROW - # endif + //VMS and MACOS don't define it but they have shm_open/close interface + #if defined(__vms) + #if __CRTL_VER >= 70200000 + #define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + #endif + //Mac OS has some non-conformant features like names limited to SHM_NAME_MAX + #elif defined (__APPLE__) + //#define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + //#define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS_NO_GROW + #endif #endif //Now check if we have only XSI shared memory #if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) &&\ !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) - //# define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS_ONLY + //#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS_ONLY #endif - #if ((_POSIX_TIMEOUTS - 0) > 0) - # define BOOST_INTERPROCESS_POSIX_TIMEOUTS - #endif - + #if defined(_POSIX_TIMEOUTS) && ((_POSIX_TIMEOUTS - 0) > 0) + #define BOOST_INTERPROCESS_POSIX_TIMEOUTS + #endif #ifdef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS //Some systems have filesystem-based resources, so the //portable "/shmname" format does not work due to permission issues //For those systems we need to form a path to a temporary directory: // hp-ux tru64 vms freebsd - #if defined(__hpux) || defined(__osf__) || defined(__vms) || (defined(__FreeBSD__) && (__FreeBSD__ < 7)) - #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY + #if defined(__hpux) || defined(__osf__) || defined(__vms) || (defined(__FreeBSD__) && (__FreeBSD__ < 7)) + #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY #elif defined(__FreeBSD__) - #define BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY + #define BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY #endif #endif #ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES #if defined(__osf__) || defined(__vms) - #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES + #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES #endif #endif - #if ((_POSIX_VERSION + 0)>= 200112L || (_XOPEN_VERSION + 0)>= 500) - #define BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES + #if defined(_POSIX_VERSION) && defined(_XOPEN_VERSION) && \ + (((_POSIX_VERSION + 0)>= 200112L || (_XOPEN_VERSION + 0)>= 500)) + #define BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES #endif -#endif + #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) + #define BOOST_INTERPROCESS_BSD_DERIVATIVE + #include <sys/sysctl.h> + #if defined(CTL_KERN) && defined (KERN_BOOTTIME) + //#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME + #endif + #endif +#endif //!defined(BOOST_INTERPROCESS_WINDOWS) -#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)\ - && !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL) -#define BOOST_INTERPROCESS_PERFECT_FORWARDING +#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) + #define BOOST_INTERPROCESS_PERFECT_FORWARDING #endif //Now declare some Boost.Interprocess features depending on the implementation - #if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) - -#define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES - -#endif - -#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) - -#define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES -#define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES - + #define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES + #define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES #endif // Timeout duration use if BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING is set #ifndef BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS -#define BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS 10000 + #define BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS 10000 #endif #include <boost/interprocess/detail/config_end.hpp> diff --git a/boost/interprocess/detail/xsi_shared_memory_device.hpp b/boost/interprocess/detail/xsi_shared_memory_device.hpp index d2e2bf2ce6..ef4b009bc1 100644 --- a/boost/interprocess/detail/xsi_shared_memory_device.hpp +++ b/boost/interprocess/detail/xsi_shared_memory_device.hpp @@ -46,7 +46,7 @@ class xsi_shared_memory_device { /// @cond BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper) - /// @endcond + /// @endcond public: @@ -74,10 +74,10 @@ class xsi_shared_memory_device { this->swap(moved); } xsi_shared_memory_device &operator=(BOOST_RV_REF(xsi_shared_memory_device) moved) - { + { xsi_shared_memory_device tmp(boost::move(moved)); this->swap(tmp); - return *this; + return *this; } //!Swaps two xsi_shared_memory_device. Does not throw @@ -168,7 +168,7 @@ inline xsi_shared_memory_device::xsi_shared_memory_device() : m_shm(), m_mode(invalid_mode), m_name() {} -inline xsi_shared_memory_device::~xsi_shared_memory_device() +inline xsi_shared_memory_device::~xsi_shared_memory_device() {} inline const char *xsi_shared_memory_device::get_name() const @@ -178,7 +178,7 @@ inline void xsi_shared_memory_device::swap(xsi_shared_memory_device &other) { m_shm.swap(other.m_shm); std::swap(m_mode, other.m_mode); - m_name.swap(other.m_name); + m_name.swap(other.m_name); } inline mapping_handle_t xsi_shared_memory_device::get_mapping_handle() const diff --git a/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp b/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp index d74d9664a5..14811e7e62 100644 --- a/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp +++ b/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp @@ -40,7 +40,7 @@ class xsi_shared_memory_file_wrapper { /// @cond BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper) - /// @endcond + /// @endcond public: xsi_shared_memory_file_wrapper() : xsi_shared_memory() {} @@ -61,10 +61,10 @@ class xsi_shared_memory_file_wrapper { this->swap(moved); } xsi_shared_memory_file_wrapper &operator=(BOOST_RV_REF(xsi_shared_memory_file_wrapper) moved) - { + { xsi_shared_memory_file_wrapper tmp(boost::move(moved)); this->swap(tmp); - return *this; + return *this; } //!Swaps two xsi_shared_memory_file_wrapper. Does not throw |