feat():initial version

This commit is contained in:
2026-06-09 20:16:47 +08:00
commit 85fbb3188c
14809 changed files with 3044607 additions and 0 deletions

View File

@@ -0,0 +1,655 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2012
// (C) Copyright Markus Schoepflin 2007
// (C) Copyright Bryce Lelbach 2010
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP
#define BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/cstdint.hpp>
namespace boost{
namespace interprocess{
namespace ipcdetail{
//! Atomically increment an boost::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);
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem);
//! 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);
//! 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);
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#if defined (BOOST_INTERPROCESS_WINDOWS)
#include <boost/interprocess/detail/win32_api.hpp>
#if defined( _MSC_VER )
extern "C" void _ReadWriteBarrier(void);
#pragma intrinsic(_ReadWriteBarrier)
#define BOOST_INTERPROCESS_READ_WRITE_BARRIER _ReadWriteBarrier()
#elif defined(__GNUC__)
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
#define BOOST_INTERPROCESS_READ_WRITE_BARRIER __sync_synchronize()
#else
#define BOOST_INTERPROCESS_READ_WRITE_BARRIER __asm__ __volatile__("" : : : "memory")
#endif
#endif
namespace boost{
namespace interprocess{
namespace ipcdetail{
//! 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 winapi::interlocked_decrement(reinterpret_cast<volatile long*>(mem)) + 1; }
//! 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 winapi::interlocked_increment(reinterpret_cast<volatile long*>(mem))-1; }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{
const boost::uint32_t val = *mem;
BOOST_INTERPROCESS_READ_WRITE_BARRIER;
return val;
}
//! 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)
{ winapi::interlocked_exchange(reinterpret_cast<volatile long*>(mem), val); }
//! 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 winapi::interlocked_compare_exchange(reinterpret_cast<volatile long*>(mem), with, cmp); }
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(_CRAYC)
namespace boost {
namespace interprocess {
namespace ipcdetail{
//! 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 prev = cmp;
// This version by Mans Rullgard of Pathscale
__asm__ __volatile__ ( "lock\n\t"
"cmpxchg %2,%0"
: "+m"(*mem), "+a"(prev)
: "r"(with)
: "cc");
return prev;
}
//! 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)
{
// int r = *pw;
// *mem += val;
// return r;
int r;
asm volatile
(
"lock\n\t"
"xadd %1, %0":
"+m"( *mem ), "=r"( r ): // outputs (%0, %1)
"1"( val ): // inputs (%2 == %1)
"memory", "cc" // clobbers
);
return r;
}
//! 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)
{
const boost::uint32_t val = *mem;
__asm__ __volatile__ ( "" ::: "memory" );
return val;
}
//! 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)
{
__asm__ __volatile__
(
"xchgl %0, %1"
: "+r" (val), "+m" (*mem)
:: "memory"
);
}
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#elif defined(__GNUC__) && (defined(__PPC__) || defined(__ppc__))
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)
{
boost::uint32_t prev, temp;
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;
}
//! 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 prev;
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" (with), "r" (cmp)
: "cc", "memory");
return prev;
}
//! 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(-1u)); }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{
const boost::uint32_t val = *mem;
__asm__ __volatile__ ( "" ::: "memory" );
return val;
}
//! 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>
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 atomic_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), (int32_t)val) - val; }
//! 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 atomic_cas_32(reinterpret_cast<volatile ::uint32_t*>(mem), cmp, with); }
//! 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_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), 1) - 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_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), (boost::uint32_t)-1) + 1; }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ return *mem; }
//! 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(__osf__) && defined(__DECCXX)
#include <machine/builtins.h>
#include <c_asm.h>
namespace boost{
namespace interprocess{
namespace ipcdetail{
//! Atomically decrement a uint32_t by 1
//! "mem": pointer to the atomic value
//! Returns the old value pointed to by mem
//! Acquire, memory barrier after decrement.
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
{ boost::uint32_t old_val = __ATOMIC_DECREMENT_LONG(mem); __MB(); return old_val; }
//! Atomically increment a uint32_t by 1
//! "mem": pointer to the object
//! Returns the old value pointed to by mem
//! Release, memory barrier before increment.
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
{ __MB(); return __ATOMIC_INCREMENT_LONG(mem); }
// Rational for the implementation of the atomic read and write functions.
//
// 1. The Alpha Architecture Handbook requires that access to a byte,
// an aligned word, an aligned longword, or an aligned quadword is
// atomic. (See 'Alpha Architecture Handbook', version 4, chapter 5.2.2.)
//
// 2. The CXX User's Guide states that volatile quantities are accessed
// with single assembler instructions, and that a compilation error
// occurs when declaring a quantity as volatile which is not properly
// aligned.
//! Atomically read an boost::uint32_t from memory
//! Acquire, memory barrier after load.
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ boost::uint32_t old_val = *mem; __MB(); return old_val; }
//! Atomically set an boost::uint32_t in memory
//! "mem": pointer to the object
//! "param": val value that the object will assume
//! Release, memory barrier before store.
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
{ __MB(); *mem = val; }
//! 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
//! Memory barrier between load and store.
inline boost::uint32_t atomic_cas32(
volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
{
// Note:
//
// Branch prediction prefers backward branches, and the Alpha Architecture
// Handbook explicitely states that the loop should not be implemented like
// it is below. (See chapter 4.2.5.) Therefore the code should probably look
// like this:
//
// return asm(
// "10: ldl_l %v0,(%a0) ;"
// " cmpeq %v0,%a2,%t0 ;"
// " beq %t0,20f ;"
// " mb ;"
// " mov %a1,%t0 ;"
// " stl_c %t0,(%a0) ;"
// " beq %t0,30f ;"
// "20: ret ;"
// "30: br 10b;",
// mem, with, cmp);
//
// But as the compiler always transforms this into the form where a backward
// branch is taken on failure, we can as well implement it in the straight
// forward form, as this is what it will end up in anyway.
return asm(
"10: ldl_l %v0,(%a0) ;" // load prev value from mem and lock mem
" cmpeq %v0,%a2,%t0 ;" // compare with given value
" beq %t0,20f ;" // if not equal, we're done
" mb ;" // memory barrier
" mov %a1,%t0 ;" // load new value into scratch register
" stl_c %t0,(%a0) ;" // store new value to locked mem (overwriting scratch)
" beq %t0,10b ;" // store failed because lock has been stolen, retry
"20: ",
mem, with, cmp);
}
} //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)
{ boost::uint32_t old_val = *mem; __sync_synchronize(); return old_val; }
//! 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)
{ __sync_synchronize(); *mem = val; }
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#elif defined(__VXWORKS__)
#include <vxAtomicLib.h>
// VxWorks atomic32_t is not volatile, for some unknown reason
#define vx_atomic_cast(_i) (reinterpret_cast< ::atomic32_t *>( const_cast<boost::uint32_t *>(_i)))
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 ::vxAtomic32Add( vx_atomic_cast(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 ::vxAtomic32Inc( vx_atomic_cast(mem) ); }
//! 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 ::vxAtomic32Dec( vx_atomic_cast(mem) ); }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ return ::vxAtomic32Get( vx_atomic_cast(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 ::vxAtomic32Cas( vx_atomic_cast(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)
{ ::vxAtomic32Set( vx_atomic_cast(mem), val); }
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#else
#error No atomic operations implemented for this platform, sorry!
#endif
namespace boost{
namespace interprocess{
namespace ipcdetail{
inline bool atomic_add_unless32
(volatile boost::uint32_t *mem, boost::uint32_t value, boost::uint32_t unless_this)
{
boost::uint32_t old, c(atomic_read32(mem));
while(c != unless_this && (old = atomic_cas32(mem, c + value, c)) != c){
c = old;
}
return c != unless_this;
}
} //namespace ipcdetail
} //namespace interprocess
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP

View File

@@ -0,0 +1,31 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP
#define BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost { namespace interprocess { namespace ipcdetail {
struct static_cast_tag {};
struct const_cast_tag {};
struct dynamic_cast_tag {};
struct reinterpret_cast_tag {};
}}} //namespace boost { namespace interprocess { namespace ipcdetail {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP

View File

@@ -0,0 +1,50 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONFIG_INCLUDED
#define BOOST_INTERPROCESS_CONFIG_INCLUDED
#include <boost/config.hpp>
#endif
#ifdef BOOST_MSVC
#pragma warning (push)
#pragma warning (disable : 4702) // unreachable code
#pragma warning (disable : 4706) // assignment within conditional expression
#pragma warning (disable : 4127) // conditional expression is constant
#pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
#pragma warning (disable : 4284) // odd return type for operator->
#pragma warning (disable : 4244) // possible loss of data
#pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2"
#pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data
#pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier"
#pragma warning (disable : 4355) // "this" : used in base member initializer list
#pragma warning (disable : 4345) // behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized
#pragma warning (disable : 4503) // "identifier" : decorated name length exceeded, name was truncated
#pragma warning (disable : 4511) // copy constructor could not be generated
#pragma warning (disable : 4512) // assignment operator could not be generated
#pragma warning (disable : 4514) // unreferenced inline removed
#pragma warning (disable : 4521) // Disable "multiple copy constructors specified"
#pragma warning (disable : 4522) // "class" : multiple assignment operators specified
#pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter
#pragma warning (disable : 4710) // function not inlined
#pragma warning (disable : 4711) // function selected for automatic inline expansion
#pragma warning (disable : 4786) // identifier truncated in debug info
#pragma warning (disable : 4996) // "function": was declared deprecated
#pragma warning (disable : 4197) // top-level volatile in cast is ignored
#pragma warning (disable : 4541) // 'typeid' used on polymorphic type 'boost::exception'
// 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
#if defined(BOOST_GCC) && (BOOST_GCC >= 40600)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

View File

@@ -0,0 +1,16 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#if defined BOOST_MSVC
#pragma warning (pop)
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40600)
#pragma GCC diagnostic pop
#endif

View File

@@ -0,0 +1,18 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_EXTERNAL_CONFIG_INCLUDED
#define BOOST_INTERPROCESS_EXTERNAL_CONFIG_INCLUDED
#include <boost/config.hpp>
#endif
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wshadow"
#endif

View File

@@ -0,0 +1,12 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406)
# pragma GCC diagnostic pop
#endif

View File

@@ -0,0 +1,302 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <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/shared_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

View File

@@ -0,0 +1,213 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP
#define BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/simple_swap.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail{
class file_wrapper
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
BOOST_MOVABLE_BUT_NOT_COPYABLE(file_wrapper)
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Default constructor.
//!Represents an empty file_wrapper.
file_wrapper();
//!Creates a file object with name "name" and mode "mode", with the access mode "mode"
//!If the file previously exists, throws an error.
file_wrapper(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions())
{ this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm); }
//!Tries to create a file with name "name" and mode "mode", with the
//!access mode "mode". If the file previously exists, it tries to open it with mode "mode".
//!Otherwise throws an error.
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".
//!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.
//!Does not throw
file_wrapper(BOOST_RV_REF(file_wrapper) moved)
: m_handle(file_handle_t(ipcdetail::invalid_file()))
{ this->swap(moved); }
//!Moves the ownership of "moved"'s file to *this.
//!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;
}
//!Swaps to file_wrappers.
//!Does not throw
void swap(file_wrapper &other);
//!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);
//!Closes the
//!file
~file_wrapper();
//!Returns the name of the file
//!used in the constructor
const char *get_name() const;
//!Returns the name of the file
//!used in the constructor
bool get_size(offset_t &size) const;
//!Returns access mode
//!used in the constructor
mode_t get_mode() const;
//!Get mapping handle
//!to use with mapped_region
mapping_handle_t get_mapping_handle() const;
private:
//!Closes a previously opened file mapping. Never throws.
void priv_close();
//!Closes a previously opened file mapping. Never throws.
bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm);
file_handle_t m_handle;
mode_t m_mode;
std::string m_filename;
};
inline file_wrapper::file_wrapper()
: m_handle(file_handle_t(ipcdetail::invalid_file()))
, m_mode(read_only), m_filename()
{}
inline file_wrapper::~file_wrapper()
{ this->priv_close(); }
inline const char *file_wrapper::get_name() const
{ return m_filename.c_str(); }
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)
{
(simple_swap)(m_handle, other.m_handle);
(simple_swap)(m_mode, other.m_mode);
m_filename.swap(other.m_filename);
}
inline mapping_handle_t file_wrapper::get_mapping_handle() const
{ return mapping_handle_from_file_handle(m_handle); }
inline mode_t file_wrapper::get_mode() const
{ return m_mode; }
inline bool file_wrapper::priv_open_or_create
(ipcdetail::create_enum_t type,
const char *filename,
mode_t mode,
const permissions &perm = permissions())
{
m_filename = filename;
if(mode != read_only && mode != read_write){
error_info err(mode_error);
throw interprocess_exception(err);
}
//Open file existing native API to obtain the handle
switch(type){
case ipcdetail::DoOpen:
m_handle = open_existing_file(filename, mode);
break;
case ipcdetail::DoCreate:
m_handle = create_new_file(filename, mode, perm);
break;
case ipcdetail::DoOpenOrCreate:
m_handle = create_or_open_file(filename, mode, perm);
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Check for error
if(m_handle == invalid_file()){
error_info err = system_error_code();
throw interprocess_exception(err);
}
m_mode = mode;
return true;
}
inline bool file_wrapper::remove(const char *filename)
{ return delete_file(filename); }
inline void file_wrapper::truncate(offset_t length)
{
if(!truncate_file(m_handle, length)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline void file_wrapper::priv_close()
{
if(m_handle != invalid_file()){
close_file(m_handle);
m_handle = invalid_file();
}
}
} //namespace ipcdetail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP

View File

@@ -0,0 +1,77 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP
#define BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/container/detail/type_traits.hpp> //alignment_of, aligned_storage
#include <typeinfo> //typeid
//!\file
//!Describes an abstract interface for placement construction and destruction.
namespace boost {
namespace interprocess {
namespace ipcdetail {
struct in_place_interface
{
in_place_interface(std::size_t alignm, std::size_t sz, const char *tname)
: alignment(alignm), size(sz), type_name(tname)
{}
std::size_t alignment;
std::size_t size;
const char *type_name;
virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) = 0;
virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed) = 0;
virtual ~in_place_interface(){}
};
template<class T>
struct placement_destroy : public in_place_interface
{
placement_destroy()
: in_place_interface(::boost::container::dtl::alignment_of<T>::value, sizeof(T), typeid(T).name())
{}
virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed)
{
T* memory = static_cast<T*>(mem);
for(destroyed = 0; destroyed < num; ++destroyed)
(memory++)->~T();
}
virtual void construct_n(void *, std::size_t, std::size_t &) {}
private:
void destroy(void *mem)
{ static_cast<T*>(mem)->~T(); }
};
}
}
} //namespace boost { namespace interprocess { namespace ipcdetail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP

View File

@@ -0,0 +1,53 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_INTERMODULE_SINGLETON_HPP
#define BOOST_INTERPROCESS_INTERMODULE_SINGLETON_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#ifdef BOOST_INTERPROCESS_WINDOWS
#include <boost/interprocess/detail/windows_intermodule_singleton.hpp>
#else
#include <boost/interprocess/detail/portable_intermodule_singleton.hpp>
#endif
namespace boost{
namespace interprocess{
namespace ipcdetail{
//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 = true, bool Phoenix = false>
class intermodule_singleton
#ifdef BOOST_INTERPROCESS_WINDOWS
: public windows_intermodule_singleton<C, LazyInit, Phoenix>
#else
: public portable_intermodule_singleton<C, LazyInit, Phoenix>
#endif
{};
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#include <boost/interprocess/detail/config_end.hpp>
#endif

View File

@@ -0,0 +1,504 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_INTERMODULE_SINGLETON_COMMON_HPP
#define BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/container/detail/type_traits.hpp> //alignment_of, aligned_storage
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/interprocess/sync/spin/wait.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
ThreadSafeGlobalMap *const pmap = get_map_ptr();
void *tmp = constructor(*pmap);
//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){
spin_wait swait;
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){
swait.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.
ThreadSafeGlobalMap * const pmap = get_map_ptr();
destructor(ptr, *pmap);
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_ptr()
{
return static_cast<ThreadSafeGlobalMap *>(static_cast<void*>(mem_holder.map_mem));
}
static void initialize_global_map_handle()
{
//Obtain unique map name and size
spin_wait swait;
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){
swait.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
ThreadSafeGlobalMap * const pmap = get_map_ptr();
intermodule_singleton_helpers::thread_safe_global_map_dependant
<ThreadSafeGlobalMap>::construct_map(static_cast<void*>(pmap));
//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(*pmap);
//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()){
pmap->~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
ThreadSafeGlobalMap * const pmap = get_map_ptr();
typename intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::
unlink_map_logic f(*pmap);
pmap->~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 union mem_holder_t
{
unsigned char map_mem [sizeof(ThreadSafeGlobalMap)];
::boost::container::dtl::max_align_t aligner;
} 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 true. If false
//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), ret_ptr()
{}
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;
}
}
private:
ThreadSafeGlobalMap &m_map;
};
//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

View File

@@ -0,0 +1,39 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP
#define BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost{
namespace interprocess{
namespace ipcdetail{
class interprocess_tester
{
public:
template<class T>
static void dont_close_on_destruction(T &t)
{ t.dont_close_on_destruction(); }
};
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,119 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/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, false> 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
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
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)
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
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

View File

@@ -0,0 +1,776 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP
#define BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/segment_manager.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/detail/nothrow.hpp>
#include <boost/interprocess/detail/simple_swap.hpp>
//
#include <boost/core/no_exceptions_support.hpp>
//
#include <boost/intrusive/detail/minimal_pair_header.hpp>
#include <boost/assert.hpp>
//!\file
//!Describes a named shared memory allocation user class.
//!
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class BasicManagedMemoryImpl>
class create_open_func;
template<
class CharType,
class MemoryAlgorithm,
template<class IndexConfig> class IndexType
>
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
//!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
, class MemoryAlgorithm
, template<class IndexConfig> class IndexType
, std::size_t Offset = 0
>
class basic_managed_memory_impl
{
//Non-copyable
basic_managed_memory_impl(const basic_managed_memory_impl &);
basic_managed_memory_impl &operator=(const basic_managed_memory_impl &);
template<class BasicManagedMemoryImpl>
friend class create_open_func;
public:
typedef typename segment_manager_type
<CharType, MemoryAlgorithm, IndexType>::type segment_manager;
typedef CharType char_type;
typedef MemoryAlgorithm memory_algorithm;
typedef typename MemoryAlgorithm::mutex_family mutex_family;
typedef CharType char_t;
typedef typename MemoryAlgorithm::size_type size_type;
typedef typename MemoryAlgorithm::difference_type difference_type;
typedef difference_type handle_t;
typedef typename segment_manager::
const_named_iterator const_named_iterator;
typedef typename segment_manager::
const_unique_iterator const_unique_iterator;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
typedef typename
segment_manager::char_ptr_holder_t char_ptr_holder_t;
//Experimental. Don't use.
typedef typename segment_manager::multiallocation_chain multiallocation_chain;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
static const size_type PayloadPerAllocation = segment_manager::PayloadPerAllocation;
private:
typedef basic_managed_memory_impl
<CharType, MemoryAlgorithm, IndexType, Offset> self_t;
protected:
template<class ManagedMemory>
static bool grow(const char *filename, size_type extra_bytes)
{
typedef typename ManagedMemory::device_type device_type;
//Increase file size
try{
offset_t old_size;
{
device_type f(open_or_create, filename, read_write);
if(!f.get_size(old_size))
return false;
f.truncate(old_size + extra_bytes);
}
ManagedMemory managed_memory(open_only, filename);
//Grow always works
managed_memory.self_t::grow(extra_bytes);
}
catch(...){
return false;
}
return true;
}
template<class ManagedMemory>
static bool shrink_to_fit(const char *filename)
{
typedef typename ManagedMemory::device_type device_type;
size_type new_size;
try{
ManagedMemory managed_memory(open_only, filename);
managed_memory.get_size();
managed_memory.self_t::shrink_to_fit();
new_size = managed_memory.get_size();
}
catch(...){
return false;
}
//Decrease file size
{
device_type f(open_or_create, filename, read_write);
f.truncate(new_size);
}
return true;
}
//!Constructor. Allocates basic resources. Never throws.
basic_managed_memory_impl()
: mp_header(0){}
//!Destructor. Calls close. Never throws.
~basic_managed_memory_impl()
{ this->close_impl(); }
//!Places segment manager in the reserved space. This can throw.
bool create_impl (void *addr, size_type size)
{
if(mp_header) return false;
//Check if there is enough space
if(size < segment_manager::get_min_size())
return false;
//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
BOOST_ASSERT((0 == (std::size_t)addr % boost::move_detail::alignment_of<segment_manager>::value));
mp_header = ::new(addr, boost_container_new_t()) segment_manager(size);
}
BOOST_CATCH(...){
return false;
}
BOOST_CATCH_END
return true;
}
//!Connects to a segment manager in the reserved buffer. Never throws.
bool open_impl (void *addr, size_type)
{
if(mp_header) return false;
mp_header = static_cast<segment_manager*>(addr);
return true;
}
//!Frees resources. Never throws.
bool close_impl()
{
bool ret = mp_header != 0;
mp_header = 0;
return ret;
}
//!Frees resources and destroys common resources. Never throws.
bool destroy_impl()
{
if(mp_header == 0)
return false;
mp_header->~segment_manager();
this->close_impl();
return true;
}
//!
void grow(size_type extra_bytes)
{ mp_header->grow(extra_bytes); }
void shrink_to_fit()
{ mp_header->shrink_to_fit(); }
public:
//!Returns segment manager. Never throws.
segment_manager *get_segment_manager() const
{ return mp_header; }
//!Returns the base address of the memory in this process. Never throws.
void * get_address () const
{ return reinterpret_cast<char*>(mp_header) - Offset; }
//!Returns the size of memory segment. Never throws.
size_type get_size () const
{ return mp_header->get_size() + Offset; }
//!Returns the number of free bytes of the memory
//!segment
size_type get_free_memory() const
{ return mp_header->get_free_memory(); }
//!Returns the result of "all_memory_deallocated()" function
//!of the used memory algorithm
bool all_memory_deallocated()
{ return mp_header->all_memory_deallocated(); }
//!Returns the result of "check_sanity()" function
//!of the used memory algorithm
bool check_sanity()
{ return mp_header->check_sanity(); }
//!Writes to zero free memory (memory not yet allocated) of
//!the memory algorithm
void zero_free_memory()
{ mp_header->zero_free_memory(); }
//!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()));
}
//!Returns true if the address belongs to the managed memory segment
bool belongs_to_segment (const void *ptr) const
{
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
//!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 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
//!is available returns 0. Never throws.
void* allocate (size_type nbytes, const std::nothrow_t &tag)
{ return mp_header->allocate(nbytes, tag); }
//!Allocates nbytes bytes aligned to "alignment" bytes. "alignment"
//!must be power of two. If no memory
//!is available returns 0. Never throws.
void * allocate_aligned (size_type nbytes, size_type alignment, const std::nothrow_t &tag)
{ return mp_header->allocate_aligned(nbytes, alignment, tag); }
template<class T>
T * allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
size_type &prefer_in_recvd_out_size, T *&reuse)
{ return mp_header->allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); }
//!Allocates nbytes bytes aligned to "alignment" bytes. "alignment"
//!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); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Experimental. Don't use.
//!Allocates n_elements of elem_bytes bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{ mp_header->allocate_many(elem_bytes, n_elements, chain); }
//!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{ mp_header->allocate_many(element_lengths, n_elements, sizeof_element, chain); }
//!Allocates n_elements of elem_bytes bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &tag, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{ mp_header->allocate_many(tag, elem_bytes, n_elements, chain); }
//!Allocates n_elements, each one of
//!element_lengths[i]*sizeof_element bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &tag, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{ mp_header->allocate_many(tag, elem_sizes, n_elements, sizeof_element, chain); }
//!Deallocates all elements contained in chain.
//!Never throws.
void deallocate_many(multiallocation_chain &chain)
{ mp_header->deallocate_many(chain); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Marks previously allocated memory as free. Never throws.
void deallocate (void *addr)
{ if (mp_header) mp_header->deallocate(addr); }
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find (char_ptr_holder_t name)
{ return mp_header->template find<T>(name); }
//!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
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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>
typename segment_manager::template construct_proxy<T>::type
construct(char_ptr_holder_t name)
{ return mp_header->template construct<T>(name); }
//!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
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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>
typename segment_manager::template construct_proxy<T>::type
find_or_construct(char_ptr_holder_t name)
{ return mp_header->template find_or_construct<T>(name); }
//!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
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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>
typename segment_manager::template construct_proxy<T>::type
construct(char_ptr_holder_t name, const std::nothrow_t &tag)
{ return mp_header->template construct<T>(name, tag); }
//!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
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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>
typename segment_manager::template construct_proxy<T>::type
find_or_construct(char_ptr_holder_t name, const std::nothrow_t &tag)
{ return mp_header->template find_or_construct<T>(name, tag); }
//!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
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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
//!
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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
//!
//!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.
//!
//!-> If there is no available memory, returns 0.
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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, const std::nothrow_t &tag)
{ return mp_header->template construct_it<T>(name, tag); }
//!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
//!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.
//!
//!-> If there is no available memory, returns 0.
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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, const std::nothrow_t &tag)
{ return mp_header->template find_or_construct_it<T>(name, tag); }
//!Calls a functor and guarantees that no new construction, search or
//!destruction will be executed by any process while executing the object
//!function call. If the functor throws, this function throws.
template <class Func>
void atomic_func(Func &f)
{ mp_header->atomic_func(f); }
//!Tries to call a functor guaranteeing that no new construction, search or
//!destruction will be executed by any process while executing the object
//!function call. If the atomic function can't be immediatelly executed
//!because the internal mutex is already locked, returns false.
//!If the functor throws, this function throws.
template <class Func>
bool try_atomic_func(Func &f)
{ return mp_header->try_atomic_func(f); }
//!Destroys a named memory object or array.
//!
//!Finds the object with the given name, calls its destructors,
//!frees used memory and returns true.
//!
//!-> If the object is not found, it returns false.
//!
//!Exception Handling:
//!
//!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.
//!
//!Destroying an object:
//!
//!If the destructor throws, the memory will be freed and that exception
//!will be thrown.
//!
//!Destroying an array:
//!
//!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
//!recommended.
template <class T>
bool destroy(const CharType *name)
{ return mp_header->template destroy<T>(name); }
//!Destroys the unique instance of type T
//!
//!Calls the destructor, frees used memory and returns true.
//!
//!Exception Handling:
//!
//!When deleting a dynamically object, the Standard does not
//!guarantee that dynamically allocated memory will be released.
//!
//!Destroying an object:
//!
//!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
//!recommended for memory.
template <class T>
bool destroy(const unique_instance_t *const )
{ return mp_header->template destroy<T>(unique_instance); }
//!Destroys the object (named, unique, or anonymous)
//!
//!Calls the destructor, frees used memory and returns true.
//!
//!Exception Handling:
//!
//!When deleting a dynamically object, the Standard does not
//!guarantee that dynamically allocated memory will be released.
//!
//!Destroying an object:
//!
//!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
//!recommended for memory.
template <class T>
void destroy_ptr(const T *ptr)
{ mp_header->template destroy_ptr<T>(ptr); }
//!Returns the name of an object created with construct/find_or_construct
//!functions. If ptr points to an unique instance typeid(T).name() is returned.
template<class T>
static const char_type *get_instance_name(const T *ptr)
{ return segment_manager::get_instance_name(ptr); }
//!Returns is the type an object created with construct/find_or_construct
//!functions. Does not throw.
template<class T>
static instance_type get_instance_type(const T *ptr)
{ return segment_manager::get_instance_type(ptr); }
//!Returns the length of an object created with construct/find_or_construct
//!functions (1 if is a single element, >=1 if it's an array). Does not throw.
template<class T>
static size_type get_instance_length(const T *ptr)
{ return segment_manager::get_instance_length(ptr); }
//!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
//!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)
{ mp_header->reserve_unique_objects(num); }
//!Calls shrink_to_fit in both named and unique object indexes
//to try to free unused memory from those indexes.
void shrink_to_fit_indexes()
{ mp_header->shrink_to_fit_indexes(); }
//!Returns the number of named objects stored
//!in the managed segment.
size_type get_num_named_objects()
{ return mp_header->get_num_named_objects(); }
//!Returns the number of unique objects stored
//!in the managed segment.
size_type get_num_unique_objects()
{ return mp_header->get_num_unique_objects(); }
//!Returns a constant iterator to the index storing the
//!named allocations. NOT thread-safe. Never throws.
const_named_iterator named_begin() const
{ return mp_header->named_begin(); }
//!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(); }
//!Returns a constant iterator to the index storing the
//!unique allocations. NOT thread-safe. Never throws.
const_unique_iterator unique_begin() const
{ return mp_header->unique_begin(); }
//!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(); }
//!This is the default allocator to allocate types T
//!from this managed segment
template<class T>
struct allocator
{
typedef typename segment_manager::template allocator<T>::type type;
};
//!Returns an instance of the default allocator for type T
//!initialized that allocates memory from this segment manager.
template<class T>
typename allocator<T>::type
get_allocator()
{ return mp_header->template get_allocator<T>(); }
//!This is the default deleter to delete types T
//!from this managed segment.
template<class T>
struct deleter
{
typedef typename segment_manager::template deleter<T>::type type;
};
//!Returns an instance of the default allocator for type T
//!initialized that allocates memory from this segment manager.
template<class T>
typename deleter<T>::type
get_deleter()
{ return mp_header->template get_deleter<T>(); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find_no_lock (char_ptr_holder_t name)
{ return mp_header->template find_no_lock<T>(name); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
protected:
//!Swaps the segment manager's managed by this managed memory segment.
//!NOT thread-safe. Never throws.
void swap(basic_managed_memory_impl &other)
{ (simple_swap)(mp_header, other.mp_header); }
private:
segment_manager *mp_header;
};
template<class BasicManagedMemoryImpl>
class create_open_func
{
typedef typename BasicManagedMemoryImpl::size_type size_type;
public:
create_open_func(BasicManagedMemoryImpl * const frontend, create_enum_t type)
: m_frontend(frontend), m_type(type){}
bool operator()(void *addr, std::size_t size, bool created) const
{
if( ((m_type == DoOpen) && created) ||
((m_type == DoCreate) && !created) ||
//Check for overflow
size_type(-1) < size ){
return false;
}
else if(created){
return m_frontend->create_impl(addr, static_cast<size_type>(size));
}
else{
return m_frontend->open_impl (addr, static_cast<size_type>(size));
}
}
static std::size_t get_min_size()
{
const size_type sz = BasicManagedMemoryImpl::segment_manager::get_min_size();
if(sz > std::size_t(-1)){
//The minimum size is not representable by std::size_t
BOOST_ASSERT(false);
return std::size_t(-1);
}
else{
return static_cast<std::size_t>(sz);
}
}
private:
BasicManagedMemoryImpl *m_frontend;
create_enum_t m_type;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP

View File

@@ -0,0 +1,429 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/managed_memory_impl.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/interprocess/detail/multi_segment_services.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/containers/list.hpp>//list
#include <boost/interprocess/mapped_region.hpp> //mapped_region
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp> //managed_open_or_create_impl
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/streams/vectorstream.hpp>
#include <boost/intrusive/detail/minimal_pair_header.hpp>
#include <string> //string
#include <new> //bad_alloc
#include <ostream>//std::ends
#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/sync/mutex_family.hpp>
//!\file
//!Describes a named shared memory object allocation user class.
namespace boost {
namespace interprocess {
//TODO: We must somehow obtain the permissions of the first segment
//to apply them to subsequent segments
//-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
//!basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType>
template
<
class CharType,
class MemoryAlgorithm,
template<class IndexConfig> class IndexType
>
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
<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, true, false> managed_impl;
typedef typename void_pointer::segment_group_id segment_group_id;
typedef typename base_t::size_type size_type;
////////////////////////////////////////////////////////////////////////
//
// Some internal helper structs/functors
//
////////////////////////////////////////////////////////////////////////
//!This class defines an operator() that creates a shared memory
//!of the requested size. The rest of the parameters are
//!passed in the constructor. The class a template parameter
//!to be used with create_from_file/create_from_istream functions
//!of basic_named_object classes
// class segment_creator
// {
// public:
// segment_creator(shared_memory &shmem,
// const char *mem_name,
// const void *addr)
// : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
//
// void *operator()(size_type size)
// {
// if(!m_shmem.create(m_mem_name, size, m_addr))
// return 0;
// return m_shmem.get_address();
// }
// private:
// shared_memory &m_shmem;
// const char *m_mem_name;
// const void *m_addr;
// };
class group_services
: public multi_segment_services
{
public:
typedef std::pair<void *, size_type> result_type;
typedef basic_managed_multi_shared_memory frontend_t;
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)
: mp_frontend(frontend), m_group(0), m_min_segment_size(0){}
virtual std::pair<void *, size_type> create_new_segment(size_type alloc_size)
{ (void)alloc_size;
/*
//We should allocate an extra byte so that the
//[base_addr + alloc_size] byte belongs to this segment
alloc_size += 1;
//If requested size is less than minimum, update that
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);
}
virtual bool update_segments ()
{ return true; }
virtual ~group_services(){}
void set_group(segment_group_id group)
{ m_group = group; }
segment_group_id get_group() const
{ return m_group; }
void set_min_segment_size(size_type min_segment_size)
{ m_min_segment_size = min_segment_size; }
size_type get_min_segment_size() const
{ return m_min_segment_size; }
private:
frontend_t * const mp_frontend;
segment_group_id m_group;
size_type m_min_segment_size;
};
//!Functor to execute atomically when opening or creating a shared memory
//!segment.
struct create_open_func
{
enum type_t { DoCreate, DoOpen, DoOpenOrCreate };
typedef typename
basic_managed_multi_shared_memory::void_pointer void_pointer;
create_open_func(self_t * const frontend,
type_t type, size_type segment_number)
: 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) ||
((m_type == DoCreate) && !created))
return false;
segment_group_id group = mp_frontend->m_group_services.get_group();
bool mapped = false;
bool impl_done = false;
//Associate this newly created segment as the
//segment id = 0 of this group
void_pointer::insert_mapping
( group
, static_cast<char*>(addr) - managed_impl::ManagedOpenOrCreateUserOffset
, size + managed_impl::ManagedOpenOrCreateUserOffset);
//Check if this is the master segment
if(!m_segment_number){
//Create or open the Interprocess machinery
if((impl_done = created ?
mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){
return true;
}
}
else{
return true;
}
//This is the cleanup part
//---------------
if(impl_done){
mp_frontend->close_impl();
}
if(mapped){
bool ret = void_pointer::erase_last_mapping(group);
BOOST_ASSERT(ret);(void)ret;
}
return false;
}
static std::size_t get_min_size()
{
const size_type sz = self_t::segment_manager::get_min_size();
if(sz > std::size_t(-1)){
//The minimum size is not representable by std::size_t
BOOST_ASSERT(false);
return std::size_t(-1);
}
else{
return static_cast<std::size_t>(sz);
}
}
self_t * const mp_frontend;
type_t m_type;
size_type m_segment_number;
};
//!Functor to execute atomically when closing a shared memory segment.
struct close_func
{
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 &region, bool last) const
{
if(last) mp_frontend->destroy_impl();
else mp_frontend->close_impl();
}
self_t * const mp_frontend;
};
//Friend declarations
friend struct basic_managed_multi_shared_memory::create_open_func;
friend struct basic_managed_multi_shared_memory::close_func;
friend class basic_managed_multi_shared_memory::group_services;
typedef list<managed_impl> shmem_list_t;
basic_managed_multi_shared_memory *get_this_pointer()
{ return this; }
public:
basic_managed_multi_shared_memory(create_only_t,
const char *name,
size_type size,
const permissions &perm = permissions())
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoCreate,name, size, perm);
}
basic_managed_multi_shared_memory(open_or_create_t,
const char *name,
size_type size,
const permissions &perm = permissions())
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoOpenOrCreate, name, size, perm);
}
basic_managed_multi_shared_memory(open_only_t, const char *name)
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoOpen, name, 0, permissions());
}
~basic_managed_multi_shared_memory()
{ this->priv_close(); }
private:
bool priv_open_or_create(typename create_open_func::type_t type,
const char *name,
size_type size,
const permissions &perm)
{
if(!m_shmem_list.empty())
return false;
typename void_pointer::segment_group_id group = 0;
BOOST_TRY{
m_root_name = name;
//Insert multi segment services and get a group identifier
group = void_pointer::new_segment_group(&m_group_services);
size = void_pointer::round_size(size);
m_group_services.set_group(group);
m_group_services.set_min_segment_size(size);
if(group){
if(this->priv_new_segment(type, size, 0, perm)){
return true;
}
}
}
BOOST_CATCH(const std::bad_alloc&){
}
BOOST_CATCH_END
if(group){
void_pointer::delete_group(group);
}
return false;
}
bool priv_new_segment(typename create_open_func::type_t type,
size_type size,
const void *addr,
const permissions &perm)
{
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.
boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter;
//Pre-reserve string size
size_type str_size = m_root_name.length()+10;
if(formatter.vector().size() < str_size){
//This can throw.
formatter.reserve(str_size);
}
//Format segment's name
formatter << m_root_name
<< static_cast<unsigned int>(segment_id) << std::ends;
//This functor will be executed when constructing
create_open_func func(this, type, segment_id);
const char *name = formatter.vector().c_str();
//This can throw.
managed_impl mshm;
switch(type){
case create_open_func::DoCreate:
{
managed_impl shm(create_only, name, size, read_write, addr, func, perm);
mshm = boost::move(shm);
}
break;
case create_open_func::DoOpen:
{
managed_impl shm(open_only, name,read_write, addr, func);
mshm = boost::move(shm);
}
break;
case create_open_func::DoOpenOrCreate:
{
managed_impl shm(open_or_create, name, size, read_write, addr, func, perm);
mshm = boost::move(shm);
}
break;
default:
return false;
break;
}
//This can throw.
m_shmem_list.push_back(boost::move(mshm));
return true;
}
BOOST_CATCH(const std::bad_alloc&){
}
BOOST_CATCH_END
return false;
}
//!Frees resources. Never throws.
void priv_close()
{
if(!m_shmem_list.empty()){
bool ret;
//Obtain group identifier
segment_group_id group = m_group_services.get_group();
//Erase main segment and its resources
//typename shmem_list_t::iterator itbeg = m_shmem_list.begin(),
// itend = m_shmem_list.end(),
// it = itbeg;
//(*itbeg)->close_with_func(close_func(this));
//Delete group. All mappings are erased too.
ret = void_pointer::delete_group(group);
(void)ret;
BOOST_ASSERT(ret);
m_shmem_list.clear();
}
}
private:
shmem_list_t m_shmem_list;
group_services m_group_services;
std::string m_root_name;
};
typedef basic_managed_multi_shared_memory
< char
, rbtree_best_fit<mutex_family, intersegment_ptr<void> >
, iset_index>
managed_multi_shared_memory;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP

View File

@@ -0,0 +1,501 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-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_MANAGED_OPEN_OR_CREATE_IMPL
#define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/container/detail/type_traits.hpp> //alignment_of, aligned_storage
#include <boost/interprocess/sync/spin/wait.hpp>
#include <boost/move/move.hpp>
#include <boost/cstdint.hpp>
namespace boost {
namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace ipcdetail{ class interprocess_tester; }
template<class DeviceAbstraction>
struct managed_open_or_create_impl_device_id_t
{
typedef const char *type;
};
#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
class xsi_shared_memory_file_wrapper;
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
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
namespace ipcdetail {
template <bool StoreDevice, class DeviceAbstraction>
class managed_open_or_create_impl_device_holder
{
public:
DeviceAbstraction &get_device()
{ static DeviceAbstraction dev; return dev; }
const DeviceAbstraction &get_device() const
{ static DeviceAbstraction dev; return dev; }
};
template <class DeviceAbstraction>
class managed_open_or_create_impl_device_holder<true, DeviceAbstraction>
{
public:
DeviceAbstraction &get_device()
{ return dev; }
const DeviceAbstraction &get_device() const
{ return dev; }
private:
DeviceAbstraction dev;
};
template<class DeviceAbstraction, std::size_t MemAlignment, bool FileBased, bool StoreDevice>
class managed_open_or_create_impl
: public managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction>
{
//Non-copyable
BOOST_MOVABLE_BUT_NOT_COPYABLE(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,
InitializedSegment,
CorruptedSegment
};
public:
static const std::size_t
ManagedOpenOrCreateUserOffset =
ct_rounded_size
< sizeof(boost::uint32_t)
, MemAlignment ? (MemAlignment) :
(::boost::container::dtl::alignment_of
< ::boost::container::dtl::max_align_t >::value)
>::value;
managed_open_or_create_impl()
{}
managed_open_or_create_impl(create_only_t,
const device_id_t & id,
std::size_t size,
mode_t mode,
const void *addr,
const permissions &perm)
{
priv_open_or_create
( DoCreate
, id
, size
, mode
, addr
, perm
, null_mapped_region_function());
}
managed_open_or_create_impl(open_only_t,
const device_id_t & id,
mode_t mode,
const void *addr)
{
priv_open_or_create
( DoOpen
, id
, 0
, mode
, addr
, permissions()
, null_mapped_region_function());
}
managed_open_or_create_impl(open_or_create_t,
const device_id_t & id,
std::size_t size,
mode_t mode,
const void *addr,
const permissions &perm)
{
priv_open_or_create
( DoOpenOrCreate
, id
, size
, mode
, addr
, perm
, null_mapped_region_function());
}
template <class ConstructFunc>
managed_open_or_create_impl(create_only_t,
const device_id_t & id,
std::size_t size,
mode_t mode,
const void *addr,
const ConstructFunc &construct_func,
const permissions &perm)
{
priv_open_or_create
(DoCreate
, id
, size
, mode
, addr
, perm
, construct_func);
}
template <class ConstructFunc>
managed_open_or_create_impl(open_only_t,
const device_id_t & id,
mode_t mode,
const void *addr,
const ConstructFunc &construct_func)
{
priv_open_or_create
( DoOpen
, id
, 0
, mode
, addr
, permissions()
, construct_func);
}
template <class ConstructFunc>
managed_open_or_create_impl(open_or_create_t,
const device_id_t & id,
std::size_t size,
mode_t mode,
const void *addr,
const ConstructFunc &construct_func,
const permissions &perm)
{
priv_open_or_create
( DoOpenOrCreate
, id
, size
, mode
, addr
, perm
, construct_func);
}
managed_open_or_create_impl(BOOST_RV_REF(managed_open_or_create_impl) moved)
{ 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;
}
~managed_open_or_create_impl()
{}
std::size_t get_user_size() const
{ return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
void *get_user_address() const
{ return static_cast<char*>(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; }
std::size_t get_real_size() const
{ return m_mapped_region.get_size(); }
void *get_real_address() const
{ return m_mapped_region.get_address(); }
void swap(managed_open_or_create_impl &other)
{
this->m_mapped_region.swap(other.m_mapped_region);
}
bool flush()
{ return m_mapped_region.flush(); }
const mapped_region &get_mapped_region() const
{ return m_mapped_region; }
DeviceAbstraction &get_device()
{ return this->DevHolder::get_device(); }
const DeviceAbstraction &get_device() const
{ return this->DevHolder::get_device(); }
private:
//These are templatized to allow explicit instantiations
template<bool dummy>
static void truncate_device(DeviceAbstraction &, offset_t, false_)
{} //Empty
template<bool dummy>
static void truncate_device(DeviceAbstraction &dev, offset_t size, true_)
{ dev.truncate(size); }
template<bool dummy>
static bool check_offset_t_size(std::size_t , false_)
{ return true; } //Empty
template<bool dummy>
static bool check_offset_t_size(std::size_t size, true_)
{ return size == std::size_t(offset_t(size)); }
//These are templatized to allow explicit instantiations
template<bool dummy>
static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t size, const permissions &perm, false_ file_like)
{
(void)file_like;
DeviceAbstraction tmp(create_only, id, read_write, size, perm);
tmp.swap(dev);
}
template<bool dummy>
static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t, const permissions &perm, true_ file_like)
{
(void)file_like;
DeviceAbstraction tmp(create_only, id, read_write, perm);
tmp.swap(dev);
}
template <class ConstructFunc> inline
void priv_open_or_create
(create_enum_t type,
const device_id_t & id,
std::size_t size,
mode_t mode, const void *addr,
const permissions &perm,
ConstructFunc construct_func)
{
typedef bool_<FileBased> file_like_t;
(void)mode;
bool created = false;
bool ronly = false;
bool cow = false;
DeviceAbstraction dev;
if(type != DoOpen){
//Check if the requested size is enough to build the managed metadata
const std::size_t func_min_size = construct_func.get_min_size();
if( (std::size_t(-1) - ManagedOpenOrCreateUserOffset) < func_min_size ||
size < (func_min_size + ManagedOpenOrCreateUserOffset) ){
throw interprocess_exception(error_info(size_error));
}
}
//Check size can be represented by offset_t (used by truncate)
if(type != DoOpen && !check_offset_t_size<FileBased>(size, file_like_t())){
throw interprocess_exception(error_info(size_error));
}
if(type == DoOpen && mode == read_write){
DeviceAbstraction tmp(open_only, id, read_write);
tmp.swap(dev);
created = false;
}
else if(type == DoOpen && mode == read_only){
DeviceAbstraction tmp(open_only, id, read_only);
tmp.swap(dev);
created = false;
ronly = true;
}
else if(type == DoOpen && mode == copy_on_write){
DeviceAbstraction tmp(open_only, id, read_only);
tmp.swap(dev);
created = false;
cow = true;
}
else if(type == DoCreate){
create_device<FileBased>(dev, id, size, perm, file_like_t());
created = true;
}
else if(type == DoOpenOrCreate){
//This loop is very ugly, but brute force is sometimes better
//than diplomacy. If someone knows how to open or create a
//file and know if we have really created it or just open it
//drop me a e-mail!
bool completed = false;
spin_wait swait;
while(!completed){
try{
create_device<FileBased>(dev, id, size, perm, file_like_t());
created = true;
completed = true;
}
catch(interprocess_exception &ex){
if(ex.get_error_code() != already_exists_error){
throw;
}
else{
try{
DeviceAbstraction tmp(open_only, id, read_write);
dev.swap(tmp);
created = false;
completed = true;
}
catch(interprocess_exception &e){
if(e.get_error_code() != not_found_error){
throw;
}
}
catch(...){
throw;
}
}
}
catch(...){
throw;
}
swait.yield();
}
}
if(created){
try{
//If this throws, we are lost
truncate_device<FileBased>(dev, size, file_like_t());
//If the following throws, we will truncate the file to 1
mapped_region region(dev, read_write, 0, 0, addr);
boost::uint32_t *patomic_word = 0; //avoid gcc warning
patomic_word = static_cast<boost::uint32_t*>(region.get_address());
boost::uint32_t previous = atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
if(previous == UninitializedSegment){
try{
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);
}
catch(...){
atomic_write32(patomic_word, CorruptedSegment);
throw;
}
atomic_write32(patomic_word, InitializedSegment);
}
else if(previous == InitializingSegment || previous == InitializedSegment){
throw interprocess_exception(error_info(already_exists_error));
}
else{
throw interprocess_exception(error_info(corrupted_error));
}
}
catch(...){
try{
truncate_device<FileBased>(dev, 1u, file_like_t());
}
catch(...){
}
throw;
}
}
else{
if(FileBased){
offset_t filesize = 0;
spin_wait swait;
while(filesize == 0){
if(!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){
error_info err = system_error_code();
throw interprocess_exception(err);
}
swait.yield();
}
if(filesize == 1){
throw interprocess_exception(error_info(corrupted_error));
}
}
mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());
boost::uint32_t value = atomic_read32(patomic_word);
spin_wait swait;
while(value == InitializingSegment || value == UninitializedSegment){
swait.yield();
value = atomic_read32(patomic_word);
}
if(value != InitializedSegment)
throw interprocess_exception(error_info(corrupted_error));
construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
, region.get_size() - ManagedOpenOrCreateUserOffset
, false);
//All ok, just move resources to the external mapped region
m_mapped_region.swap(region);
}
if(StoreDevice){
this->DevHolder::get_device() = boost::move(dev);
}
}
friend void swap(managed_open_or_create_impl &left, managed_open_or_create_impl &right)
{
left.swap(right);
}
private:
friend class interprocess_tester;
void dont_close_on_destruction()
{ interprocess_tester::dont_close_on_destruction(m_mapped_region); }
mapped_region m_mapped_region;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL

View File

@@ -0,0 +1,118 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Stephen Cleary 2000.
// (C) Copyright Ion Gaztanaga 2007-2012.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
// This file is a slightly modified file from Boost.Pool
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP
#define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <climits>
#include <boost/static_assert.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
// Greatest common divisor and least common multiple
//
// gcd is an algorithm that calculates the greatest common divisor of two
// integers, using Euclid's algorithm.
//
// Pre: A > 0 && B > 0
// Recommended: A > B
template <typename Integer>
inline Integer gcd(Integer A, Integer B)
{
do
{
const Integer tmp(B);
B = A % B;
A = tmp;
} while (B != 0);
return A;
}
//
// lcm is an algorithm that calculates the least common multiple of two
// integers.
//
// Pre: A > 0 && B > 0
// Recommended: A > B
template <typename Integer>
inline Integer lcm(const Integer & A, const Integer & B)
{
Integer ret = A;
ret /= gcd(A, B);
ret *= B;
return ret;
}
template <typename Integer>
inline Integer log2_ceil(const Integer & A)
{
Integer i = 0;
Integer power_of_2 = 1;
while(power_of_2 < A){
power_of_2 <<= 1;
++i;
}
return i;
}
template <typename Integer>
inline Integer upper_power_of_2(const Integer & A)
{
Integer power_of_2 = 1;
while(power_of_2 < A){
power_of_2 <<= 1;
}
return power_of_2;
}
//This function uses binary search to discover the
//highest set bit of the integer
inline std::size_t floor_log2 (std::size_t x)
{
const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT;
const bool Size_t_Bits_Power_2= !(Bits & (Bits-1));
BOOST_STATIC_ASSERT(((Size_t_Bits_Power_2)== true));
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)
log2 += shift, n = tmp;
}
return log2;
}
} // namespace ipcdetail
} // namespace interprocess
} // namespace boost
#endif

View File

@@ -0,0 +1,44 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP
#define BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost {
namespace interprocess {
template<class T>
const T &max_value(const T &a, const T &b)
{ return a > b ? a : b; }
template<class T>
const T &min_value(const T &a, const T &b)
{ return a < b ? a : b; }
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP

View File

@@ -0,0 +1,36 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2010-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/move for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//! \file
#ifndef BOOST_INTERPROCESS_DETAIL_MOVE_HPP
#define BOOST_INTERPROCESS_DETAIL_MOVE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/move/utility_core.hpp>
namespace boost {
namespace interprocess {
using ::boost::move;
using ::boost::forward;
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MOVE_HPP

View File

@@ -0,0 +1,122 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2016.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MPL_HPP
#define BOOST_INTERPROCESS_DETAIL_MPL_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <cstddef>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template <class T, T val>
struct integral_constant
{
static const T value = val;
typedef integral_constant<T,val> type;
};
template< bool C_ >
struct bool_ : integral_constant<bool, C_>
{
static const bool value = C_;
};
typedef bool_<true> true_;
typedef bool_<false> false_;
typedef true_ true_type;
typedef false_ false_type;
typedef char yes_type;
struct no_type
{
char padding[8];
};
template <bool B, class T = void>
struct enable_if_c {
typedef T type;
};
template <class T>
struct enable_if_c<false, T> {};
template <class Cond, class T = void>
struct enable_if : public enable_if_c<Cond::value, T> {};
template <class Cond, class T = void>
struct disable_if : public enable_if_c<!Cond::value, T> {};
template<
bool C
, typename T1
, typename T2
>
struct if_c
{
typedef T1 type;
};
template<
typename T1
, typename T2
>
struct if_c<false,T1,T2>
{
typedef T2 type;
};
template<
typename T1
, typename T2
, typename T3
>
struct if_
{
typedef typename if_c<0 != T1::value, T2, T3>::type type;
};
template<std::size_t S>
struct ls_zeros
{
static const std::size_t value = (S & std::size_t(1)) ? 0 : (1u + ls_zeros<(S >> 1u)>::value);
};
template<>
struct ls_zeros<0>
{
static const std::size_t value = 0;
};
template<>
struct ls_zeros<1>
{
static const std::size_t value = 0;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MPL_HPP

View File

@@ -0,0 +1,316 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP
#define BOOST_INTERPROCESS_NAMED_PROXY_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
// interprocess/detail
#include <boost/interprocess/detail/in_place_interface.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/move/utility_core.hpp>
#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
#include <boost/move/detail/fwd_macros.hpp>
#else
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/detail/variadic_templates_tools.hpp>
#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
#include <boost/container/detail/placement_new.hpp>
#include <cstddef>
//!\file
//!Describes a proxy class that implements named allocation syntax.
namespace boost {
namespace interprocess {
namespace ipcdetail {
#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
template<class T, bool is_iterator, class ...Args>
struct CtorArgN : public placement_destroy<T>
{
typedef bool_<is_iterator> IsIterator;
typedef CtorArgN<T, is_iterator, Args...> self_t;
typedef typename build_number_seq<sizeof...(Args)>::type index_tuple_t;
self_t& operator++()
{
this->do_increment(IsIterator(), index_tuple_t());
return *this;
}
self_t operator++(int) { return ++*this; *this; }
CtorArgN(Args && ...args)
: args_(args...)
{}
virtual void construct_n(void *mem
, std::size_t num
, std::size_t &constructed)
{
T* memory = static_cast<T*>(mem);
for(constructed = 0; constructed < num; ++constructed){
this->construct(memory++, IsIterator(), index_tuple_t());
this->do_increment(IsIterator(), index_tuple_t());
}
}
private:
template<std::size_t ...IdxPack>
void construct(void *mem, true_, const index_tuple<IdxPack...>&)
{ ::new((void*)mem, boost_container_new_t())T(*boost::forward<Args>(get<IdxPack>(args_))...); }
template<std::size_t ...IdxPack>
void construct(void *mem, false_, const index_tuple<IdxPack...>&)
{ ::new((void*)mem, boost_container_new_t())T(boost::forward<Args>(get<IdxPack>(args_))...); }
template<std::size_t ...IdxPack>
void do_increment(true_, const index_tuple<IdxPack...>&)
{
this->expansion_helper(++get<IdxPack>(args_)...);
}
template<class ...ExpansionArgs>
void expansion_helper(ExpansionArgs &&...)
{}
template<std::size_t ...IdxPack>
void do_increment(false_, const index_tuple<IdxPack...>&)
{}
tuple<Args&...> args_;
};
//!Describes a proxy class that implements named
//!allocation syntax.
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?
>
class named_proxy
{
typedef typename SegmentManager::char_type char_type;
const char_type * mp_name;
SegmentManager * mp_mngr;
mutable std::size_t m_num;
const bool m_find;
const bool m_dothrow;
public:
named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow)
: mp_name(name), mp_mngr(mngr), m_num(1)
, m_find(find), m_dothrow(dothrow)
{}
template<class ...Args>
T *operator()(Args &&...args) const
{
CtorArgN<T, is_iterator, Args...> &&ctor_obj = CtorArgN<T, is_iterator, Args...>
(boost::forward<Args>(args)...);
return mp_mngr->template
generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj);
}
//This operator allows --> named_new("Name")[3]; <-- syntax
const named_proxy &operator[](std::size_t num) const
{ m_num *= num; return *this; }
};
#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
////////////////////////////////////////////////////////////////
// What the macro should generate (n == 2):
//
// template<class T, bool is_iterator, class P1, class P2>
// struct Ctor2Arg
// : public placement_destroy<T>
// {
// typedef bool_<is_iterator> IsIterator;
// typedef Ctor2Arg self_t;
//
// void do_increment(false_)
// { ++m_p1; ++m_p2; }
//
// void do_increment(true_){}
//
// self_t& operator++()
// {
// this->do_increment(IsIterator());
// return *this;
// }
//
// self_t operator++(int) { return ++*this; *this; }
//
// Ctor2Arg(const P1 &p1, const P2 &p2)
// : p1((P1 &)p_1), p2((P2 &)p_2) {}
//
// void construct(void *mem)
// { new((void*)object)T(m_p1, m_p2); }
//
// virtual void construct_n(void *mem
// , std::size_t num
// , std::size_t &constructed)
// {
// T* memory = static_cast<T*>(mem);
// for(constructed = 0; constructed < num; ++constructed){
// this->construct(memory++, IsIterator());
// this->do_increment(IsIterator());
// }
// }
//
// 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); }
//
// P1 &m_p1; P2 &m_p2;
// };
////////////////////////////////////////////////////////////////
#define BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN(N)\
\
template<class T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \
struct CtorArg##N : placement_destroy<T>\
{\
typedef CtorArg##N self_t;\
\
CtorArg##N ( BOOST_MOVE_UREF##N )\
BOOST_MOVE_COLON##N BOOST_MOVE_FWD_INIT##N{}\
\
virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed)\
{\
T* memory = static_cast<T*>(mem);\
for(constructed = 0; constructed < num; ++constructed){\
::new((void*)memory++) T ( BOOST_MOVE_MFWD##N );\
}\
}\
\
private:\
BOOST_MOVE_MREF##N\
};\
//!
BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN)
#undef BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN
#define BOOST_INTERPROCESS_NAMED_PROXY_CTORITN(N)\
\
template<class T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \
struct CtorIt##N : public placement_destroy<T>\
{\
typedef CtorIt##N self_t;\
\
self_t& operator++()\
{ BOOST_MOVE_MINC##N; return *this; }\
\
self_t operator++(int) { return ++*this; *this; }\
\
CtorIt##N ( BOOST_MOVE_VAL##N )\
BOOST_MOVE_COLON##N BOOST_MOVE_VAL_INIT##N{}\
\
virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed)\
{\
T* memory = static_cast<T*>(mem);\
for(constructed = 0; constructed < num; ++constructed){\
::new((void*)memory++) T( BOOST_MOVE_MITFWD##N );\
++(*this);\
}\
}\
\
private:\
BOOST_MOVE_MEMB##N\
};\
//!
BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CTORITN)
#undef BOOST_INTERPROCESS_NAMED_PROXY_CTORITN
//!Describes a proxy class that implements named
//!allocation syntax.
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?
>
class named_proxy
{
typedef typename SegmentManager::char_type char_type;
const char_type * mp_name;
SegmentManager * mp_mngr;
mutable std::size_t m_num;
const bool m_find;
const bool m_dothrow;
public:
named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow)
: mp_name(name), mp_mngr(mngr), m_num(1)
, m_find(find), m_dothrow(dothrow)
{}
#define BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR(N)\
\
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
T *operator()( BOOST_MOVE_UREF##N ) const\
{\
typedef typename if_c<is_iterator \
, CtorIt##N <T BOOST_MOVE_I##N BOOST_MOVE_TARG##N> \
, CtorArg##N<T BOOST_MOVE_I##N BOOST_MOVE_TARG##N> \
>::type ctor_obj_t;\
ctor_obj_t ctor_obj = ctor_obj_t( BOOST_MOVE_FWD##N );\
return mp_mngr->template generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj);\
}\
//
BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR)
#undef BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR
////////////////////////////////////////////////////////////////////////
// What the macro should generate (n == 2)
////////////////////////////////////////////////////////////////////////
//
// template <class P1, class P2>
// T *operator()(P1 &p1, P2 &p2) const
// {
// typedef CtorArg2
// <T, is_iterator, P1, P2>
// ctor_obj_t;
// ctor_obj_t ctor_obj(p1, p2);
//
// return mp_mngr->template generic_construct<T>
// (mp_name, m_num, m_find, m_dothrow, ctor_obj);
// }
//
//////////////////////////////////////////////////////////////////////////
//This operator allows --> named_new("Name")[3]; <-- syntax
const named_proxy &operator[](std::size_t num) const
{ m_num *= num; return *this; }
};
#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
}}} //namespace boost { namespace interprocess { namespace ipcdetail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP

View File

@@ -0,0 +1,42 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2014-2015. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP
#define BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace std { //no namespace versioning in clang+libc++
struct nothrow_t;
} //namespace std {
namespace boost{ namespace interprocess {
template <int Dummy = 0>
struct nothrow
{
static const std::nothrow_t &get() { return *pnothrow; }
static std::nothrow_t *pnothrow;
};
template <int Dummy>
std::nothrow_t *nothrow<Dummy>::pnothrow =
reinterpret_cast<std::nothrow_t *>(0x1234); //Avoid sanitizer warnings on references to null
}} //namespace boost{ namespace interprocess {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP

View File

@@ -0,0 +1,745 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP
#define BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/permissions.hpp>
#include <climits>
#include <limits>
#include <string>
#include <boost/move/detail/type_traits.hpp> //make_unsigned
#if defined (BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <fcntl.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <dirent.h>
# include <cerrno>
# include <cstdio>
# if 0
# include <sys/file.h>
# endif
# else
# error Unknown platform
# endif
#endif
#include <cstring>
#include <cstdlib>
namespace boost {
namespace interprocess {
#if defined (BOOST_INTERPROCESS_WINDOWS)
typedef void * file_handle_t;
typedef __int64 offset_t;
typedef struct mapping_handle_impl_t{
void * handle;
bool is_shm;
} mapping_handle_t;
typedef enum { read_only = winapi::generic_read
, read_write = winapi::generic_read | winapi::generic_write
, copy_on_write
, read_private
, invalid_mode = 0xffff
} mode_t;
typedef enum { file_begin = winapi::file_begin
, file_end = winapi::file_end
, file_current = winapi::file_current
} file_pos_t;
typedef unsigned long map_options_t;
static const map_options_t default_map_options = map_options_t(-1);
namespace ipcdetail{
inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd)
{
mapping_handle_t ret;
ret.handle = hnd;
ret.is_shm = false;
return ret;
}
inline mapping_handle_t mapping_handle_from_shm_handle(file_handle_t hnd)
{
mapping_handle_t ret;
ret.handle = hnd;
ret.is_shm = true;
return ret;
}
inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd)
{ return hnd.handle; }
inline bool create_directory(const char *path)
{ return winapi::create_directory(path); }
inline bool remove_directory(const char *path)
{ return winapi::remove_directory(path); }
inline bool get_temporary_path(char *buffer, std::size_t buf_len, std::size_t &required_len)
{
required_len = 0;
//std::size_t is always bigger or equal than unsigned long in Windows systems
//In case std::size_t is bigger than unsigned long
unsigned long buf = buf_len;
if(buf_len != buf){ //maybe overflowed
return false;
}
required_len = winapi::get_temp_path(buf_len, buffer);
const bool ret = !(buf_len < required_len);
if(ret && buffer[required_len-1] == '\\'){
buffer[required_len-1] = 0;
}
return ret;
}
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());
}
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());
}
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);
}
inline bool delete_file(const char *name)
{ return winapi::unlink_file(name); }
inline bool truncate_file (file_handle_t hnd, std::size_t size)
{
offset_t filesize;
if(!winapi::get_file_size(hnd, filesize))
return false;
typedef ::boost::move_detail::make_unsigned<offset_t>::type uoffset_t;
const uoffset_t max_filesize = uoffset_t((std::numeric_limits<offset_t>::max)());
const uoffset_t uoff_size = uoffset_t(size);
//Avoid unused variable warnings in 32 bit systems
if(uoff_size > max_filesize){
winapi::set_last_error(winapi::error_file_too_large);
return false;
}
if(offset_t(size) > filesize){
if(!winapi::set_file_pointer(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
;remaining > 0
;remaining -= write_size){
const std::size_t DataSize = 512;
static char data [DataSize];
write_size = DataSize < remaining ? DataSize : remaining;
unsigned long written;
winapi::write_file(hnd, data, (unsigned long)write_size, &written, 0);
if(written != write_size){
return false;
}
}
}
else{
if(!winapi::set_file_pointer(hnd, size, 0, winapi::file_begin)){
return false;
}
if(!winapi::set_end_of_file(hnd)){
return false;
}
}
return true;
}
inline bool get_file_size(file_handle_t hnd, offset_t &size)
{ return winapi::get_file_size(hnd, size); }
inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos)
{ return winapi::set_file_pointer(hnd, off, 0, (unsigned long) pos); }
inline bool get_file_pointer(file_handle_t hnd, offset_t &off)
{ return winapi::set_file_pointer(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);
}
inline file_handle_t invalid_file()
{ return winapi::invalid_handle_value; }
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 = ((unsigned long)-1);
// winapi::interprocess_overlapped overlapped;
// std::memset(&overlapped, 0, sizeof(overlapped));
return winapi::lock_file_ex
(hnd, winapi::lockfile_exclusive_lock, 0, len, len, &overlapped);
}
inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired)
{
const unsigned long len = ((unsigned long)-1);
winapi::interprocess_overlapped overlapped;
std::memset(&overlapped, 0, sizeof(overlapped));
if(!winapi::lock_file_ex
(hnd, winapi::lockfile_exclusive_lock | winapi::lockfile_fail_immediately,
0, len, len, &overlapped)){
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 = ((unsigned long)-1);
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 = ((unsigned long)-1);
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 = ((unsigned long)-1);
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 ?
acquired = false, true : false;
}
return (acquired = true);
}
inline bool release_file_lock_sharable(file_handle_t hnd)
{ return release_file_lock(hnd); }
inline bool delete_subdirectories_recursive
(const std::string &refcstrRootDirectory, const char *dont_delete_this, unsigned int count)
{
bool bSubdirectory = false; // Flag, indicating whether
// subdirectories have been found
void * hFile; // Handle to directory
std::string strFilePath; // Filepath
std::string strPattern; // Pattern
winapi::win32_find_data FileInformation; // File information
//Find all files and directories
strPattern = refcstrRootDirectory + "\\*.*";
hFile = winapi::find_first_file(strPattern.c_str(), &FileInformation);
if(hFile != winapi::invalid_handle_value){
do{
//If it's not "." or ".." or the pointed root_level dont_delete_this erase it
if(FileInformation.cFileName[0] != '.' &&
!(dont_delete_this && count == 0 && std::strcmp(dont_delete_this, FileInformation.cFileName) == 0)){
strFilePath.erase();
strFilePath = refcstrRootDirectory + "\\" + FileInformation.cFileName;
//If it's a directory, go recursive
if(FileInformation.dwFileAttributes & winapi::file_attribute_directory){
// Delete subdirectory
if(!delete_subdirectories_recursive(strFilePath, dont_delete_this, count+1)){
winapi::find_close(hFile);
return false;
}
}
//If it's a file, just delete it
else{
// Set file attributes
//if(::SetFileAttributes(strFilePath.c_str(), winapi::file_attribute_normal) == 0)
//return winapi::get_last_error();
// Delete file
winapi::unlink_file(strFilePath.c_str());
}
}
//Go to the next file
} while(winapi::find_next_file(hFile, &FileInformation) == 1);
// Close handle
winapi::find_close(hFile);
//See if the loop has ended with an error or just because we've traversed all the files
if(winapi::get_last_error() != winapi::error_no_more_files){
return false;
}
else
{
//Erase empty subdirectories or original refcstrRootDirectory
if(!bSubdirectory && count)
{
// Set directory attributes
//if(::SetFileAttributes(refcstrRootDirectory.c_str(), FILE_ATTRIBUTE_NORMAL) == 0)
//return ::GetLastError();
// Delete directory
if(winapi::remove_directory(refcstrRootDirectory.c_str()) == 0)
return false;
}
}
}
return true;
}
//This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this"
inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this)
{
return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this, 0u);
}
template<class Function>
inline bool for_each_file_in_dir(const char *dir, Function f)
{
void * hFile; // Handle to directory
winapi::win32_find_data FileInformation; // File information
//Get base directory
std::string str(dir);
const std::size_t base_root_dir_len = str.size();
//Find all files and directories
str += "\\*.*";
hFile = winapi::find_first_file(str.c_str(), &FileInformation);
if(hFile != winapi::invalid_handle_value){
do{ //Now loop every file
str.erase(base_root_dir_len);
//If it's not "." or ".." skip it
if(FileInformation.cFileName[0] != '.'){
str += "\\"; str += FileInformation.cFileName;
//If it's a file, apply erase logic
if(!(FileInformation.dwFileAttributes & winapi::file_attribute_directory)){
f(str.c_str(), FileInformation.cFileName);
}
}
//Go to the next file
} while(winapi::find_next_file(hFile, &FileInformation) == 1);
// Close handle and see if the loop has ended with an error
winapi::find_close(hFile);
if(winapi::get_last_error() != winapi::error_no_more_files){
return false;
}
}
return true;
}
#else //#if defined (BOOST_INTERPROCESS_WINDOWS)
typedef int file_handle_t;
typedef off_t offset_t;
typedef struct mapping_handle_impl_t
{
file_handle_t handle;
bool is_xsi;
} mapping_handle_t;
typedef enum { read_only = O_RDONLY
, read_write = O_RDWR
, copy_on_write
, read_private
, invalid_mode = 0xffff
} mode_t;
typedef enum { file_begin = SEEK_SET
, file_end = SEEK_END
, file_current = SEEK_CUR
} file_pos_t;
typedef int map_options_t;
static const map_options_t default_map_options = map_options_t(-1);
namespace ipcdetail{
inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd)
{
mapping_handle_t ret;
ret.handle = hnd;
ret.is_xsi = false;
return ret;
}
inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd)
{ return hnd.handle; }
inline bool create_directory(const char *path)
{ return ::mkdir(path, 0777) == 0 && ::chmod(path, 0777) == 0; }
inline bool remove_directory(const char *path)
{ return ::rmdir(path) == 0; }
inline bool get_temporary_path(char *buffer, std::size_t buf_len, std::size_t &required_len)
{
required_len = 5u;
if(buf_len < required_len)
return false;
else{
std::strcpy(buffer, "/tmp");
}
return true;
}
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){
::fchmod(ret, perm.get_permissions());
}
return ret;
}
inline file_handle_t create_or_open_file
(const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false)
{
(void)temporary;
int ret = -1;
//We need a loop to change permissions correctly using fchmod, since
//with "O_CREAT only" ::open we don't know if we've created or opened the file.
while(true){
ret = ::open(name, ((int)mode) | O_EXCL | O_CREAT, perm.get_permissions());
if(ret >= 0){
::fchmod(ret, perm.get_permissions());
break;
}
else if(errno == EEXIST){
if((ret = ::open(name, (int)mode)) >= 0 || errno != ENOENT){
break;
}
}
else{
break;
}
}
return ret;
}
inline file_handle_t open_existing_file
(const char *name, mode_t mode, bool temporary = false)
{
(void)temporary;
return ::open(name, (int)mode);
}
inline bool delete_file(const char *name)
{ return ::unlink(name) == 0; }
inline bool truncate_file (file_handle_t hnd, std::size_t size)
{
typedef boost::move_detail::make_unsigned<off_t>::type uoff_t;
if(uoff_t((std::numeric_limits<off_t>::max)()) < size){
errno = EINVAL;
return false;
}
return 0 == ::ftruncate(hnd, off_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){
size = data.st_size;
}
return ret;
}
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);
}
inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata)
{ return (ssize_t(numdata)) == ::write(hnd, data, numdata); }
inline file_handle_t invalid_file()
{ return -1; }
inline bool close_file(file_handle_t hnd)
{ return ::close(hnd) == 0; }
inline bool acquire_file_lock(file_handle_t hnd)
{
struct ::flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
return -1 != ::fcntl(hnd, F_SETLKW, &lock);
}
inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired)
{
struct ::flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
int ret = ::fcntl(hnd, F_SETLK, &lock);
if(ret == -1){
return (errno == EAGAIN || errno == EACCES) ?
(acquired = false, true) : false;
}
return (acquired = true);
}
inline bool release_file_lock(file_handle_t hnd)
{
struct ::flock lock;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
return -1 != ::fcntl(hnd, F_SETLK, &lock);
}
inline bool acquire_file_lock_sharable(file_handle_t hnd)
{
struct ::flock lock;
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
return -1 != ::fcntl(hnd, F_SETLKW, &lock);
}
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;
lock.l_start = 0;
lock.l_len = 0;
int ret = ::fcntl(hnd, F_SETLK, &lock);
if(ret == -1){
return (errno == EAGAIN || errno == EACCES) ?
(acquired = false, true) : false;
}
return (acquired = true);
}
inline bool release_file_lock_sharable(file_handle_t hnd)
{ return release_file_lock(hnd); }
#if 0
inline bool acquire_file_lock(file_handle_t hnd)
{ return 0 == ::flock(hnd, LOCK_EX); }
inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired)
{
int ret = ::flock(hnd, LOCK_EX | LOCK_NB);
acquired = ret == 0;
return (acquired || errno == EWOULDBLOCK);
}
inline bool release_file_lock(file_handle_t hnd)
{ return 0 == ::flock(hnd, LOCK_UN); }
inline bool acquire_file_lock_sharable(file_handle_t hnd)
{ return 0 == ::flock(hnd, LOCK_SH); }
inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired)
{
int ret = ::flock(hnd, LOCK_SH | LOCK_NB);
acquired = ret == 0;
return (acquired || errno == EWOULDBLOCK);
}
inline bool release_file_lock_sharable(file_handle_t hnd)
{ return 0 == ::flock(hnd, LOCK_UN); }
#endif
inline bool delete_subdirectories_recursive
(const std::string &refcstrRootDirectory, const char *dont_delete_this)
{
DIR *d = opendir(refcstrRootDirectory.c_str());
if(!d) {
return false;
}
struct dir_close
{
DIR *d_;
dir_close(DIR *d) : d_(d) {}
~dir_close() { ::closedir(d_); }
} dc(d); (void)dc;
struct ::dirent *de;
struct ::stat st;
std::string fn;
while((de=::readdir(d))) {
if( de->d_name[0] == '.' && ( de->d_name[1] == '\0'
|| (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){
continue;
}
if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){
continue;
}
fn = refcstrRootDirectory;
fn += '/';
fn += de->d_name;
if(std::remove(fn.c_str())) {
if(::stat(fn.c_str(), & st)) {
return false;
}
if(S_ISDIR(st.st_mode)) {
if(!delete_subdirectories_recursive(fn, 0) ){
return false;
}
} else {
return false;
}
}
}
return std::remove(refcstrRootDirectory.c_str()) ? false : true;
}
template<class Function>
inline bool for_each_file_in_dir(const char *dir, Function f)
{
std::string refcstrRootDirectory(dir);
DIR *d = opendir(refcstrRootDirectory.c_str());
if(!d) {
return false;
}
struct dir_close
{
DIR *d_;
dir_close(DIR *d) : d_(d) {}
~dir_close() { ::closedir(d_); }
} dc(d); (void)dc;
struct ::dirent *de;
struct ::stat st;
std::string fn;
while((de=::readdir(d))) {
if( de->d_name[0] == '.' && ( de->d_name[1] == '\0'
|| (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){
continue;
}
fn = refcstrRootDirectory;
fn += '/';
fn += de->d_name;
if(::stat(fn.c_str(), & st)) {
return false;
}
//If it's a file, apply erase logic
if(!S_ISDIR(st.st_mode)) {
f(fn.c_str(), de->d_name);
}
}
return true;
}
//This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this"
inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this)
{
return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this );
}
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
inline bool open_or_create_directory(const char *dir_name)
{
//If fails, check that it's because it already exists
if(!create_directory(dir_name)){
error_info info(system_error_code());
if(info.get_error_code() != already_exists_error){
return false;
}
}
return true;
}
inline std::string get_temporary_path()
{
std::size_t required_len = 0;
get_temporary_path(0, 0, required_len);
std::string ret_str(required_len, char(0));
get_temporary_path(&ret_str[0], ret_str.size(), required_len);
while(!ret_str.empty() && !ret_str[ret_str.size()-1]){
ret_str.erase(ret_str.size()-1);
}
return ret_str;
}
} //namespace ipcdetail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP

View File

@@ -0,0 +1,634 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//Thread launching functions are adapted from boost/detail/lightweight_thread.hpp
//
// boost/detail/lightweight_thread.hpp
//
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
// Copyright (c) 2008 Peter Dimov
//
// 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
#ifndef BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP
#define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <cstddef>
#include <ostream>
#if defined(BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
# include <process.h>
#else
# include <pthread.h>
# include <unistd.h>
# include <sched.h>
# include <time.h>
# ifdef BOOST_INTERPROCESS_BSD_DERIVATIVE
//Some *BSD systems (OpenBSD & NetBSD) need sys/param.h before sys/sysctl.h, whereas
//others (FreeBSD & Darwin) need sys/types.h
# include <sys/types.h>
# include <sys/param.h>
# include <sys/sysctl.h>
# endif
#if defined(__VXWORKS__)
#include <vxCpuLib.h>
#endif
//According to the article "C/C++ tip: How to measure elapsed real time for benchmarking"
//Check MacOs first as macOS 10.12 SDK defines both CLOCK_MONOTONIC and
//CLOCK_MONOTONIC_RAW and no clock_gettime.
# if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
# include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
# define BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
# elif defined(CLOCK_MONOTONIC_PRECISE) //BSD
# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_PRECISE
# elif defined(CLOCK_MONOTONIC_RAW) //Linux
# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW
# elif defined(CLOCK_HIGHRES) //Solaris
# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_HIGHRES
# elif defined(CLOCK_MONOTONIC) //POSIX (AIX, BSD, Linux, Solaris)
# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC
# else
# error "No high resolution steady clock in your system, please provide a patch"
# endif
#endif
namespace boost {
namespace interprocess {
namespace ipcdetail{
#if defined (BOOST_INTERPROCESS_WINDOWS)
typedef unsigned long OS_process_id_t;
typedef unsigned long OS_thread_id_t;
struct OS_thread_t
{
OS_thread_t()
: m_handle()
{}
void* handle() const
{ return m_handle; }
void* m_handle;
};
typedef OS_thread_id_t OS_systemwide_thread_id_t;
//process
inline OS_process_id_t get_current_process_id()
{ return winapi::get_current_process_id(); }
inline OS_process_id_t get_invalid_process_id()
{ return OS_process_id_t(0); }
//thread
inline OS_thread_id_t get_current_thread_id()
{ return winapi::get_current_thread_id(); }
inline OS_thread_id_t get_invalid_thread_id()
{ return OS_thread_id_t(0xffffffff); }
inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2)
{ return id1 == id2; }
//return the system tick in ns
inline unsigned long get_system_tick_ns()
{
unsigned long curres, ignore1, ignore2;
winapi::query_timer_resolution(&ignore1, &ignore2, &curres);
//Windows API returns the value in hundreds of ns
return (curres - 1ul)*100ul;
}
//return the system tick in us
inline unsigned long get_system_tick_us()
{
unsigned long curres, ignore1, ignore2;
winapi::query_timer_resolution(&ignore1, &ignore2, &curres);
//Windows API returns the value in hundreds of ns
return (curres - 1ul)/10ul + 1ul;
}
typedef unsigned __int64 OS_highres_count_t;
inline unsigned long get_system_tick_in_highres_counts()
{
__int64 freq;
unsigned long curres, ignore1, ignore2;
winapi::query_timer_resolution(&ignore1, &ignore2, &curres);
//Frequency in counts per second
if(!winapi::query_performance_frequency(&freq)){
//Tick resolution in ms
return (curres-1ul)/10000ul + 1ul;
}
else{
//In femtoseconds
__int64 count_fs = (1000000000000000LL - 1LL)/freq + 1LL;
__int64 tick_counts = (static_cast<__int64>(curres)*100000000LL - 1LL)/count_fs + 1LL;
return static_cast<unsigned long>(tick_counts);
}
}
inline OS_highres_count_t get_current_system_highres_count()
{
__int64 count;
if(!winapi::query_performance_counter(&count)){
count = winapi::get_tick_count();
}
return count;
}
inline void zero_highres_count(OS_highres_count_t &count)
{ count = 0; }
inline bool is_highres_count_zero(const OS_highres_count_t &count)
{ return count == 0; }
template <class Ostream>
inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count)
{
ostream << count;
return ostream;
}
inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r)
{ return l - r; }
inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r)
{ return l < r; }
inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r)
{ return l < static_cast<OS_highres_count_t>(r); }
inline void thread_sleep_tick()
{ winapi::sleep_tick(); }
inline void thread_yield()
{ winapi::sched_yield(); }
inline void thread_sleep(unsigned int ms)
{ winapi::sleep(ms); }
//systemwide thread
inline OS_systemwide_thread_id_t get_current_systemwide_thread_id()
{
return get_current_thread_id();
}
inline void systemwide_thread_id_copy
(const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to)
{
to = from;
}
inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2)
{
return equal_thread_id(id1, id2);
}
inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id()
{
return get_invalid_thread_id();
}
inline long double get_current_process_creation_time()
{
winapi::interprocess_filetime CreationTime, ExitTime, KernelTime, UserTime;
winapi::get_process_times
( winapi::get_current_process(), &CreationTime, &ExitTime, &KernelTime, &UserTime);
typedef long double ldouble_t;
const ldouble_t resolution = (100.0l/1000000000.0l);
return CreationTime.dwHighDateTime*(ldouble_t(1u<<31u)*2.0l*resolution) +
CreationTime.dwLowDateTime*resolution;
}
inline unsigned int get_num_cores()
{
winapi::interprocess_system_info sysinfo;
winapi::get_system_info( &sysinfo );
//in Windows dw is long which is equal in bits to int
return static_cast<unsigned>(sysinfo.dwNumberOfProcessors);
}
#else //#if defined (BOOST_INTERPROCESS_WINDOWS)
typedef pthread_t OS_thread_t;
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()
{}
OS_systemwide_thread_id_t(pid_t p, pthread_t t)
: pid(p), tid(t)
{}
OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x)
: pid(x.pid), tid(x.tid)
{}
OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x)
: pid(x.pid), tid(x.tid)
{}
OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x)
{ pid = x.pid; tid = x.tid; return *this; }
OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x)
{ pid = x.pid; tid = x.tid; return *this; }
void operator=(const OS_systemwide_thread_id_t &x) volatile
{ pid = x.pid; tid = x.tid; }
pid_t pid;
pthread_t tid;
};
inline void systemwide_thread_id_copy
(const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to)
{
to.pid = from.pid;
to.tid = from.tid;
}
//process
inline OS_process_id_t get_current_process_id()
{ return ::getpid(); }
inline OS_process_id_t get_invalid_process_id()
{ return pid_t(0); }
//thread
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;
}
inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2)
{ return 0 != pthread_equal(id1, id2); }
inline void thread_yield()
{ ::sched_yield(); }
#ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
typedef struct timespec OS_highres_count_t;
#else
typedef unsigned long long OS_highres_count_t;
#endif
inline unsigned long get_system_tick_ns()
{
#ifdef _SC_CLK_TCK
long ticks_per_second =::sysconf(_SC_CLK_TCK); // ticks per sec
if(ticks_per_second <= 0){ //Try a typical value on error
ticks_per_second = 100;
}
return 999999999ul/static_cast<unsigned long>(ticks_per_second)+1ul;
#else
#error "Can't obtain system tick value for your system, please provide a patch"
#endif
}
inline unsigned long get_system_tick_in_highres_counts()
{
#ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
return get_system_tick_ns();
#else
mach_timebase_info_data_t info;
mach_timebase_info(&info);
//ns
return static_cast<unsigned long>
(
static_cast<double>(get_system_tick_ns())
/ (static_cast<double>(info.numer) / info.denom)
);
#endif
}
//return system ticks in us
inline unsigned long get_system_tick_us()
{
return (get_system_tick_ns()-1)/1000ul + 1ul;
}
inline OS_highres_count_t get_current_system_highres_count()
{
#if defined(BOOST_INTERPROCESS_CLOCK_MONOTONIC)
struct timespec count;
::clock_gettime(BOOST_INTERPROCESS_CLOCK_MONOTONIC, &count);
return count;
#elif defined(BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME)
return ::mach_absolute_time();
#endif
}
#ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
inline void zero_highres_count(OS_highres_count_t &count)
{ count.tv_sec = 0; count.tv_nsec = 0; }
inline bool is_highres_count_zero(const OS_highres_count_t &count)
{ return count.tv_sec == 0 && count.tv_nsec == 0; }
template <class Ostream>
inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count)
{
ostream << count.tv_sec << "s:" << count.tv_nsec << "ns";
return ostream;
}
inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r)
{
OS_highres_count_t res;
if (l.tv_nsec < r.tv_nsec){
res.tv_nsec = 1000000000 + l.tv_nsec - r.tv_nsec;
res.tv_sec = l.tv_sec - 1 - r.tv_sec;
}
else{
res.tv_nsec = l.tv_nsec - r.tv_nsec;
res.tv_sec = l.tv_sec - r.tv_sec;
}
return res;
}
inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r)
{ return l.tv_sec < r.tv_sec || (l.tv_sec == r.tv_sec && l.tv_nsec < r.tv_nsec); }
inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r)
{ return !l.tv_sec && (static_cast<unsigned long>(l.tv_nsec) < r); }
#else
inline void zero_highres_count(OS_highres_count_t &count)
{ count = 0; }
inline bool is_highres_count_zero(const OS_highres_count_t &count)
{ return count == 0; }
template <class Ostream>
inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count)
{
ostream << count ;
return ostream;
}
inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r)
{ return l - r; }
inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r)
{ return l < r; }
inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r)
{ return l < static_cast<OS_highres_count_t>(r); }
#endif
inline void thread_sleep_tick()
{
struct timespec rqt;
//Sleep for the half of the tick time
rqt.tv_sec = 0;
rqt.tv_nsec = get_system_tick_ns()/2;
::nanosleep(&rqt, 0);
}
inline void thread_sleep(unsigned int ms)
{
struct timespec rqt;
rqt.tv_sec = ms/1000u;
rqt.tv_nsec = (ms%1000u)*1000000u;
::nanosleep(&rqt, 0);
}
//systemwide thread
inline OS_systemwide_thread_id_t get_current_systemwide_thread_id()
{
return OS_systemwide_thread_id_t(::getpid(), ::pthread_self());
}
inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2)
{
return (0 != pthread_equal(id1.tid, id2.tid)) && (id1.pid == id2.pid);
}
inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id()
{
return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id());
}
inline long double get_current_process_creation_time()
{ return 0.0L; }
inline unsigned int get_num_cores()
{
#ifdef _SC_NPROCESSORS_ONLN
long cores = ::sysconf(_SC_NPROCESSORS_ONLN);
// sysconf returns -1 if the name is invalid, the option does not exist or
// does not have a definite limit.
// if sysconf returns some other negative number, we have no idea
// what is going on. Default to something safe.
if(cores <= 0){
return 1;
}
//Check for overflow (unlikely)
else if(static_cast<unsigned long>(cores) >=
static_cast<unsigned long>(static_cast<unsigned int>(-1))){
return static_cast<unsigned int>(-1);
}
else{
return static_cast<unsigned int>(cores);
}
#elif defined(BOOST_INTERPROCESS_BSD_DERIVATIVE) && defined(HW_NCPU)
int request[2] = { CTL_HW, HW_NCPU };
int num_cores;
std::size_t result_len = sizeof(num_cores);
if ( (::sysctl (request, 2, &num_cores, &result_len, 0, 0) < 0) || (num_cores <= 0) ){
//Return a safe value
return 1;
}
else{
return static_cast<unsigned int>(num_cores);
}
#elif defined(__VXWORKS__)
cpuset_t set = ::vxCpuEnabledGet();
#ifdef __DCC__
int i;
for( i = 0; set; ++i)
{
set &= set -1;
}
return(i);
#else
return (__builtin_popcount(set) );
#endif
#endif
}
inline int thread_create(OS_thread_t * thread, void *(*start_routine)(void*), void* arg)
{ return pthread_create(thread, 0, start_routine, arg); }
inline void thread_join(OS_thread_t thread)
{ (void)pthread_join(thread, 0); }
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
typedef char pid_str_t[sizeof(OS_process_id_t)*3+1];
inline void get_pid_str(pid_str_t &pid_str, OS_process_id_t pid)
{
bufferstream bstream(pid_str, sizeof(pid_str));
bstream << pid << std::ends;
}
inline void get_pid_str(pid_str_t &pid_str)
{ get_pid_str(pid_str, get_current_process_id()); }
#if defined(BOOST_INTERPROCESS_WINDOWS)
inline int thread_create( OS_thread_t * thread, unsigned (__stdcall * start_routine) (void*), void* arg )
{
void* h = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 );
if( h != 0 ){
thread->m_handle = h;
return 0;
}
else{
return 1;
}
thread->m_handle = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 );
return thread->m_handle != 0;
}
inline void thread_join( OS_thread_t thread)
{
winapi::wait_for_single_object( thread.handle(), winapi::infinite_time );
winapi::close_handle( thread.handle() );
}
#endif
class abstract_thread
{
public:
virtual ~abstract_thread() {}
virtual void run() = 0;
};
template<class T>
class os_thread_func_ptr_deleter
{
public:
explicit os_thread_func_ptr_deleter(T* p)
: m_p(p)
{}
T *release()
{ T *p = m_p; m_p = 0; return p; }
T *get() const
{ return m_p; }
T *operator ->() const
{ return m_p; }
~os_thread_func_ptr_deleter()
{ delete m_p; }
private:
T *m_p;
};
#if defined(BOOST_INTERPROCESS_WINDOWS)
inline unsigned __stdcall launch_thread_routine( void * pv )
{
os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) );
pt->run();
return 0;
}
#else
extern "C" void * launch_thread_routine( void * pv );
inline void * launch_thread_routine( void * pv )
{
os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) );
pt->run();
return 0;
}
#endif
template<class F>
class launch_thread_impl
: public abstract_thread
{
public:
explicit launch_thread_impl( F f )
: f_( f )
{}
void run()
{ f_(); }
private:
F f_;
};
template<class F>
inline int thread_launch( OS_thread_t & pt, F f )
{
os_thread_func_ptr_deleter<abstract_thread> p( new launch_thread_impl<F>( f ) );
int r = thread_create(&pt, launch_thread_routine, p.get());
if( r == 0 ){
p.release();
}
return r;
}
} //namespace ipcdetail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP

View File

@@ -0,0 +1,78 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012.
// (C) Copyright Gennaro Prota 2003 - 2004.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP
#define BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
struct two {char _[2];};
namespace pointer_type_imp {
template <class U> static two test(...);
template <class U> static char test(typename U::pointer* = 0);
} //namespace pointer_type_imp {
template <class T>
struct has_pointer_type
{
static const bool value = sizeof(pointer_type_imp::test<T>(0)) == 1;
};
namespace pointer_type_imp {
template <class T, class D, bool = has_pointer_type<D>::value>
struct pointer_type
{
typedef typename D::pointer type;
};
template <class T, class D>
struct pointer_type<T, D, false>
{
typedef T* type;
};
} //namespace pointer_type_imp {
template <class T, class D>
struct pointer_type
{
typedef typename pointer_type_imp::pointer_type<T,
typename remove_reference<D>::type>::type type;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP

View File

@@ -0,0 +1,361 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_PORTABLE_INTERMODULE_SINGLETON_HPP
#define BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/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/shared_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_shared_dir_and_clean_old(s);
s += "/";
s += subdir_name;
if(!open_or_create_directory(s.c_str())){
error_info err = system_error_code();
throw interprocess_exception(err);
}
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;
get_shared_dir(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_lockfile = 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_lockfile < 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_lockfile);
}
}
//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 = false>
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

View File

@@ -0,0 +1,51 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP
#define BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
//workaround to avoid winsock redefines when using date-time
#ifdef _WIN32
#ifndef 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
#include <boost/date_time/microsec_time_clock.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
namespace boost {
namespace interprocess {
typedef boost::date_time::microsec_clock<boost::posix_time::ptime> microsec_clock;
}
}
#ifdef _WIN32
#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#undef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef _WIN32
#endif //#ifndef BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP

View File

@@ -0,0 +1,41 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-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_PTIME_WRK_HPP
#define BOOST_INTERPROCESS_PTIME_WRK_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
//workaround to avoid winsock redefines when using date-time
#ifdef _WIN32
#ifndef 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
#include <boost/date_time/posix_time/ptime.hpp>
#ifdef _WIN32
#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#undef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef _WIN32
#endif //#ifndef BOOST_INTERPROCESS_PTIME_WRK_HPP

View File

@@ -0,0 +1,385 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2010-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_ROBUST_EMULATION_HPP
#define BOOST_INTERPROCESS_ROBUST_EMULATION_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/shared_dir_helpers.hpp>
#include <boost/interprocess/detail/intermodule_singleton.hpp>
#include <boost/interprocess/detail/portable_intermodule_singleton.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/sync/spin/wait.hpp>
#include <boost/interprocess/sync/detail/common_algorithms.hpp>
#include <string>
namespace boost{
namespace interprocess{
namespace ipcdetail{
namespace robust_emulation_helpers {
template<class T>
class mutex_traits
{
public:
static void take_ownership(T &t)
{ t.take_ownership(); }
};
inline void remove_if_can_lock_file(const char *file_path)
{
file_handle_t fhnd = open_existing_file(file_path, read_write);
if(fhnd != invalid_file()){
bool acquired;
if(try_acquire_file_lock(fhnd, acquired) && acquired){
delete_file(file_path);
}
close_file(fhnd);
}
}
inline const char *robust_lock_subdir_path()
{ return "robust"; }
inline const char *robust_lock_prefix()
{ return "lck"; }
inline void robust_lock_path(std::string &s)
{
get_shared_dir(s);
s += "/";
s += robust_lock_subdir_path();
}
inline void create_and_get_robust_lock_file_path(std::string &s, OS_process_id_t pid)
{
intermodule_singleton_helpers::create_tmp_subdir_and_get_pid_based_filepath
(robust_lock_subdir_path(), robust_lock_prefix(), pid, s);
}
//This class will be a intermodule_singleton. The constructor will create
//a lock file, the destructor will erase it.
//
//We should take in care that another process might be erasing unlocked
//files while creating this one, so there are some race conditions we must
//take in care to guarantee some robustness.
class robust_mutex_lock_file
{
file_handle_t fd;
std::string fname;
public:
robust_mutex_lock_file()
{
permissions p;
p.set_unrestricted();
//Remove old lock files of other processes
remove_old_robust_lock_files();
//Create path and obtain lock file path for this process
create_and_get_robust_lock_file_path(fname, get_current_process_id());
//Now try to open or create the lock file
fd = create_or_open_file(fname.c_str(), read_write, p);
//If we can't open or create it, then something unrecoverable has happened
if(fd == invalid_file()){
throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: could not open or create file");
}
//Now we must take in care a race condition with another process
//calling "remove_old_robust_lock_files()". No other threads from this
//process will be creating the lock file because intermodule_singleton
//guarantees this. So let's loop acquiring the lock and checking if we
//can't exclusively create the file (if the file is erased by another process
//then this exclusive open would fail). If the file can't be exclusively created
//then we have correctly open/create and lock the file. If the file can
//be exclusively created, then close previous locked file and try again.
while(1){
bool acquired;
if(!try_acquire_file_lock(fd, acquired) || !acquired ){
throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: try_acquire_file_lock");
}
//Creating exclusively must fail with already_exists_error
//to make sure we've locked the file and no one has
//deleted it between creation and locking
file_handle_t fd2 = create_new_file(fname.c_str(), read_write, p);
if(fd2 != invalid_file()){
close_file(fd);
fd = fd2;
continue;
}
//If exclusive creation fails with expected error go ahead
else if(error_info(system_error_code()).get_error_code() == already_exists_error){ //must already exist
//Leak descriptor to mantain the file locked until the process dies
break;
}
//If exclusive creation fails with unexpected error throw an unrecoverable error
else{
close_file(fd);
throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: create_file filed with unexpected error");
}
}
}
~robust_mutex_lock_file()
{
//The destructor is guaranteed by intermodule_singleton to be
//executed serialized between all threads from current process,
//so we just need to close and unlink the file.
close_file(fd);
//If some other process deletes the file before us after
//closing it there should not be any problem.
delete_file(fname.c_str());
}
private:
//This functor is execute for all files in the lock file directory
class other_process_lock_remover
{
public:
void operator()(const char *filepath, const char *filename)
{
std::string pid_str;
//If the lock file is not our own lock file, then try to do the cleanup
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);
}
}
};
bool remove_old_robust_lock_files()
{
std::string refcstrRootDirectory;
robust_lock_path(refcstrRootDirectory);
return for_each_file_in_dir(refcstrRootDirectory.c_str(), other_process_lock_remover());
}
};
} //namespace robust_emulation_helpers {
//This is the mutex class. Mutex should follow mutex concept
//with an additonal "take_ownership()" function to take ownership of the
//mutex when robust_spin_mutex determines the previous owner was dead.
template<class Mutex>
class robust_spin_mutex
{
public:
static const boost::uint32_t correct_state = 0;
static const boost::uint32_t fixing_state = 1;
static const boost::uint32_t broken_state = 2;
typedef robust_emulation_helpers::mutex_traits<Mutex> mutex_traits_t;
robust_spin_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
void consistent();
bool previous_owner_dead();
private:
static const unsigned int spin_threshold = 100u;
bool lock_own_unique_file();
bool robust_check();
bool check_if_owner_dead_and_take_ownership_atomically();
bool is_owner_dead(boost::uint32_t own);
void owner_to_filename(boost::uint32_t own, std::string &s);
//The real mutex
Mutex mtx;
//The pid of the owner
volatile boost::uint32_t owner;
//The state of the mutex (correct, fixing, broken)
volatile boost::uint32_t state;
};
template<class Mutex>
inline robust_spin_mutex<Mutex>::robust_spin_mutex()
: mtx(), owner(get_invalid_process_id()), state(correct_state)
{}
template<class Mutex>
inline void robust_spin_mutex<Mutex>::lock()
{ try_based_lock(*this); }
template<class Mutex>
inline bool robust_spin_mutex<Mutex>::try_lock()
{
//Same as lock() but without spinning
if(atomic_read32(&this->state) == broken_state){
throw interprocess_exception(lock_error, "Broken id");
}
if(!this->lock_own_unique_file()){
throw interprocess_exception(lock_error, "Broken id");
}
if (mtx.try_lock()){
atomic_write32(&this->owner, get_current_process_id());
return true;
}
else{
if(!this->robust_check()){
return false;
}
else{
return true;
}
}
}
template<class Mutex>
inline bool robust_spin_mutex<Mutex>::timed_lock
(const boost::posix_time::ptime &abs_time)
{ return try_based_timed_lock(*this, abs_time); }
template<class Mutex>
inline void robust_spin_mutex<Mutex>::owner_to_filename(boost::uint32_t own, std::string &s)
{
robust_emulation_helpers::create_and_get_robust_lock_file_path(s, own);
}
template<class Mutex>
inline bool robust_spin_mutex<Mutex>::robust_check()
{
//If the old owner was dead, and we've acquired ownership, mark
//the mutex as 'fixing'. This means that a "consistent()" is needed
//to avoid marking the mutex as "broken" when the mutex is unlocked.
if(!this->check_if_owner_dead_and_take_ownership_atomically()){
return false;
}
atomic_write32(&this->state, fixing_state);
return true;
}
template<class Mutex>
inline bool robust_spin_mutex<Mutex>::check_if_owner_dead_and_take_ownership_atomically()
{
boost::uint32_t cur_owner = get_current_process_id();
boost::uint32_t old_owner = atomic_read32(&this->owner), old_owner2;
//The cas loop guarantees that only one thread from this or another process
//will succeed taking ownership
do{
//Check if owner is dead
if(!this->is_owner_dead(old_owner)){
return false;
}
//If it's dead, try to mark this process as the owner in the owner field
old_owner2 = old_owner;
old_owner = atomic_cas32(&this->owner, cur_owner, old_owner);
}while(old_owner2 != old_owner);
//If success, we fix mutex internals to assure our ownership
mutex_traits_t::take_ownership(mtx);
return true;
}
template<class Mutex>
inline bool robust_spin_mutex<Mutex>::is_owner_dead(boost::uint32_t own)
{
//If owner is an invalid id, then it's clear it's dead
if(own == (boost::uint32_t)get_invalid_process_id()){
return true;
}
//Obtain the lock filename of the owner field
std::string file;
this->owner_to_filename(own, file);
//Now the logic is to open and lock it
file_handle_t fhnd = open_existing_file(file.c_str(), read_write);
if(fhnd != invalid_file()){
//If we can open the file, lock it.
bool acquired;
if(try_acquire_file_lock(fhnd, acquired) && acquired){
//If locked, just delete the file
delete_file(file.c_str());
close_file(fhnd);
return true;
}
//If not locked, the owner is suppossed to be still alive
close_file(fhnd);
}
else{
//If the lock file does not exist then the owner is dead (a previous cleanup)
//function has deleted the file. If there is another reason, then this is
//an unrecoverable error
if(error_info(system_error_code()).get_error_code() == not_found_error){
return true;
}
}
return false;
}
template<class Mutex>
inline void robust_spin_mutex<Mutex>::consistent()
{
//This function supposes the previous state was "fixing"
//and the current process holds the mutex
if(atomic_read32(&this->state) != fixing_state &&
atomic_read32(&this->owner) != (boost::uint32_t)get_current_process_id()){
throw interprocess_exception(lock_error, "Broken id");
}
//If that's the case, just update mutex state
atomic_write32(&this->state, correct_state);
}
template<class Mutex>
inline bool robust_spin_mutex<Mutex>::previous_owner_dead()
{
//Notifies if a owner recovery has been performed in the last lock()
return atomic_read32(&this->state) == fixing_state;
}
template<class Mutex>
inline void robust_spin_mutex<Mutex>::unlock()
{
//If in "fixing" state, unlock and mark the mutex as unrecoverable
//so next locks will fail and all threads will be notified that the
//data protected by the mutex was not recoverable.
if(atomic_read32(&this->state) == fixing_state){
atomic_write32(&this->state, broken_state);
}
//Write an invalid owner to minimize pid reuse possibility
atomic_write32(&this->owner, get_invalid_process_id());
mtx.unlock();
}
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 =
&ipcdetail::intermodule_singleton
<robust_emulation_helpers::robust_mutex_lock_file>::get();
return dummy != 0;
}
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#include <boost/interprocess/detail/config_end.hpp>
#endif

View File

@@ -0,0 +1,518 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
#define BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
// interprocess
#include <boost/interprocess/exceptions.hpp>
// interprocess/detail
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/in_place_interface.hpp>
// container/detail
#include <boost/container/detail/type_traits.hpp> //alignment_of
#include <boost/container/detail/minimal_char_traits_header.hpp>
// intrusive
#include <boost/intrusive/pointer_traits.hpp>
// move/detail
#include <boost/move/detail/type_traits.hpp> //make_unsigned
// other boost
#include <boost/assert.hpp> //BOOST_ASSERT
#include <boost/core/no_exceptions_support.hpp>
// std
#include <cstddef> //std::size_t
//!\file
//!Describes the object placed in a memory segment that provides
//!named object allocation capabilities.
namespace boost{
namespace interprocess{
template<class MemoryManager>
class segment_manager_base;
//!An integer that describes the type of the
//!instance constructed in memory
enum instance_type { anonymous_type, named_type, unique_type, max_allocation_type };
namespace ipcdetail{
template<class MemoryAlgorithm>
class mem_algo_deallocator
{
void * m_ptr;
MemoryAlgorithm & m_algo;
public:
mem_algo_deallocator(void *ptr, MemoryAlgorithm &algo)
: m_ptr(ptr), m_algo(algo)
{}
void release()
{ m_ptr = 0; }
~mem_algo_deallocator()
{ if(m_ptr) m_algo.deallocate(m_ptr); }
};
template<class size_type>
struct block_header
{
size_type m_value_bytes;
unsigned short m_num_char;
unsigned char m_value_alignment;
unsigned char m_alloc_type_sizeof_char;
block_header(size_type val_bytes
,size_type val_alignment
,unsigned char al_type
,std::size_t szof_char
,std::size_t num_char
)
: m_value_bytes(val_bytes)
, m_num_char((unsigned short)num_char)
, m_value_alignment((unsigned char)val_alignment)
, m_alloc_type_sizeof_char( (al_type << 5u) | ((unsigned char)szof_char & 0x1F) )
{};
template<class T>
block_header &operator= (const T& )
{ return *this; }
size_type total_size() const
{
if(alloc_type() != anonymous_type){
return name_offset() + (m_num_char+1)*sizeof_char();
}
else{
return this->value_offset() + m_value_bytes;
}
}
size_type value_bytes() const
{ return m_value_bytes; }
template<class Header>
size_type total_size_with_header() const
{
return get_rounded_size
( size_type(sizeof(Header))
, size_type(::boost::container::dtl::alignment_of<block_header<size_type> >::value))
+ total_size();
}
unsigned char alloc_type() const
{ return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; }
unsigned char sizeof_char() const
{ return m_alloc_type_sizeof_char & (unsigned char)0x1F; }
template<class CharType>
CharType *name() const
{
return const_cast<CharType*>(reinterpret_cast<const CharType*>
(reinterpret_cast<const char*>(this) + name_offset()));
}
unsigned short name_length() const
{ 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()));
}
void *value() const
{
return const_cast<char*>((reinterpret_cast<const char*>(this) + this->value_offset()));
}
size_type value_offset() const
{
return get_rounded_size(size_type(sizeof(block_header<size_type>)), size_type(m_value_alignment));
}
template<class CharType>
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 &&
std::char_traits<CharType>::compare(name<CharType>(), b.name<CharType>(), m_num_char) < 0);
}
template<class CharType>
bool equal_comp(const block_header<size_type> &b) const
{
return m_num_char == b.m_num_char &&
std::char_traits<CharType>::compare(name<CharType>(), b.name<CharType>(), m_num_char) == 0;
}
template<class T>
static block_header<size_type> *block_header_from_value(T *value)
{ return block_header_from_value(value, sizeof(T), ::boost::container::dtl::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 =
const_cast<block_header*>
(reinterpret_cast<const block_header*>(reinterpret_cast<const char*>(value) -
get_rounded_size(sizeof(block_header), algn)));
(void)sz;
//Some sanity checks
BOOST_ASSERT(hdr->m_value_alignment == algn);
BOOST_ASSERT(hdr->m_value_bytes % sz == 0);
return hdr;
}
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) +
get_rounded_size( size_type(sizeof(Header))
, size_type(::boost::container::dtl::alignment_of<block_header<size_type> >::value)));
//Some sanity checks
return hdr;
}
template<class Header>
static Header *to_first_header(block_header<size_type> *bheader)
{
Header * hdr =
reinterpret_cast<Header*>(reinterpret_cast<char*>(bheader) -
get_rounded_size( size_type(sizeof(Header))
, size_type(::boost::container::dtl::alignment_of<block_header<size_type> >::value)));
//Some sanity checks
return hdr;
}
};
inline void array_construct(void *mem, std::size_t num, in_place_interface &table)
{
//Try constructors
std::size_t constructed = 0;
BOOST_TRY{
table.construct_n(mem, num, constructed);
}
//If there is an exception call destructors and erase index node
BOOST_CATCH(...){
std::size_t destroyed = 0;
table.destroy_n(mem, constructed, destroyed);
BOOST_RETHROW
}
BOOST_CATCH_END
}
template<class CharT>
struct intrusive_compare_key
{
typedef CharT char_type;
intrusive_compare_key(const CharT *str, std::size_t len)
: mp_str(str), m_len(len)
{}
const CharT * mp_str;
std::size_t m_len;
};
//!This struct indicates an anonymous object creation
//!allocation
template<instance_type type>
class instance_t
{
instance_t(){}
};
template<class T>
struct char_if_void
{
typedef T type;
};
template<>
struct char_if_void<void>
{
typedef char type;
};
typedef instance_t<anonymous_type> anonymous_instance_t;
typedef instance_t<unique_type> unique_instance_t;
template<class Hook, class CharType, class SizeType>
struct intrusive_value_type_impl
: public Hook
{
private:
//Non-copyable
intrusive_value_type_impl(const intrusive_value_type_impl &);
intrusive_value_type_impl& operator=(const intrusive_value_type_impl &);
public:
typedef CharType char_type;
typedef SizeType size_type;
intrusive_value_type_impl(){}
enum { BlockHdrAlignment = ::boost::container::dtl::alignment_of<block_header<size_type> >::value };
block_header<size_type> *get_block_header() const
{
return const_cast<block_header<size_type>*>
(reinterpret_cast<const block_header<size_type> *>(reinterpret_cast<const char*>(this) +
get_rounded_size(size_type(sizeof(*this)), size_type(BlockHdrAlignment))));
}
bool operator <(const intrusive_value_type_impl<Hook, CharType, SizeType> & other) const
{ return (this->get_block_header())->template less_comp<CharType>(*other.get_block_header()); }
bool operator ==(const intrusive_value_type_impl<Hook, CharType, SizeType> & other) const
{ return (this->get_block_header())->template equal_comp<CharType>(*other.get_block_header()); }
static intrusive_value_type_impl *get_intrusive_value_type(block_header<size_type> *hdr)
{
return reinterpret_cast<intrusive_value_type_impl *>(reinterpret_cast<char*>(hdr) -
get_rounded_size(size_type(sizeof(intrusive_value_type_impl)), size_type(BlockHdrAlignment)));
}
CharType *name() const
{ return get_block_header()->template name<CharType>(); }
unsigned short name_length() const
{ return get_block_header()->name_length(); }
void *value() const
{ return get_block_header()->value(); }
};
template<class CharType>
class char_ptr_holder
{
public:
char_ptr_holder(const CharType *name)
: m_name(name)
{}
char_ptr_holder(const anonymous_instance_t *)
: m_name(static_cast<CharType*>(0))
{}
char_ptr_holder(const unique_instance_t *)
: m_name(reinterpret_cast<CharType*>(-1))
{}
operator const CharType *()
{ return m_name; }
const CharType *get() const
{ return m_name; }
bool is_unique() const
{ return m_name == reinterpret_cast<CharType*>(-1); }
bool is_anonymous() const
{ return m_name == static_cast<CharType*>(0); }
private:
const CharType *m_name;
};
//!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
{
typedef typename boost::intrusive::
pointer_traits<VoidPointer>::template
rebind_pointer<const CharT>::type const_char_ptr_t;
typedef CharT char_type;
typedef typename boost::intrusive::pointer_traits<const_char_ptr_t>::difference_type difference_type;
typedef typename boost::move_detail::make_unsigned<difference_type>::type size_type;
private:
//Offset pointer to the object's name
const_char_ptr_t mp_str;
//Length of the name buffer (null NOT included)
size_type m_len;
public:
//!Constructor of the key
index_key (const char_type *nm, size_type length)
: mp_str(nm), m_len(length)
{}
//!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
(to_raw_pointer(mp_str),to_raw_pointer(right.mp_str), m_len) < 0);
}
//!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
(to_raw_pointer(mp_str), to_raw_pointer(right.mp_str), m_len) == 0;
}
void name(const CharT *nm)
{ mp_str = nm; }
void name_length(size_type len)
{ m_len = len; }
const CharT *name() const
{ return to_raw_pointer(mp_str); }
size_type name_length() const
{ return m_len; }
};
//!The index_data stores a pointer to a buffer and the element count needed
//!to know how many destructors must be called when calling destroy
template<class VoidPointer>
struct index_data
{
typedef VoidPointer void_pointer;
void_pointer m_ptr;
explicit index_data(void *ptr) : m_ptr(ptr){}
void *value() const
{ return static_cast<void*>(to_raw_pointer(m_ptr)); }
};
template<class MemoryAlgorithm>
struct segment_manager_base_type
{ typedef segment_manager_base<MemoryAlgorithm> type; };
template<class CharT, class MemoryAlgorithm>
struct index_config
{
typedef typename MemoryAlgorithm::void_pointer void_pointer;
typedef CharT char_type;
typedef index_key<CharT, void_pointer> key_type;
typedef index_data<void_pointer> mapped_type;
typedef typename segment_manager_base_type
<MemoryAlgorithm>::type segment_manager_base;
template<class HeaderBase>
struct intrusive_value_type
{ typedef intrusive_value_type_impl<HeaderBase, CharT, typename segment_manager_base::size_type> type; };
typedef intrusive_compare_key<CharT> intrusive_compare_key_type;
};
template<class Iterator, bool intrusive>
class segment_manager_iterator_value_adaptor
{
typedef typename Iterator::value_type iterator_val_t;
typedef typename iterator_val_t::char_type char_type;
public:
segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val)
: m_val(&val)
{}
const char_type *name() const
{ return m_val->name(); }
unsigned short name_length() const
{ return m_val->name_length(); }
const void *value() const
{ return m_val->value(); }
const typename Iterator::value_type *m_val;
};
template<class Iterator>
class segment_manager_iterator_value_adaptor<Iterator, false>
{
typedef typename Iterator::value_type iterator_val_t;
typedef typename iterator_val_t::first_type first_type;
typedef typename iterator_val_t::second_type second_type;
typedef typename first_type::char_type char_type;
typedef typename first_type::size_type size_type;
public:
segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val)
: m_val(&val)
{}
const char_type *name() const
{ return m_val->first.name(); }
size_type name_length() const
{ return m_val->first.name_length(); }
const void *value() const
{
return reinterpret_cast<block_header<size_type>*>
(to_raw_pointer(m_val->second.m_ptr))->value();
}
const typename Iterator::value_type *m_val;
};
template<class Iterator, bool intrusive>
struct segment_manager_iterator_transform
{
typedef segment_manager_iterator_value_adaptor<Iterator, intrusive> result_type;
template <class T> result_type operator()(const T &arg) const
{ return result_type(arg); }
};
} //namespace ipcdetail {
//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;
namespace ipcdetail_really_deep_namespace {
//Otherwise, gcc issues a warning of previously defined
//anonymous_instance and unique_instance
struct dummy
{
dummy()
{
(void)anonymous_instance;
(void)unique_instance;
}
};
} //detail_really_deep_namespace
}} //namespace boost { namespace interprocess
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP

View File

@@ -0,0 +1,212 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2014. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_SHARED_DIR_HELPERS_HPP
#define BOOST_INTERPROCESS_DETAIL_SHARED_DIR_HELPERS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <string>
#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_KERNEL_BOOTTIME)
#if defined(BOOST_INTERPROCESS_WINDOWS)
//This type will initialize the stamp
struct windows_bootstamp
{
windows_bootstamp()
{
//Throw if bootstamp not available
if(!winapi::get_last_bootup_time(stamp)){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
//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;
}
}
#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, 0, 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_shared_dir_root(std::string &dir_path)
{
#if defined (BOOST_INTERPROCESS_WINDOWS)
winapi::get_shared_documents_folder(dir_path);
#else
dir_path = "/tmp";
#endif
//We always need this path, so throw on error
if(dir_path.empty()){
error_info err = system_error_code();
throw interprocess_exception(err);
}
//Remove final null.
dir_path += "/boost_interprocess";
}
#if defined(BOOST_INTERPROCESS_SHARED_DIR_FUNC) && defined(BOOST_INTERPROCESS_SHARED_DIR_PATH)
#error "Error: Both BOOST_INTERPROCESS_SHARED_DIR_FUNC and BOOST_INTERPROCESS_SHARED_DIR_PATH defined!"
#endif
#ifdef BOOST_INTERPROCESS_SHARED_DIR_FUNC
// When BOOST_INTERPROCESS_SHARED_DIR_FUNC is defined, users have to implement
// get_shared_dir
void get_shared_dir(std::string &shared_dir);
#else
inline void get_shared_dir(std::string &shared_dir)
{
#if defined(BOOST_INTERPROCESS_SHARED_DIR_PATH)
shared_dir = BOOST_INTERPROCESS_SHARED_DIR_PATH;
#else
get_shared_dir_root(shared_dir);
#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME)
shared_dir += "/";
get_bootstamp(shared_dir, true);
#endif
#endif
}
#endif
inline void shared_filepath(const char *filename, std::string &filepath)
{
get_shared_dir(filepath);
filepath += "/";
filepath += filename;
}
inline void create_shared_dir_and_clean_old(std::string &shared_dir)
{
#if defined(BOOST_INTERPROCESS_SHARED_DIR_PATH) || defined(BOOST_INTERPROCESS_SHARED_DIR_FUNC)
get_shared_dir(shared_dir);
#else
//First get the temp directory
std::string root_shared_dir;
get_shared_dir_root(root_shared_dir);
//If fails, check that it's because already exists
if(!create_directory(root_shared_dir.c_str())){
error_info info(system_error_code());
if(info.get_error_code() != already_exists_error){
throw interprocess_exception(info);
}
}
#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME)
get_shared_dir(shared_dir);
//If fails, check that it's because already exists
if(!create_directory(shared_dir.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 = shared_dir;
subdir.erase(0, root_shared_dir.size()+1);
delete_subdirectories(root_shared_dir, subdir.c_str());
#else
shared_dir = root_shared_dir;
#endif
#endif
}
inline void create_shared_dir_cleaning_old_and_get_filepath(const char *filename, std::string &shared_dir)
{
create_shared_dir_and_clean_old(shared_dir);
shared_dir += "/";
shared_dir += filename;
}
inline void add_leading_slash(const char *name, std::string &new_name)
{
if(name[0] != '/'){
new_name = '/';
}
new_name += name;
}
} //namespace boost{
} //namespace interprocess {
} //namespace ipcdetail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //ifndef BOOST_INTERPROCESS_DETAIL_SHARED_DIR_HELPERS_HPP

View File

@@ -0,0 +1,29 @@
#ifndef BOOST_INTERPROCESS_DETAIL_SWAP_HPP
#define BOOST_INTERPROCESS_DETAIL_SWAP_HPP
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2014-2015. 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_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost { namespace interprocess {
template<class T>
void simple_swap(T&x, T&y)
{ T tmp(x); x = y; y = tmp; }
}} //namespace boost{ namespace interprocess {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_SWAP_HPP

View File

@@ -0,0 +1,57 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2014-2015. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_STD_FWD_HPP
#define BOOST_INTERPROCESS_DETAIL_STD_FWD_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
//////////////////////////////////////////////////////////////////////////////
// Standard predeclarations
//////////////////////////////////////////////////////////////////////////////
#include <boost/move/detail/std_ns_begin.hpp>
BOOST_MOVE_STD_NS_BEG
struct input_iterator_tag;
struct forward_iterator_tag;
struct bidirectional_iterator_tag;
struct random_access_iterator_tag;
template<class T>
struct char_traits;
#if defined(BOOST_MSVC) && (BOOST_MSVC >= 1800) &&defined(BOOST_DINKUMWARE_STDLIB)
#define BOOST_INTERPROCESS_STD_FWD_MSVC_IOS_BUG
// Compiler bug workaround. Previous versions (<= VC11)
// used dummy virtual functions
# pragma vtordisp(push, 2)
#endif
template<class CharT, class Traits>
class basic_ostream;
template<class CharT, class Traits>
class basic_istream;
#ifdef BOOST_INTERPROCESS_STD_FWD_MSVC_IOS_BUG
# pragma vtordisp(pop)
# undef BOOST_INTERPROCESS_STD_FWD_MSVC_IOS_BUG
#endif
BOOST_MOVE_STD_NS_END
#include <boost/move/detail/std_ns_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_STD_FWD_HPP

View File

@@ -0,0 +1,44 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2015.
// (C) Copyright Gennaro Prota 2003 - 2004.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP
#define BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
// interprocess
#include <boost/interprocess/interprocess_fwd.hpp>
// container/detail
#include <boost/container/detail/transform_iterator.hpp>
namespace boost {
namespace interprocess {
using boost::container::make_transform_iterator;
using boost::container::transform_iterator;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP

View File

@@ -0,0 +1,162 @@
//////////////////////////////////////////////////////////////////////////////
// (C) Copyright John Maddock 2000.
// (C) Copyright Ion Gaztanaga 2005-2012.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP
#define BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
struct nat{};
template<class T>
struct remove_reference
{
typedef T type;
};
template<class T>
struct remove_reference<T&>
{
typedef T type;
};
template<class T>
struct is_reference
{
static const bool value = false;
};
template<class T>
struct is_reference<T&>
{
static const bool value = true;
};
template<class T>
struct is_pointer
{
static const bool value = false;
};
template<class T>
struct is_pointer<T*>
{
static const bool value = true;
};
template <typename T>
struct add_reference
{
typedef T& type;
};
template<class T>
struct add_reference<T&>
{
typedef T& type;
};
template<>
struct add_reference<void>
{
typedef nat &type;
};
template<>
struct add_reference<const void>
{
typedef const nat &type;
};
template <class T>
struct add_const_reference
{ typedef const T &type; };
template <class T>
struct add_const_reference<T&>
{ typedef T& type; };
template<class T>
struct remove_const
{
typedef T type;
};
template<class T>
struct remove_const<const T>
{
typedef T type;
};
template<class T>
struct remove_volatile
{
typedef T type;
};
template<class T>
struct remove_volatile<volatile T>
{
typedef T type;
};
template<class T>
struct remove_const_volatile
{
typedef typename remove_const<typename remove_volatile<T>::type>::type type;
};
template <typename T, typename U>
struct is_same
{
typedef char yes_type;
struct no_type
{
char padding[8];
};
template <typename V>
static yes_type is_same_tester(V*, V*);
static no_type is_same_tester(...);
static T *t;
static U *u;
static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u));
};
template<class T, class U>
struct is_cv_same
{
static const bool value = is_same< typename remove_const_volatile<T>::type
, typename remove_const_volatile<U>::type >::value;
};
} // namespace ipcdetail
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP

View File

@@ -0,0 +1,213 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2015.
// (C) Copyright Gennaro Prota 2003 - 2004.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP
#define BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/detail/min_max.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/intrusive/pointer_traits.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/static_assert.hpp>
#include <boost/cstdint.hpp>
#include <climits>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template <class T>
inline T* to_raw_pointer(T* p)
{ return p; }
template <class Pointer>
inline typename boost::intrusive::pointer_traits<Pointer>::element_type*
to_raw_pointer(const Pointer &p)
{ return boost::interprocess::ipcdetail::to_raw_pointer(p.operator->()); }
//Rounds "orig_size" by excess to round_to bytes
template<class SizeType>
inline SizeType get_rounded_size(SizeType orig_size, SizeType round_to)
{
return ((orig_size-1)/round_to+1)*round_to;
}
//Truncates "orig_size" to a multiple of "multiple" bytes.
template<class SizeType>
inline SizeType get_truncated_size(SizeType orig_size, SizeType multiple)
{
return orig_size/multiple*multiple;
}
//Rounds "orig_size" by excess to round_to bytes. round_to must be power of two
template<class SizeType>
inline SizeType get_rounded_size_po2(SizeType orig_size, SizeType round_to)
{
return ((orig_size-1)&(~(round_to-1))) + round_to;
}
//Truncates "orig_size" to a multiple of "multiple" bytes. multiple must be power of two
template<class SizeType>
inline SizeType get_truncated_size_po2(SizeType orig_size, SizeType multiple)
{
return (orig_size & (~(multiple-1)));
}
template <std::size_t OrigSize, std::size_t RoundTo>
struct ct_rounded_size
{
BOOST_STATIC_ASSERT((RoundTo != 0));
static const std::size_t intermediate_value = (OrigSize-1)/RoundTo+1;
BOOST_STATIC_ASSERT(intermediate_value <= std::size_t(-1)/RoundTo);
static const std::size_t value = intermediate_value*RoundTo;
};
// Gennaro Prota wrote this. Thanks!
template <int p, int n = 4>
struct ct_max_pow2_less
{
static const std::size_t c = 2*n < p;
static const std::size_t value =
c ? (ct_max_pow2_less< c*p, 2*c*n>::value) : n;
};
template <>
struct ct_max_pow2_less<0, 0>
{
static const std::size_t value = 0;
};
} //namespace ipcdetail {
//!Trait class to detect if an index is a node
//!index. This allows more efficient operations
//!when deallocating named objects.
template <class Index>
struct is_node_index
{
static const bool value = false;
};
//!Trait class to detect if an index is an intrusive
//!index. This will embed the derivation hook in each
//!allocation header, to provide memory for the intrusive
//!container.
template <class Index>
struct is_intrusive_index
{
static const bool value = false;
};
template <typename T>
BOOST_INTERPROCESS_FORCEINLINE T* addressof(T& v)
{
return reinterpret_cast<T*>(
&const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
}
template<class SizeType>
struct sqrt_size_type_max
{
static const SizeType value = (SizeType(1) << (sizeof(SizeType)*(CHAR_BIT/2)))-1;
};
template<class SizeType>
inline bool multiplication_overflows(SizeType a, SizeType b)
{
const SizeType sqrt_size_max = sqrt_size_type_max<SizeType>::value;
return //Fast runtime check
( (a | b) > sqrt_size_max &&
//Slow division check
b && a > SizeType(-1)/b
);
}
template<std::size_t SztSizeOfType, class SizeType>
BOOST_INTERPROCESS_FORCEINLINE bool size_overflows(SizeType count)
{
//Compile time-check
BOOST_STATIC_ASSERT(SztSizeOfType <= SizeType(-1));
//Runtime check
return multiplication_overflows(SizeType(SztSizeOfType), count);
}
template<class RawPointer, class OffsetType>
class pointer_offset_caster;
template<class T, class OffsetType>
class pointer_offset_caster<T*, OffsetType>
{
public:
BOOST_INTERPROCESS_FORCEINLINE explicit pointer_offset_caster(OffsetType offset)
: m_offset(offset)
{}
BOOST_INTERPROCESS_FORCEINLINE explicit pointer_offset_caster(const volatile T *p)
: m_offset(reinterpret_cast<OffsetType>(p))
{}
BOOST_INTERPROCESS_FORCEINLINE OffsetType offset() const
{ return m_offset; }
BOOST_INTERPROCESS_FORCEINLINE T* pointer() const
{ return reinterpret_cast<T*>(m_offset); }
private:
OffsetType m_offset;
};
template<class SizeType>
inline bool sum_overflows(SizeType a, SizeType b)
{ return SizeType(-1) - a < b; }
//Anti-exception node eraser
template<class Cont>
class value_eraser
{
public:
value_eraser(Cont & cont, typename Cont::iterator it)
: m_cont(cont), m_index_it(it), m_erase(true){}
~value_eraser()
{ if(m_erase) m_cont.erase(m_index_it); }
BOOST_INTERPROCESS_FORCEINLINE void release() { m_erase = false; }
private:
Cont &m_cont;
typename Cont::iterator m_index_it;
bool m_erase;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP

View File

@@ -0,0 +1,35 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP
#define BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/container/detail/variadic_templates_tools.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
using boost::container::dtl::tuple;
using boost::container::dtl::build_number_seq;
using boost::container::dtl::index_tuple;
using boost::container::dtl::get;
}}} //namespace boost { namespace interprocess { namespace ipcdetail {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,314 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_WINDOWS_INTERMODULE_SINGLETON_HPP
#define BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/container/string.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 <boost/container/map.hpp>
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 boost::container::map<boost::container::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){
delete m;
//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(boost::container::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(boost::container::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(boost::container::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()){
map_type &map = this->get_map_unlocked();
BOOST_ASSERT(map.empty());
delete &map;
}
//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 = false>
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

View File

@@ -0,0 +1,201 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP
#define BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#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>
//////////////////////////////////////////////////////
//Check for XSI shared memory objects. They are available in nearly all UNIX platforms
//////////////////////////////////////////////////////
#if !defined(__QNXNTO__) && !defined(__ANDROID__) && !defined(__HAIKU__) && !(__VXWORKS__)
#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
#endif
//////////////////////////////////////////////////////
// From SUSv3/UNIX 98, pthread_mutexattr_settype is mandatory
//////////////////////////////////////////////////////
#if defined(_XOPEN_UNIX) && ((_XOPEN_VERSION + 0) >= 500)
#define BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES
#endif
//////////////////////////////////////////////////////
// _POSIX_THREAD_PROCESS_SHARED (POSIX.1b/POSIX.4)
//////////////////////////////////////////////////////
#if defined(_POSIX_THREAD_PROCESS_SHARED) && ((_POSIX_THREAD_PROCESS_SHARED + 0) > 0)
//Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it.
#if defined(__CYGWIN__)
#define BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED
#elif defined(__APPLE__)
//The pthreads implementation of darwin stores a pointer to a mutex inside the condition
//structure so real sharing between processes is broken. See:
//https://opensource.apple.com/source/libpthread/libpthread-301.30.1/src/pthread_cond.c.auto.html
//in method pthread_cond_wait
#define BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED
#endif
//If buggy _POSIX_THREAD_PROCESS_SHARED is detected avoid using it
#if defined(BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED)
#undef BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED
#else
#define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED
#endif
#endif
//////////////////////////////////////////////////////
// _POSIX_SHARED_MEMORY_OBJECTS (POSIX.1b/POSIX.4)
//////////////////////////////////////////////////////
#if ( defined(_POSIX_SHARED_MEMORY_OBJECTS) && ((_POSIX_SHARED_MEMORY_OBJECTS + 0) > 0) ) ||\
(defined(__vms) && __CRTL_VER >= 70200000)
#define 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
//Some systems have "jailed" environments where shm usage is restricted at runtime
//and temporary file based shm is possible in those executions.
#elif defined(__FreeBSD__)
#define BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
#endif
#endif
//////////////////////////////////////////////////////
// _POSIX_MAPPED_FILES (POSIX.1b/POSIX.4)
//////////////////////////////////////////////////////
#if defined(_POSIX_MAPPED_FILES) && ((_POSIX_MAPPED_FILES + 0) > 0)
#define BOOST_INTERPROCESS_POSIX_MAPPED_FILES
#endif
//////////////////////////////////////////////////////
// _POSIX_SEMAPHORES (POSIX.1b/POSIX.4)
//////////////////////////////////////////////////////
#if ( defined(_POSIX_SEMAPHORES) && ((_POSIX_SEMAPHORES + 0) > 0) ) ||\
( defined(__FreeBSD__) && (__FreeBSD__ >= 4)) || \
defined(__APPLE__)
#define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
//MacOsX declares _POSIX_SEMAPHORES but sem_init returns ENOSYS
#if !defined(__APPLE__)
#define BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES
#endif
#if defined(__osf__) || defined(__vms)
#define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
#endif
#endif
//////////////////////////////////////////////////////
// _POSIX_BARRIERS (SUSv3/Unix03)
//////////////////////////////////////////////////////
#if defined(_POSIX_BARRIERS) && ((_POSIX_BARRIERS + 0) >= 200112L)
#define BOOST_INTERPROCESS_POSIX_BARRIERS
#endif
//////////////////////////////////////////////////////
// _POSIX_TIMEOUTS (SUSv3/Unix03)
//////////////////////////////////////////////////////
#if defined(_POSIX_TIMEOUTS) && ((_POSIX_TIMEOUTS + 0L) >= 200112L)
#define BOOST_INTERPROCESS_POSIX_TIMEOUTS
#endif
//////////////////////////////////////////////////////
// Detect BSD derivatives to detect sysctl
//////////////////////////////////////////////////////
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
#define BOOST_INTERPROCESS_BSD_DERIVATIVE
//Some *BSD systems (OpenBSD & NetBSD) need sys/param.h before sys/sysctl.h, whereas
//others (FreeBSD & Darwin) need sys/types.h
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#if defined(CTL_KERN) && defined (KERN_BOOTTIME)
//#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
#endif
#endif
//////////////////////////////////////////////////////
//64 bit offset
//////////////////////////////////////////////////////
#if (defined (_V6_ILP32_OFFBIG) &&(_V6_ILP32_OFFBIG - 0 > 0)) ||\
(defined (_V6_LP64_OFF64) &&(_V6_LP64_OFF64 - 0 > 0)) ||\
(defined (_V6_LPBIG_OFFBIG) &&(_V6_LPBIG_OFFBIG - 0 > 0)) ||\
(defined (_XBS5_ILP32_OFFBIG)&&(_XBS5_ILP32_OFFBIG - 0 > 0)) ||\
(defined (_XBS5_LP64_OFF64) &&(_XBS5_LP64_OFF64 - 0 > 0)) ||\
(defined (_XBS5_LPBIG_OFFBIG)&&(_XBS5_LPBIG_OFFBIG - 0 > 0)) ||\
(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
#endif
#endif //!defined(BOOST_INTERPROCESS_WINDOWS)
#if defined(BOOST_INTERPROCESS_WINDOWS) || defined(BOOST_INTERPROCESS_POSIX_MAPPED_FILES)
# define BOOST_INTERPROCESS_MAPPED_FILES
#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
#define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES
#endif
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#define BOOST_INTERPROCESS_PERFECT_FORWARDING
#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
#endif
//Other switches
//BOOST_INTERPROCESS_MSG_QUEUE_USES_CIRC_INDEX
//message queue uses a circular queue as index instead of an array (better performance)
//Boost version < 1.52 uses an array, so undef this if you want to communicate
//with processes compiled with those versions.
#define BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX
//Macros for documentation purposes. For code, expands to the argument
#define BOOST_INTERPROCESS_IMPDEF(TYPE) TYPE
#define BOOST_INTERPROCESS_SEEDOC(TYPE) TYPE
#define BOOST_INTERPROCESS_DOC1ST(TYPE1, TYPE2) TYPE2
#define BOOST_INTERPROCESS_I ,
#define BOOST_INTERPROCESS_DOCIGN(T1) T1
//#define BOOST_INTERPROCESS_DISABLE_FORCEINLINE
#if defined(BOOST_INTERPROCESS_DISABLE_FORCEINLINE)
#define BOOST_INTERPROCESS_FORCEINLINE inline
#elif defined(BOOST_INTERPROCESS_FORCEINLINE_IS_BOOST_FORCELINE)
#define BOOST_INTERPROCESS_FORCEINLINE BOOST_FORCEINLINE
#elif defined(BOOST_MSVC) && defined(_DEBUG)
//"__forceinline" and MSVC seems to have some bugs in debug mode
#define BOOST_INTERPROCESS_FORCEINLINE inline
#elif defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ < 5)))
//Older GCCs have problems with forceinline
#define BOOST_INTERPROCESS_FORCEINLINE inline
#else
#define BOOST_INTERPROCESS_FORCEINLINE BOOST_FORCEINLINE
#endif
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP

View File

@@ -0,0 +1,88 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP
#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/detail/workaround.hpp>
#if !defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS)
#error "This header can't be used in operating systems without XSI (System V) shared memory support"
#endif
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/shared_dir_helpers.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/xsi_shared_memory.hpp>
//!\file
//!Describes a class representing a pseudo-file implemented on top of xsi shared memory.
namespace boost {
namespace interprocess {
class xsi_shared_memory_file_wrapper
: public xsi_shared_memory
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper)
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
xsi_shared_memory_file_wrapper() : xsi_shared_memory() {}
xsi_shared_memory_file_wrapper(create_only_t, const xsi_key &key, mode_t , std::size_t size, const permissions& perm = permissions())
: xsi_shared_memory(create_only_t(), key, size, perm.get_permissions())
{}
xsi_shared_memory_file_wrapper(open_or_create_t, const xsi_key &key, mode_t , std::size_t size, const permissions& perm = permissions())
: xsi_shared_memory(open_or_create_t(), key, size, perm.get_permissions())
{}
xsi_shared_memory_file_wrapper(open_only_t, const xsi_key &key, mode_t, const permissions& = permissions())
: xsi_shared_memory(open_only_t(), key)
{}
xsi_shared_memory_file_wrapper(BOOST_RV_REF(xsi_shared_memory_file_wrapper) moved)
{ 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;
}
//!Swaps two xsi_shared_memory_file_wrapper. Does not throw
void swap(xsi_shared_memory_file_wrapper &other)
{ this->xsi_shared_memory::swap(other); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP