Squashed 'boost/' content from commit b4feb19f2

git-subtree-dir: boost
git-subtree-split: b4feb19f287ee92d87a9624b5d36b7cf46aeadeb
This commit is contained in:
Bill Somerville
2018-06-09 21:48:32 +01:00
commit 4ebe6417a5
12444 changed files with 2327021 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_CREATION_TAGS_HPP
#define BOOST_INTERPROCESS_CREATION_TAGS_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 {
//!Tag to indicate that the resource must
//!be only created
struct create_only_t {};
//!Tag to indicate that the resource must
//!be only opened
struct open_only_t {};
//!Tag to indicate that the resource must
//!be only opened for reading
struct open_read_only_t {};
//!Tag to indicate that the resource must
//!be only opened privately for reading
struct open_read_private_t {};
//!Tag to indicate that the resource must
//!be only opened for reading
struct open_copy_on_write_t {};
//!Tag to indicate that the resource must
//!be created. If already created, it must be opened.
struct open_or_create_t {};
//!Value to indicate that the resource must
//!be only created
static const create_only_t create_only = create_only_t();
//!Value to indicate that the resource must
//!be only opened
static const open_only_t open_only = open_only_t();
//!Value to indicate that the resource must
//!be only opened for reading
static const open_read_only_t open_read_only = open_read_only_t();
//!Value to indicate that the resource must
//!be created. If already created, it must be opened.
static const open_or_create_t open_or_create = open_or_create_t();
//!Value to indicate that the resource must
//!be only opened for reading
static const open_copy_on_write_t open_copy_on_write = open_copy_on_write_t();
namespace ipcdetail {
enum create_enum_t
{ DoCreate, DoOpen, DoOpenOrCreate };
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CREATION_TAGS_HPP
+601
View File
@@ -0,0 +1,601 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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{
#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
@@ -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
+16
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
@@ -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
@@ -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
@@ -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::container_detail::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
@@ -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
@@ -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::container_detail::alignment_of
< ::boost::container::container_detail::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
+44
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
+122
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
@@ -0,0 +1,739 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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 <string>
#include <limits>
#include <climits>
#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 <errno.h>
# include <cstdio>
# include <dirent.h>
# 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 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_ex(hnd, filesize, 0, winapi::file_begin)){
return false;
}
//We will write zeros in the end of the file
//since set_end_of_file does not guarantee this
for(std::size_t remaining = size - filesize, write_size = 0
;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_ex(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_ex(hnd, off, 0, (unsigned long) pos); }
inline bool get_file_pointer(file_handle_t hnd, offset_t &off)
{ return winapi::set_file_pointer_ex(hnd, 0, &off, winapi::file_current); }
inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata)
{
unsigned long written;
return 0 != winapi::write_file(hnd, data, (unsigned long)numdata, &written, 0);
}
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 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(1){
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
@@ -0,0 +1,617 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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
//According to the article "C/C++ tip: How to measure elapsed real time for benchmarking"
# if 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
# elif !defined(CLOCK_MONOTONIC) && (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
# 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;
winapi::set_timer_resolution(10000, 0, &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;
winapi::set_timer_resolution(10000, 0, &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;
winapi::set_timer_resolution(10000, 0, &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::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);
}
#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
@@ -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
@@ -0,0 +1,216 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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
namespace boost {
namespace interprocess {
namespace ipcdetail {
// 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
+29
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
+57
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
+162
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
+213
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 pointer_uintptr_caster;
template<class T>
class pointer_uintptr_caster<T*>
{
public:
BOOST_INTERPROCESS_FORCEINLINE explicit pointer_uintptr_caster(uintptr_t sz)
: m_uintptr(sz)
{}
BOOST_INTERPROCESS_FORCEINLINE explicit pointer_uintptr_caster(const volatile T *p)
: m_uintptr(reinterpret_cast<uintptr_t>(p))
{}
BOOST_INTERPROCESS_FORCEINLINE uintptr_t uintptr() const
{ return m_uintptr; }
BOOST_INTERPROCESS_FORCEINLINE T* pointer() const
{ return reinterpret_cast<T*>(m_uintptr); }
private:
uintptr_t m_uintptr;
};
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
File diff suppressed because it is too large Load Diff
@@ -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
+208
View File
@@ -0,0 +1,208 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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
//Define this to connect with shared memory created with versions < 1.54
//#define BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME
#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__)
#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
//Mac Os X < Lion (10.7) might define _POSIX_THREAD_PROCESS_SHARED but there is no real support.
#elif defined(__APPLE__)
#include "TargetConditionals.h"
//Check we're on Mac OS target
#if defined(TARGET_OS_MAC)
#include "AvailabilityMacros.h"
//If minimum target for this compilation is older than Mac Os Lion, then we are out of luck
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
#define BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED
#endif
#endif
#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
+241
View File
@@ -0,0 +1,241 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
// Parts of this code are taken from boost::filesystem library
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 Beman Dawes
// Copyright (C) 2001 Dietmar Kuehl
// Use, modification, and distribution is subject to 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 library home page at http://www.boost.org/libs/filesystem
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ERRORS_HPP
#define BOOST_INTERPROCESS_ERRORS_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 <stdarg.h>
#include <string>
#if defined (BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <errno.h> //Errors
# include <cstring> //strerror
# else //ifdef BOOST_HAS_UNISTD_H
# error Unknown platform
# endif //ifdef BOOST_HAS_UNISTD_H
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
//!\file
//!Describes the error numbering of interprocess classes
namespace boost {
namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inline int system_error_code() // artifact of POSIX and WINDOWS error reporting
{
#if defined (BOOST_INTERPROCESS_WINDOWS)
return winapi::get_last_error();
#else
return errno; // GCC 3.1 won't accept ::errno
#endif
}
#if defined (BOOST_INTERPROCESS_WINDOWS)
inline void fill_system_message(int sys_err_code, std::string &str)
{
void *lpMsgBuf;
winapi::format_message(
winapi::format_message_allocate_buffer |
winapi::format_message_from_system |
winapi::format_message_ignore_inserts,
0,
sys_err_code,
winapi::make_lang_id(winapi::lang_neutral, winapi::sublang_default), // Default language
reinterpret_cast<char *>(&lpMsgBuf),
0,
0
);
str += static_cast<const char*>(lpMsgBuf);
winapi::local_free( lpMsgBuf ); // free the buffer
while ( str.size()
&& (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') )
str.erase( str.size()-1 );
}
# else
inline void fill_system_message( int system_error, std::string &str)
{ str = std::strerror(system_error); }
# endif
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
enum error_code_t
{
no_error = 0,
system_error, // system generated error; if possible, is translated
// to one of the more specific errors below.
other_error, // library generated error
security_error, // includes access rights, permissions failures
read_only_error,
io_error,
path_error,
not_found_error,
// not_directory_error,
busy_error, // implies trying again might succeed
already_exists_error,
not_empty_error,
is_directory_error,
out_of_space_error,
out_of_memory_error,
out_of_resource_error,
lock_error,
sem_error,
mode_error,
size_error,
corrupted_error,
not_such_file_or_directory,
invalid_argument,
timeout_when_locking_error,
timeout_when_waiting_error,
owner_dead_error
};
typedef int native_error_t;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
struct ec_xlate
{
native_error_t sys_ec;
error_code_t ec;
};
static const ec_xlate ec_table[] =
{
#if defined (BOOST_INTERPROCESS_WINDOWS)
{ /*ERROR_ACCESS_DENIED*/5L, security_error },
{ /*ERROR_INVALID_ACCESS*/12L, security_error },
{ /*ERROR_SHARING_VIOLATION*/32L, security_error },
{ /*ERROR_LOCK_VIOLATION*/33L, security_error },
{ /*ERROR_LOCKED*/212L, security_error },
{ /*ERROR_NOACCESS*/998L, security_error },
{ /*ERROR_WRITE_PROTECT*/19L, read_only_error },
{ /*ERROR_NOT_READY*/21L, io_error },
{ /*ERROR_SEEK*/25L, io_error },
{ /*ERROR_READ_FAULT*/30L, io_error },
{ /*ERROR_WRITE_FAULT*/29L, io_error },
{ /*ERROR_CANTOPEN*/1011L, io_error },
{ /*ERROR_CANTREAD*/1012L, io_error },
{ /*ERROR_CANTWRITE*/1013L, io_error },
{ /*ERROR_DIRECTORY*/267L, path_error },
{ /*ERROR_INVALID_NAME*/123L, path_error },
{ /*ERROR_FILE_NOT_FOUND*/2L, not_found_error },
{ /*ERROR_PATH_NOT_FOUND*/3L, not_found_error },
{ /*ERROR_DEV_NOT_EXIST*/55L, not_found_error },
{ /*ERROR_DEVICE_IN_USE*/2404L, busy_error },
{ /*ERROR_OPEN_FILES*/2401L, busy_error },
{ /*ERROR_BUSY_DRIVE*/142L, busy_error },
{ /*ERROR_BUSY*/170L, busy_error },
{ /*ERROR_FILE_EXISTS*/80L, already_exists_error },
{ /*ERROR_ALREADY_EXISTS*/183L, already_exists_error },
{ /*ERROR_DIR_NOT_EMPTY*/145L, not_empty_error },
{ /*ERROR_HANDLE_DISK_FULL*/39L, out_of_space_error },
{ /*ERROR_DISK_FULL*/112L, out_of_space_error },
{ /*ERROR_OUTOFMEMORY*/14L, out_of_memory_error },
{ /*ERROR_NOT_ENOUGH_MEMORY*/8L, out_of_memory_error },
{ /*ERROR_TOO_MANY_OPEN_FILES*/4L, out_of_resource_error },
{ /*ERROR_INVALID_ADDRESS*/487L, busy_error }
#else //#if defined (BOOST_INTERPROCESS_WINDOWS)
{ EACCES, security_error },
{ EROFS, read_only_error },
{ EIO, io_error },
{ ENAMETOOLONG, path_error },
{ ENOENT, not_found_error },
// { ENOTDIR, not_directory_error },
{ EAGAIN, busy_error },
{ EBUSY, busy_error },
{ ETXTBSY, busy_error },
{ EEXIST, already_exists_error },
{ ENOTEMPTY, not_empty_error },
{ EISDIR, is_directory_error },
{ ENOSPC, out_of_space_error },
{ ENOMEM, out_of_memory_error },
{ EMFILE, out_of_resource_error },
{ ENOENT, not_such_file_or_directory },
{ EINVAL, invalid_argument }
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
};
inline error_code_t lookup_error(native_error_t err)
{
const ec_xlate *cur = &ec_table[0],
*end = cur + sizeof(ec_table)/sizeof(ec_xlate);
for (;cur != end; ++cur ){
if ( err == cur->sys_ec ) return cur->ec;
}
return system_error; // general system error code
}
struct error_info
{
error_info(error_code_t ec = other_error )
: m_nat(0), m_ec(ec)
{}
error_info(native_error_t sys_err_code)
: m_nat(sys_err_code), m_ec(lookup_error(sys_err_code))
{}
error_info & operator =(error_code_t ec)
{
m_nat = 0;
m_ec = ec;
return *this;
}
error_info & operator =(native_error_t sys_err_code)
{
m_nat = sys_err_code;
m_ec = lookup_error(sys_err_code);
return *this;
}
native_error_t get_native_error()const
{ return m_nat; }
error_code_t get_error_code()const
{ return m_ec; }
private:
native_error_t m_nat;
error_code_t m_ec;
};
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} // namespace interprocess {
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_ERRORS_HPP
+110
View File
@@ -0,0 +1,110 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_EXCEPTIONS_HPP
#define BOOST_INTERPROCESS_EXCEPTIONS_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 <stdexcept>
//!\file
//!Describes exceptions thrown by interprocess classes
namespace boost {
namespace interprocess {
//!This class is the base class of all exceptions
//!thrown by boost::interprocess
class BOOST_SYMBOL_VISIBLE interprocess_exception : public std::exception
{
public:
interprocess_exception(const char *err)
: m_err(other_error)
{
try { m_str = err; }
catch (...) {}
}
interprocess_exception(const error_info &err_info, const char *str = 0)
: m_err(err_info)
{
try{
if(m_err.get_native_error() != 0){
fill_system_message(m_err.get_native_error(), m_str);
}
else if(str){
m_str = str;
}
else{
m_str = "boost::interprocess_exception::library_error";
}
}
catch(...){}
}
virtual ~interprocess_exception() throw(){}
virtual const char * what() const throw()
{ return m_str.c_str(); }
native_error_t get_native_error()const { return m_err.get_native_error(); }
// Note: a value of other_error implies a library (rather than system) error
error_code_t get_error_code() const { return m_err.get_error_code(); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
error_info m_err;
std::string m_str;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
//!This is the exception thrown by shared interprocess_mutex family when a deadlock situation
//!is detected or when using a interprocess_condition the interprocess_mutex is not locked
class BOOST_SYMBOL_VISIBLE lock_exception : public interprocess_exception
{
public:
lock_exception()
: interprocess_exception(lock_error)
{}
virtual const char* what() const throw()
{ return "boost::interprocess::lock_exception"; }
};
//!This exception is thrown when a memory request can't be
//!fulfilled.
class BOOST_SYMBOL_VISIBLE bad_alloc : public interprocess_exception
{
public:
bad_alloc() : interprocess_exception("::boost::interprocess::bad_alloc"){}
virtual const char* what() const throw()
{ return "boost::interprocess::bad_alloc"; }
};
} // namespace interprocess {
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_EXCEPTIONS_HPP
+516
View File
@@ -0,0 +1,516 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_FWD_HPP
#define BOOST_INTERPROCESS_FWD_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#ifndef BOOST_CSTDINT_HPP
# include <boost/cstdint.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/std_fwd.hpp>
//! \file
//! This header file forward declares the basic interprocess types:
//! - boost::interprocess::offset_ptr;
//! - boost::interprocess::permissions;
//! - boost::interprocess::mapped_region;
//! - boost::interprocess::file_mapping;
//! - boost::interprocess::shared_memory_object;
//! - boost::interprocess::windows_shared_memory;
//! - boost::interprocess::xsi_shared_memory;
//!
//! The following synchronization mechanisms and locks:
//! - boost::interprocess::null_mutex;
//! - boost::interprocess::interprocess_mutex;
//! - boost::interprocess::interprocess_recursive_mutex;
//! - boost::interprocess::interprocess_semaphore;
//! - boost::interprocess::named_mutex;
//! - boost::interprocess::named_recursive_mutex;
//! - boost::interprocess::named_semaphore;
//! - boost::interprocess::interprocess_sharable_mutex;
//! - boost::interprocess::interprocess_condition;
//! - boost::interprocess::scoped_lock;
//! - boost::interprocess::sharable_lock;
//! - boost::interprocess::upgradable_lock;
//!
//! The following mutex families:
//! - boost::interprocess::mutex_family;
//! - boost::interprocess::null_mutex_family;
//!
//! The following allocators:
//! - boost::interprocess::allocator;
//! - boost::interprocess::node_allocator;
//! - boost::interprocess::private_node_allocator;
//! - boost::interprocess::cached_node_allocator;
//! - boost::interprocess::adaptive_pool;
//! - boost::interprocess::private_adaptive_pool;
//! - boost::interprocess::cached_adaptive_pool;
//!
//! The following allocation algorithms:
//! - boost::interprocess::simple_seq_fit;
//! - boost::interprocess::rbtree_best_fit;
//!
//! The following index types:
//! - boost::interprocess::flat_map_index;
//! - boost::interprocess::iset_index;
//! - boost::interprocess::iunordered_set_index;
//! - boost::interprocess::map_index;
//! - boost::interprocess::null_index;
//! - boost::interprocess::unordered_map_index;
//!
//! The following managed memory types:
//! - boost::interprocess::segment_manager;
//! - boost::interprocess::basic_managed_external_buffer
//! - boost::interprocess::managed_external_buffer
//! - boost::interprocess::wmanaged_external_buffer
//! - boost::interprocess::basic_managed_shared_memory
//! - boost::interprocess::managed_shared_memory
//! - boost::interprocess::wmanaged_shared_memory
//! - boost::interprocess::basic_managed_windows_shared_memory
//! - boost::interprocess::managed_windows_shared_memory
//! - boost::interprocess::wmanaged_windows_shared_memory
//! - boost::interprocess::basic_managed_xsi_shared_memory
//! - boost::interprocess::managed_xsi_shared_memory
//! - boost::interprocess::wmanaged_xsi_shared_memory
//! - boost::interprocess::fixed_managed_shared_memory
//! - boost::interprocess::wfixed_managed_shared_memory
//! - boost::interprocess::basic_managed_heap_memory
//! - boost::interprocess::managed_heap_memory
//! - boost::interprocess::wmanaged_heap_memory
//! - boost::interprocess::basic_managed_mapped_file
//! - boost::interprocess::managed_mapped_file
//! - boost::interprocess::wmanaged_mapped_file
//!
//! The following exception types:
//! - boost::interprocess::interprocess_exception
//! - boost::interprocess::lock_exception
//! - boost::interprocess::bad_alloc
//!
//! The following stream types:
//! - boost::interprocess::basic_bufferbuf
//! - boost::interprocess::basic_ibufferstream
//! - boost::interprocess::basic_obufferstream
//! - boost::interprocess::basic_bufferstream
//! - boost::interprocess::basic_vectorbuf
//! - boost::interprocess::basic_ivectorstream
//! - boost::interprocess::basic_ovectorstream
//! - boost::interprocess::basic_vectorstream
//!
//! The following smart pointer types:
//! - boost::interprocess::scoped_ptr
//! - boost::interprocess::intrusive_ptr
//! - boost::interprocess::shared_ptr
//! - boost::interprocess::weak_ptr
//!
//! The following interprocess communication types:
//! - boost::interprocess::message_queue_t;
//! - boost::interprocess::message_queue;
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#include <cstddef>
//////////////////////////////////////////////////////////////////////////////
// Standard predeclarations
//////////////////////////////////////////////////////////////////////////////
namespace boost{ namespace intrusive{ } }
namespace boost{ namespace interprocess{ namespace bi = boost::intrusive; } }
namespace boost { namespace interprocess {
//////////////////////////////////////////////////////////////////////////////
// permissions
//////////////////////////////////////////////////////////////////////////////
class permissions;
//////////////////////////////////////////////////////////////////////////////
// shared_memory
//////////////////////////////////////////////////////////////////////////////
class shared_memory_object;
#if defined (BOOST_INTERPROCESS_WINDOWS)
class windows_shared_memory;
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS)
class xsi_shared_memory;
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
//////////////////////////////////////////////////////////////////////////////
// file mapping / mapped region
//////////////////////////////////////////////////////////////////////////////
class file_mapping;
class mapped_region;
//////////////////////////////////////////////////////////////////////////////
// Mutexes
//////////////////////////////////////////////////////////////////////////////
class null_mutex;
class interprocess_mutex;
class interprocess_recursive_mutex;
class named_mutex;
class named_recursive_mutex;
class interprocess_semaphore;
class named_semaphore;
//////////////////////////////////////////////////////////////////////////////
// Mutex families
//////////////////////////////////////////////////////////////////////////////
struct mutex_family;
struct null_mutex_family;
//////////////////////////////////////////////////////////////////////////////
// Other synchronization classes
//////////////////////////////////////////////////////////////////////////////
class interprocess_sharable_mutex;
class interprocess_condition;
//////////////////////////////////////////////////////////////////////////////
// Locks
//////////////////////////////////////////////////////////////////////////////
template <class Mutex>
class scoped_lock;
template <class SharableMutex>
class sharable_lock;
template <class UpgradableMutex>
class upgradable_lock;
//////////////////////////////////////////////////////////////////////////////
// STL compatible allocators
//////////////////////////////////////////////////////////////////////////////
template<class T, class SegmentManager>
class allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64>
class node_allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64>
class private_node_allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64>
class cached_node_allocator;
template< class T, class SegmentManager, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2, unsigned char OverheadPercent = 5 >
class adaptive_pool;
template< class T, class SegmentManager, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2, unsigned char OverheadPercent = 5 >
class private_adaptive_pool;
template< class T, class SegmentManager, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2, unsigned char OverheadPercent = 5 >
class cached_adaptive_pool;
//////////////////////////////////////////////////////////////////////////////
// offset_ptr
//////////////////////////////////////////////////////////////////////////////
static const std::size_t offset_type_alignment = 0;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
# ifdef BOOST_HAS_INTPTR_T
using ::boost::uintptr_t;
# else
typedef std::size_t uintptr_t;
# endif
#endif
template < class T, class DifferenceType = std::ptrdiff_t
, class OffsetType = uintptr_t, std::size_t Alignment = offset_type_alignment>
class offset_ptr;
//////////////////////////////////////////////////////////////////////////////
// Memory allocation algorithms
//////////////////////////////////////////////////////////////////////////////
//Single segment memory allocation algorithms
template<class MutexFamily, class VoidMutex = offset_ptr<void> >
class simple_seq_fit;
template<class MutexFamily, class VoidMutex = offset_ptr<void>, std::size_t MemAlignment = 0>
class rbtree_best_fit;
//////////////////////////////////////////////////////////////////////////////
// Index Types
//////////////////////////////////////////////////////////////////////////////
template<class IndexConfig> class flat_map_index;
template<class IndexConfig> class iset_index;
template<class IndexConfig> class iunordered_set_index;
template<class IndexConfig> class map_index;
template<class IndexConfig> class null_index;
template<class IndexConfig> class unordered_map_index;
//////////////////////////////////////////////////////////////////////////////
// Segment manager
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class segment_manager;
//////////////////////////////////////////////////////////////////////////////
// External buffer managed memory classes
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_external_buffer;
typedef basic_managed_external_buffer
<char
,rbtree_best_fit<null_mutex_family>
,iset_index>
managed_external_buffer;
typedef basic_managed_external_buffer
<wchar_t
,rbtree_best_fit<null_mutex_family>
,iset_index>
wmanaged_external_buffer;
//////////////////////////////////////////////////////////////////////////////
// managed memory classes
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_shared_memory;
typedef basic_managed_shared_memory
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_shared_memory;
typedef basic_managed_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_shared_memory;
//////////////////////////////////////////////////////////////////////////////
// Windows shared memory managed memory classes
//////////////////////////////////////////////////////////////////////////////
#if defined (BOOST_INTERPROCESS_WINDOWS)
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_windows_shared_memory;
typedef basic_managed_windows_shared_memory
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_windows_shared_memory;
typedef basic_managed_windows_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_windows_shared_memory;
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS)
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_xsi_shared_memory;
typedef basic_managed_xsi_shared_memory
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_xsi_shared_memory;
typedef basic_managed_xsi_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_xsi_shared_memory;
#endif //#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS)
//////////////////////////////////////////////////////////////////////////////
// Fixed address shared memory
//////////////////////////////////////////////////////////////////////////////
typedef basic_managed_shared_memory
<char
,rbtree_best_fit<mutex_family, void*>
,iset_index>
fixed_managed_shared_memory;
typedef basic_managed_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family, void*>
,iset_index>
wfixed_managed_shared_memory;
//////////////////////////////////////////////////////////////////////////////
// Heap memory managed memory classes
//////////////////////////////////////////////////////////////////////////////
template
<class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_heap_memory;
typedef basic_managed_heap_memory
<char
,rbtree_best_fit<null_mutex_family>
,iset_index>
managed_heap_memory;
typedef basic_managed_heap_memory
<wchar_t
,rbtree_best_fit<null_mutex_family>
,iset_index>
wmanaged_heap_memory;
//////////////////////////////////////////////////////////////////////////////
// Mapped file managed memory classes
//////////////////////////////////////////////////////////////////////////////
template
<class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_mapped_file;
typedef basic_managed_mapped_file
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_mapped_file;
typedef basic_managed_mapped_file
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_mapped_file;
//////////////////////////////////////////////////////////////////////////////
// Exceptions
//////////////////////////////////////////////////////////////////////////////
class interprocess_exception;
class lock_exception;
class bad_alloc;
//////////////////////////////////////////////////////////////////////////////
// Bufferstream
//////////////////////////////////////////////////////////////////////////////
//bufferstream
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_bufferbuf;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_ibufferstream;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_obufferstream;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_bufferstream;
//////////////////////////////////////////////////////////////////////////////
// Vectorstream
//////////////////////////////////////////////////////////////////////////////
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_vectorbuf;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_ivectorstream;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_ovectorstream;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_vectorstream;
//////////////////////////////////////////////////////////////////////////////
// Smart pointers
//////////////////////////////////////////////////////////////////////////////
template<class T, class Deleter>
class scoped_ptr;
template<class T, class VoidPointer>
class intrusive_ptr;
template<class T, class VoidAllocator, class Deleter>
class shared_ptr;
template<class T, class VoidAllocator, class Deleter>
class weak_ptr;
//////////////////////////////////////////////////////////////////////////////
// IPC
//////////////////////////////////////////////////////////////////////////////
template<class VoidPointer>
class message_queue_t;
typedef message_queue_t<offset_ptr<void> > message_queue;
}} //namespace boost { namespace interprocess {
#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_FWD_HPP
+923
View File
@@ -0,0 +1,923 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_MAPPED_REGION_HPP
#define BOOST_INTERPROCESS_MAPPED_REGION_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/exceptions.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <string>
#include <boost/cstdint.hpp>
#include <boost/assert.hpp>
#include <boost/move/adl_move_swap.hpp>
//Some Unixes use caddr_t instead of void * in madvise
// SunOS Tru64 HP-UX AIX
#if defined(sun) || defined(__sun) || defined(__osf__) || defined(__osf) || defined(_hpux) || defined(hpux) || defined(_AIX)
#define BOOST_INTERPROCESS_MADVISE_USES_CADDR_T
#include <sys/types.h>
#endif
//A lot of UNIXes have destructive semantics for MADV_DONTNEED, so
//we need to be careful to allow it.
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
#define BOOST_INTERPROCESS_MADV_DONTNEED_HAS_NONDESTRUCTIVE_SEMANTICS
#endif
#if defined (BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
# include <boost/interprocess/sync/windows/sync_utils.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <fcntl.h>
# include <sys/mman.h> //mmap
# include <unistd.h>
# include <sys/stat.h>
# include <sys/types.h>
# if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS)
# include <sys/shm.h> //System V shared memory...
# endif
# include <boost/assert.hpp>
# else
# error Unknown platform
# endif
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
//!\file
//!Describes mapped region class
namespace boost {
namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Solaris declares madvise only in some configurations but defines MADV_XXX, a bit confusing.
//Predeclare it here to avoid any compilation error
#if (defined(sun) || defined(__sun)) && defined(MADV_NORMAL)
extern "C" int madvise(caddr_t, size_t, int);
#endif
namespace ipcdetail{ class interprocess_tester; }
namespace ipcdetail{ class raw_mapped_region_creator; }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!The mapped_region class represents a portion or region created from a
//!memory_mappable object.
//!
//!The OS can map a region bigger than the requested one, as region must
//!be multiple of the page size, but mapped_region will always refer to
//!the region specified by the user.
class mapped_region
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
BOOST_MOVABLE_BUT_NOT_COPYABLE(mapped_region)
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Creates a mapping region of the mapped memory "mapping", starting in
//!offset "offset", and the mapping's size will be "size". The mapping
//!can be opened for read only, read-write or copy-on-write.
//!
//!If an address is specified, both the offset and the address must be
//!multiples of the page size.
//!
//!The map is created using "default_map_options". This flag is OS
//!dependant and it should not be changed unless the user needs to
//!specify special options.
//!
//!In Windows systems "map_options" is a DWORD value passed as
//!"dwDesiredAccess" to "MapViewOfFileEx". If "default_map_options" is passed
//!it's initialized to zero. "map_options" is XORed with FILE_MAP_[COPY|READ|WRITE].
//!
//!In UNIX systems and POSIX mappings "map_options" is an int value passed as "flags"
//!to "mmap". If "default_map_options" is specified it's initialized to MAP_NOSYNC
//!if that option exists and to zero otherwise. "map_options" XORed with MAP_PRIVATE or MAP_SHARED.
//!
//!In UNIX systems and XSI mappings "map_options" is an int value passed as "shmflg"
//!to "shmat". If "default_map_options" is specified it's initialized to zero.
//!"map_options" is XORed with SHM_RDONLY if needed.
//!
//!The OS could allocate more pages than size/page_size(), but get_address()
//!will always return the address passed in this function (if not null) and
//!get_size() will return the specified size.
template<class MemoryMappable>
mapped_region(const MemoryMappable& mapping
,mode_t mode
,offset_t offset = 0
,std::size_t size = 0
,const void *address = 0
,map_options_t map_options = default_map_options);
//!Default constructor. Address will be 0 (nullptr).
//!Size will be 0.
//!Does not throw
mapped_region();
//!Move constructor. *this will be constructed taking ownership of "other"'s
//!region and "other" will be left in default constructor state.
mapped_region(BOOST_RV_REF(mapped_region) other)
#if defined (BOOST_INTERPROCESS_WINDOWS)
: m_base(0), m_size(0)
, m_page_offset(0)
, m_mode(read_only)
, m_file_or_mapping_hnd(ipcdetail::invalid_file())
#else
: m_base(0), m_size(0), m_page_offset(0), m_mode(read_only), m_is_xsi(false)
#endif
{ this->swap(other); }
//!Destroys the mapped region.
//!Does not throw
~mapped_region();
//!Move assignment. If *this owns a memory mapped region, it will be
//!destroyed and it will take ownership of "other"'s memory mapped region.
mapped_region &operator=(BOOST_RV_REF(mapped_region) other)
{
mapped_region tmp(boost::move(other));
this->swap(tmp);
return *this;
}
//!Swaps the mapped_region with another
//!mapped region
void swap(mapped_region &other);
//!Returns the size of the mapping. Never throws.
std::size_t get_size() const;
//!Returns the base address of the mapping.
//!Never throws.
void* get_address() const;
//!Returns the mode of the mapping used to construct the mapped region.
//!Never throws.
mode_t get_mode() const;
//!Flushes to the disk a byte range within the mapped memory.
//!If 'async' is true, the function will return before flushing operation is completed
//!If 'async' is false, function will return once data has been written into the underlying
//!device (i.e., in mapped files OS cached information is written to disk).
//!Never throws. Returns false if operation could not be performed.
bool flush(std::size_t mapping_offset = 0, std::size_t numbytes = 0, bool async = true);
//!Shrinks current mapped region. If after shrinking there is no longer need for a previously
//!mapped memory page, accessing that page can trigger a segmentation fault.
//!Depending on the OS, this operation might fail (XSI shared memory), it can decommit storage
//!and free a portion of the virtual address space (e.g.POSIX) or this
//!function can release some physical memory wihout freeing any virtual address space(Windows).
//!Returns true on success. Never throws.
bool shrink_by(std::size_t bytes, bool from_back = true);
//!This enum specifies region usage behaviors that an application can specify
//!to the mapped region implementation.
enum advice_types{
//!Specifies that the application has no advice to give on its behavior with respect to
//!the region. It is the default characteristic if no advice is given for a range of memory.
advice_normal,
//!Specifies that the application expects to access the region sequentially from
//!lower addresses to higher addresses. The implementation can lower the priority of
//!preceding pages within the region once a page have been accessed.
advice_sequential,
//!Specifies that the application expects to access the region in a random order,
//!and prefetching is likely not advantageous.
advice_random,
//!Specifies that the application expects to access the region in the near future.
//!The implementation can prefetch pages of the region.
advice_willneed,
//!Specifies that the application expects that it will not access the region in the near future.
//!The implementation can unload pages within the range to save system resources.
advice_dontneed
};
//!Advises the implementation on the expected behavior of the application with respect to the data
//!in the region. The implementation may use this information to optimize handling of the region data.
//!This function has no effect on the semantics of access to memory in the region, although it may affect
//!the performance of access.
//!If the advise type is not known to the implementation, the function returns false. True otherwise.
bool advise(advice_types advise);
//!Returns the size of the page. This size is the minimum memory that
//!will be used by the system when mapping a memory mappable source and
//!will restrict the address and the offset to map.
static std::size_t get_page_size();
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
//!Closes a previously opened memory mapping. Never throws
void priv_close();
void* priv_map_address() const;
std::size_t priv_map_size() const;
bool priv_flush_param_check(std::size_t mapping_offset, void *&addr, std::size_t &numbytes) const;
bool priv_shrink_param_check(std::size_t bytes, bool from_back, void *&shrink_page_start, std::size_t &shrink_page_bytes);
static void priv_size_from_mapping_size
(offset_t mapping_size, offset_t offset, offset_t page_offset, std::size_t &size);
static offset_t priv_page_offset_addr_fixup(offset_t page_offset, const void *&addr);
template<int dummy>
struct page_size_holder
{
static const std::size_t PageSize;
static std::size_t get_page_size();
};
void* m_base;
std::size_t m_size;
std::size_t m_page_offset;
mode_t m_mode;
#if defined(BOOST_INTERPROCESS_WINDOWS)
file_handle_t m_file_or_mapping_hnd;
#else
bool m_is_xsi;
#endif
friend class ipcdetail::interprocess_tester;
friend class ipcdetail::raw_mapped_region_creator;
void dont_close_on_destruction();
#if defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION)
template<int Dummy>
static void destroy_syncs_in_range(const void *addr, std::size_t size);
#endif
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inline void swap(mapped_region &x, mapped_region &y)
{ x.swap(y); }
inline mapped_region::~mapped_region()
{ this->priv_close(); }
inline std::size_t mapped_region::get_size() const
{ return m_size; }
inline mode_t mapped_region::get_mode() const
{ return m_mode; }
inline void* mapped_region::get_address() const
{ return m_base; }
inline void* mapped_region::priv_map_address() const
{ return static_cast<char*>(m_base) - m_page_offset; }
inline std::size_t mapped_region::priv_map_size() const
{ return m_size + m_page_offset; }
inline bool mapped_region::priv_flush_param_check
(std::size_t mapping_offset, void *&addr, std::size_t &numbytes) const
{
//Check some errors
if(m_base == 0)
return false;
if(mapping_offset >= m_size || (mapping_offset + numbytes) > m_size){
return false;
}
//Update flush size if the user does not provide it
if(numbytes == 0){
numbytes = m_size - mapping_offset;
}
addr = (char*)this->priv_map_address() + mapping_offset;
numbytes += m_page_offset;
return true;
}
inline bool mapped_region::priv_shrink_param_check
(std::size_t bytes, bool from_back, void *&shrink_page_start, std::size_t &shrink_page_bytes)
{
//Check some errors
if(m_base == 0 || bytes > m_size){
return false;
}
else if(bytes == m_size){
this->priv_close();
return true;
}
else{
const std::size_t page_size = mapped_region::get_page_size();
if(from_back){
const std::size_t new_pages = (m_size + m_page_offset - bytes - 1)/page_size + 1;
shrink_page_start = static_cast<char*>(this->priv_map_address()) + new_pages*page_size;
shrink_page_bytes = m_page_offset + m_size - new_pages*page_size;
m_size -= bytes;
}
else{
shrink_page_start = this->priv_map_address();
m_page_offset += bytes;
shrink_page_bytes = (m_page_offset/page_size)*page_size;
m_page_offset = m_page_offset % page_size;
m_size -= bytes;
m_base = static_cast<char *>(m_base) + bytes;
BOOST_ASSERT(shrink_page_bytes%page_size == 0);
}
return true;
}
}
inline void mapped_region::priv_size_from_mapping_size
(offset_t mapping_size, offset_t offset, offset_t page_offset, std::size_t &size)
{
//Check if mapping size fits in the user address space
//as offset_t is the maximum file size and its signed.
if(mapping_size < offset ||
boost::uintmax_t(mapping_size - (offset - page_offset)) >
boost::uintmax_t(std::size_t(-1))){
error_info err(size_error);
throw interprocess_exception(err);
}
size = static_cast<std::size_t>(mapping_size - (offset - page_offset));
}
inline offset_t mapped_region::priv_page_offset_addr_fixup(offset_t offset, const void *&address)
{
//We can't map any offset so we have to obtain system's
//memory granularity
const std::size_t page_size = mapped_region::get_page_size();
//We calculate the difference between demanded and valid offset
//(always less than a page in std::size_t, thus, representable by std::size_t)
const std::size_t page_offset =
static_cast<std::size_t>(offset - (offset / page_size) * page_size);
//Update the mapping address
if(address){
address = static_cast<const char*>(address) - page_offset;
}
return page_offset;
}
#if defined (BOOST_INTERPROCESS_WINDOWS)
inline mapped_region::mapped_region()
: m_base(0), m_size(0), m_page_offset(0), m_mode(read_only)
, m_file_or_mapping_hnd(ipcdetail::invalid_file())
{}
template<int dummy>
inline std::size_t mapped_region::page_size_holder<dummy>::get_page_size()
{
winapi::system_info info;
winapi::get_system_info(&info);
return std::size_t(info.dwAllocationGranularity);
}
template<class MemoryMappable>
inline mapped_region::mapped_region
(const MemoryMappable &mapping
,mode_t mode
,offset_t offset
,std::size_t size
,const void *address
,map_options_t map_options)
: m_base(0), m_size(0), m_page_offset(0), m_mode(mode)
, m_file_or_mapping_hnd(ipcdetail::invalid_file())
{
mapping_handle_t mhandle = mapping.get_mapping_handle();
{
file_handle_t native_mapping_handle = 0;
//Set accesses
//For "create_file_mapping"
unsigned long protection = 0;
//For "mapviewoffile"
unsigned long map_access = map_options == default_map_options ? 0 : map_options;
switch(mode)
{
case read_only:
case read_private:
protection |= winapi::page_readonly;
map_access |= winapi::file_map_read;
break;
case read_write:
protection |= winapi::page_readwrite;
map_access |= winapi::file_map_write;
break;
case copy_on_write:
protection |= winapi::page_writecopy;
map_access |= winapi::file_map_copy;
break;
default:
{
error_info err(mode_error);
throw interprocess_exception(err);
}
break;
}
//For file mapping (including emulated shared memory through temporary files),
//the device is a file handle so we need to obtain file's size and call create_file_mapping
//to obtain the mapping handle.
//For files we don't need the file mapping after mapping the memory, as the file is there
//so we'll program the handle close
void * handle_to_close = winapi::invalid_handle_value;
if(!mhandle.is_shm){
//Create mapping handle
native_mapping_handle = winapi::create_file_mapping
( ipcdetail::file_handle_from_mapping_handle(mapping.get_mapping_handle())
, protection, 0, 0, 0);
//Check if all is correct
if(!native_mapping_handle){
error_info err = winapi::get_last_error();
throw interprocess_exception(err);
}
handle_to_close = native_mapping_handle;
}
else{
//For windows_shared_memory the device handle is already a mapping handle
//and we need to maintain it
native_mapping_handle = mhandle.handle;
}
//RAII handle close on scope exit
const winapi::handle_closer close_handle(handle_to_close);
(void)close_handle;
const offset_t page_offset = priv_page_offset_addr_fixup(offset, address);
//Obtain mapping size if user provides 0 size
if(size == 0){
offset_t mapping_size;
if(!winapi::get_file_mapping_size(native_mapping_handle, mapping_size)){
error_info err = winapi::get_last_error();
throw interprocess_exception(err);
}
//This can throw
priv_size_from_mapping_size(mapping_size, offset, page_offset, size);
}
//Map with new offsets and size
void *base = winapi::map_view_of_file_ex
(native_mapping_handle,
map_access,
offset - page_offset,
static_cast<std::size_t>(page_offset + size),
const_cast<void*>(address));
//Check error
if(!base){
error_info err = winapi::get_last_error();
throw interprocess_exception(err);
}
//Calculate new base for the user
m_base = static_cast<char*>(base) + page_offset;
m_page_offset = page_offset;
m_size = size;
}
//Windows shared memory needs the duplication of the handle if we want to
//make mapped_region independent from the mappable device
//
//For mapped files, we duplicate the file handle to be able to FlushFileBuffers
if(!winapi::duplicate_current_process_handle(mhandle.handle, &m_file_or_mapping_hnd)){
error_info err = winapi::get_last_error();
this->priv_close();
throw interprocess_exception(err);
}
}
inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes, bool async)
{
void *addr;
if(!this->priv_flush_param_check(mapping_offset, addr, numbytes)){
return false;
}
//Flush it all
if(!winapi::flush_view_of_file(addr, numbytes)){
return false;
}
//m_file_or_mapping_hnd can be a file handle or a mapping handle.
//so flushing file buffers has only sense for files...
else if(!async && m_file_or_mapping_hnd != winapi::invalid_handle_value &&
winapi::get_file_type(m_file_or_mapping_hnd) == winapi::file_type_disk){
return winapi::flush_file_buffers(m_file_or_mapping_hnd);
}
return true;
}
inline bool mapped_region::shrink_by(std::size_t bytes, bool from_back)
{
void *shrink_page_start = 0;
std::size_t shrink_page_bytes = 0;
if(!this->priv_shrink_param_check(bytes, from_back, shrink_page_start, shrink_page_bytes)){
return false;
}
else if(shrink_page_bytes){
//In Windows, we can't decommit the storage or release the virtual address space,
//the best we can do is try to remove some memory from the process working set.
//With a bit of luck we can free some physical memory.
unsigned long old_protect_ignored;
bool b_ret = winapi::virtual_unlock(shrink_page_start, shrink_page_bytes)
|| (winapi::get_last_error() == winapi::error_not_locked);
(void)old_protect_ignored;
//Change page protection to forbid any further access
b_ret = b_ret && winapi::virtual_protect
(shrink_page_start, shrink_page_bytes, winapi::page_noaccess, old_protect_ignored);
return b_ret;
}
else{
return true;
}
}
inline bool mapped_region::advise(advice_types)
{
//Windows has no madvise/posix_madvise equivalent
return false;
}
inline void mapped_region::priv_close()
{
if(m_base){
void *addr = this->priv_map_address();
#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION)
mapped_region::destroy_syncs_in_range<0>(addr, m_size);
#endif
winapi::unmap_view_of_file(addr);
m_base = 0;
}
if(m_file_or_mapping_hnd != ipcdetail::invalid_file()){
winapi::close_handle(m_file_or_mapping_hnd);
m_file_or_mapping_hnd = ipcdetail::invalid_file();
}
}
inline void mapped_region::dont_close_on_destruction()
{}
#else //#if defined (BOOST_INTERPROCESS_WINDOWS)
inline mapped_region::mapped_region()
: m_base(0), m_size(0), m_page_offset(0), m_mode(read_only), m_is_xsi(false)
{}
template<int dummy>
inline std::size_t mapped_region::page_size_holder<dummy>::get_page_size()
{ return std::size_t(sysconf(_SC_PAGESIZE)); }
template<class MemoryMappable>
inline mapped_region::mapped_region
( const MemoryMappable &mapping
, mode_t mode
, offset_t offset
, std::size_t size
, const void *address
, map_options_t map_options)
: m_base(0), m_size(0), m_page_offset(0), m_mode(mode), m_is_xsi(false)
{
mapping_handle_t map_hnd = mapping.get_mapping_handle();
//Some systems dont' support XSI shared memory
#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
if(map_hnd.is_xsi){
//Get the size
::shmid_ds xsi_ds;
int ret = ::shmctl(map_hnd.handle, IPC_STAT, &xsi_ds);
if(ret == -1){
error_info err(system_error_code());
throw interprocess_exception(err);
}
//Compare sizess
if(size == 0){
size = (std::size_t)xsi_ds.shm_segsz;
}
else if(size != (std::size_t)xsi_ds.shm_segsz){
error_info err(size_error);
throw interprocess_exception(err);
}
//Calculate flag
int flag = map_options == default_map_options ? 0 : map_options;
if(m_mode == read_only){
flag |= SHM_RDONLY;
}
else if(m_mode != read_write){
error_info err(mode_error);
throw interprocess_exception(err);
}
//Attach memory
//Some old shmat implementation take the address as a non-const void pointer
//so uncast it to make code portable.
void *const final_address = const_cast<void *>(address);
void *base = ::shmat(map_hnd.handle, final_address, flag);
if(base == (void*)-1){
error_info err(system_error_code());
throw interprocess_exception(err);
}
//Update members
m_base = base;
m_size = size;
m_mode = mode;
m_page_offset = 0;
m_is_xsi = true;
return;
}
#endif //ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
//We calculate the difference between demanded and valid offset
const offset_t page_offset = priv_page_offset_addr_fixup(offset, address);
if(size == 0){
struct ::stat buf;
if(0 != fstat(map_hnd.handle, &buf)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
//This can throw
priv_size_from_mapping_size(buf.st_size, offset, page_offset, size);
}
#ifdef MAP_NOSYNC
#define BOOST_INTERPROCESS_MAP_NOSYNC MAP_NOSYNC
#else
#define BOOST_INTERPROCESS_MAP_NOSYNC 0
#endif //MAP_NOSYNC
//Create new mapping
int prot = 0;
int flags = map_options == default_map_options ? BOOST_INTERPROCESS_MAP_NOSYNC : map_options;
#undef BOOST_INTERPROCESS_MAP_NOSYNC
switch(mode)
{
case read_only:
prot |= PROT_READ;
flags |= MAP_SHARED;
break;
case read_private:
prot |= (PROT_READ);
flags |= MAP_PRIVATE;
break;
case read_write:
prot |= (PROT_WRITE | PROT_READ);
flags |= MAP_SHARED;
break;
case copy_on_write:
prot |= (PROT_WRITE | PROT_READ);
flags |= MAP_PRIVATE;
break;
default:
{
error_info err(mode_error);
throw interprocess_exception(err);
}
break;
}
//Map it to the address space
void* base = mmap ( const_cast<void*>(address)
, static_cast<std::size_t>(page_offset + size)
, prot
, flags
, mapping.get_mapping_handle().handle
, offset - page_offset);
//Check if mapping was successful
if(base == MAP_FAILED){
error_info err = system_error_code();
throw interprocess_exception(err);
}
//Calculate new base for the user
m_base = static_cast<char*>(base) + page_offset;
m_page_offset = page_offset;
m_size = size;
//Check for fixed mapping error
if(address && (base != address)){
error_info err(busy_error);
this->priv_close();
throw interprocess_exception(err);
}
}
inline bool mapped_region::shrink_by(std::size_t bytes, bool from_back)
{
void *shrink_page_start = 0;
std::size_t shrink_page_bytes = 0;
if(m_is_xsi || !this->priv_shrink_param_check(bytes, from_back, shrink_page_start, shrink_page_bytes)){
return false;
}
else if(shrink_page_bytes){
//In UNIX we can decommit and free virtual address space.
return 0 == munmap(shrink_page_start, shrink_page_bytes);
}
else{
return true;
}
}
inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes, bool async)
{
void *addr;
if(m_is_xsi || !this->priv_flush_param_check(mapping_offset, addr, numbytes)){
return false;
}
//Flush it all
return msync(addr, numbytes, async ? MS_ASYNC : MS_SYNC) == 0;
}
inline bool mapped_region::advise(advice_types advice)
{
int unix_advice = 0;
//Modes; 0: none, 2: posix, 1: madvise
const unsigned int mode_none = 0;
const unsigned int mode_padv = 1;
const unsigned int mode_madv = 2;
// Suppress "unused variable" warnings
(void)mode_padv;
(void)mode_madv;
unsigned int mode = mode_none;
//Choose advice either from POSIX (preferred) or native Unix
switch(advice){
case advice_normal:
#if defined(POSIX_MADV_NORMAL)
unix_advice = POSIX_MADV_NORMAL;
mode = mode_padv;
#elif defined(MADV_NORMAL)
unix_advice = MADV_NORMAL;
mode = mode_madv;
#endif
break;
case advice_sequential:
#if defined(POSIX_MADV_SEQUENTIAL)
unix_advice = POSIX_MADV_SEQUENTIAL;
mode = mode_padv;
#elif defined(MADV_SEQUENTIAL)
unix_advice = MADV_SEQUENTIAL;
mode = mode_madv;
#endif
break;
case advice_random:
#if defined(POSIX_MADV_RANDOM)
unix_advice = POSIX_MADV_RANDOM;
mode = mode_padv;
#elif defined(MADV_RANDOM)
unix_advice = MADV_RANDOM;
mode = mode_madv;
#endif
break;
case advice_willneed:
#if defined(POSIX_MADV_WILLNEED)
unix_advice = POSIX_MADV_WILLNEED;
mode = mode_padv;
#elif defined(MADV_WILLNEED)
unix_advice = MADV_WILLNEED;
mode = mode_madv;
#endif
break;
case advice_dontneed:
#if defined(POSIX_MADV_DONTNEED)
unix_advice = POSIX_MADV_DONTNEED;
mode = mode_padv;
#elif defined(MADV_DONTNEED) && defined(BOOST_INTERPROCESS_MADV_DONTNEED_HAS_NONDESTRUCTIVE_SEMANTICS)
unix_advice = MADV_DONTNEED;
mode = mode_madv;
#endif
break;
default:
return false;
}
switch(mode){
#if defined(POSIX_MADV_NORMAL)
case mode_padv:
return 0 == posix_madvise(this->priv_map_address(), this->priv_map_size(), unix_advice);
#endif
#if defined(MADV_NORMAL)
case mode_madv:
return 0 == madvise(
#if defined(BOOST_INTERPROCESS_MADVISE_USES_CADDR_T)
(caddr_t)
#endif
this->priv_map_address(), this->priv_map_size(), unix_advice);
#endif
default:
return false;
}
}
inline void mapped_region::priv_close()
{
if(m_base != 0){
#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
if(m_is_xsi){
int ret = ::shmdt(m_base);
BOOST_ASSERT(ret == 0);
(void)ret;
return;
}
#endif //#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
munmap(this->priv_map_address(), this->priv_map_size());
m_base = 0;
}
}
inline void mapped_region::dont_close_on_destruction()
{ m_base = 0; }
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
template<int dummy>
const std::size_t mapped_region::page_size_holder<dummy>::PageSize
= mapped_region::page_size_holder<dummy>::get_page_size();
inline std::size_t mapped_region::get_page_size()
{
if(!page_size_holder<0>::PageSize)
return page_size_holder<0>::get_page_size();
else
return page_size_holder<0>::PageSize;
}
inline void mapped_region::swap(mapped_region &other)
{
::boost::adl_move_swap(this->m_base, other.m_base);
::boost::adl_move_swap(this->m_size, other.m_size);
::boost::adl_move_swap(this->m_page_offset, other.m_page_offset);
::boost::adl_move_swap(this->m_mode, other.m_mode);
#if defined (BOOST_INTERPROCESS_WINDOWS)
::boost::adl_move_swap(this->m_file_or_mapping_hnd, other.m_file_or_mapping_hnd);
#else
::boost::adl_move_swap(this->m_is_xsi, other.m_is_xsi);
#endif
}
//!No-op functor
struct null_mapped_region_function
{
bool operator()(void *, std::size_t , bool) const
{ return true; }
static std::size_t get_min_size()
{ return 0; }
};
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MAPPED_REGION_HPP
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#ifndef BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP
#define BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP
#if defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION)
# include <boost/interprocess/sync/windows/sync_utils.hpp>
# include <boost/interprocess/detail/windows_intermodule_singleton.hpp>
namespace boost {
namespace interprocess {
template<int Dummy>
inline void mapped_region::destroy_syncs_in_range(const void *addr, std::size_t size)
{
ipcdetail::sync_handles &handles =
ipcdetail::windows_intermodule_singleton<ipcdetail::sync_handles>::get();
handles.destroy_syncs_in_range(addr, size);
}
} //namespace interprocess {
} //namespace boost {
#endif //defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION)
#endif //#ifdef BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP
#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+132
View File
@@ -0,0 +1,132 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_PERMISSIONS_HPP
#define BOOST_INTERPROCESS_PERMISSIONS_HPP
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#if defined(BOOST_INTERPROCESS_WINDOWS)
#include <boost/interprocess/detail/win32_api.hpp>
#endif
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!\file
//!Describes permissions class
namespace boost {
namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#if defined(BOOST_INTERPROCESS_WINDOWS)
namespace ipcdetail {
template <int Dummy>
struct unrestricted_permissions_holder
{
static winapi::interprocess_all_access_security unrestricted;
};
template<int Dummy>
winapi::interprocess_all_access_security unrestricted_permissions_holder<Dummy>::unrestricted;
} //namespace ipcdetail {
#endif //defined BOOST_INTERPROCESS_WINDOWS
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!The permissions class represents permissions to be set to shared memory or
//!files, that can be constructed form usual permission representations:
//!a SECURITY_ATTRIBUTES pointer in windows or ORed rwx chmod integer in UNIX.
class permissions
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#if defined(BOOST_INTERPROCESS_WINDOWS)
typedef void* os_permissions_type;
#else
typedef int os_permissions_type;
#endif
os_permissions_type m_perm;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Constructs a permissions object from a user provided os-dependent
//!permissions.
permissions(os_permissions_type type)
: m_perm(type)
{}
//!Constructs a default permissions object:
//!A null security attributes pointer for windows or 0644
//!for UNIX.
permissions()
{ set_default(); }
//!Sets permissions to default values:
//!A null security attributes pointer for windows or 0644
//!for UNIX.
void set_default()
{
#if defined (BOOST_INTERPROCESS_WINDOWS)
m_perm = 0;
#else
m_perm = 0644;
#endif
}
//!Sets permissions to unrestricted access:
//!A null DACL for windows or 0666 for UNIX.
void set_unrestricted()
{
#if defined (BOOST_INTERPROCESS_WINDOWS)
m_perm = &ipcdetail::unrestricted_permissions_holder<0>::unrestricted;
#else
m_perm = 0666;
#endif
}
//!Sets permissions from a user provided os-dependent
//!permissions.
void set_permissions(os_permissions_type perm)
{ m_perm = perm; }
//!Returns stored os-dependent
//!permissions
os_permissions_type get_permissions() const
{ return m_perm; }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_PERMISSIONS_HPP
+436
View File
@@ -0,0 +1,436 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_SHARED_MEMORY_OBJECT_HPP
#define BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/shared_dir_helpers.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/move/adl_move_swap.hpp>
#include <cstddef>
#include <string>
#if defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
# include <fcntl.h> //O_CREAT, O_*...
# include <sys/mman.h> //shm_xxx
# include <unistd.h> //ftruncate, close
# include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
# if defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
# if defined(__FreeBSD__)
# include <sys/sysctl.h>
# endif
# endif
#else
//
#endif
//!\file
//!Describes a shared memory object management class.
namespace boost {
namespace interprocess {
//!A class that wraps a shared memory mapping that can be used to
//!create mapped regions from the mapped files
class shared_memory_object
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable and non-assignable
BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_memory_object)
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Default constructor. Represents an empty shared_memory_object.
shared_memory_object();
//!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode"
//!If the file previously exists, throws an error.*/
shared_memory_object(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 shared memory object 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.
shared_memory_object(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 shared memory object with name "name", with the access mode "mode".
//!If the file does not previously exist, it throws an error.
shared_memory_object(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 shared memory object to *this.
//!After the call, "moved" does not represent any shared memory object.
//!Does not throw
shared_memory_object(BOOST_RV_REF(shared_memory_object) moved)
: m_handle(file_handle_t(ipcdetail::invalid_file()))
, m_mode(read_only)
{ this->swap(moved); }
//!Moves the ownership of "moved"'s shared memory to *this.
//!After the call, "moved" does not represent any shared memory.
//!Does not throw
shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved)
{
shared_memory_object tmp(boost::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps the shared_memory_objects. Does not throw
void swap(shared_memory_object &moved);
//!Erases a shared memory object from the system.
//!Returns false on error. Never throws
static bool remove(const char *name);
//!Sets the size of the shared memory mapping
void truncate(offset_t length);
//!Destroys *this and indicates that the calling process is finished using
//!the resource. All mapped regions are still
//!valid after destruction. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~shared_memory_object();
//!Returns the name of the shared memory object.
const char *get_name() const;
//!Returns true if the size of the shared memory object
//!can be obtained and writes the size in the passed reference
bool get_size(offset_t &size) const;
//!Returns access mode
mode_t get_mode() const;
//!Returns mapping handle. Never throws.
mapping_handle_t get_mapping_handle() const;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
//!Closes a previously opened file mapping. Never throws.
void priv_close();
//!Opens or creates a shared memory object.
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;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inline shared_memory_object::shared_memory_object()
: m_handle(file_handle_t(ipcdetail::invalid_file()))
, m_mode(read_only)
{}
inline shared_memory_object::~shared_memory_object()
{ this->priv_close(); }
inline const char *shared_memory_object::get_name() const
{ return m_filename.c_str(); }
inline bool shared_memory_object::get_size(offset_t &size) const
{ return ipcdetail::get_file_size((file_handle_t)m_handle, size); }
inline void shared_memory_object::swap(shared_memory_object &other)
{
boost::adl_move_swap(m_handle, other.m_handle);
boost::adl_move_swap(m_mode, other.m_mode);
m_filename.swap(other.m_filename);
}
inline mapping_handle_t shared_memory_object::get_mapping_handle() const
{
return ipcdetail::mapping_handle_from_file_handle(m_handle);
}
inline mode_t shared_memory_object::get_mode() const
{ return m_mode; }
#if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
inline bool shared_memory_object::priv_open_or_create
(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm)
{
m_filename = filename;
std::string shmfile;
ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, shmfile);
//Set accesses
if (mode != read_write && mode != read_only){
error_info err = other_error;
throw interprocess_exception(err);
}
switch(type){
case ipcdetail::DoOpen:
m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true);
break;
case ipcdetail::DoCreate:
m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true);
break;
case ipcdetail::DoOpenOrCreate:
m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true);
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Check for error
if(m_handle == ipcdetail::invalid_file()){
error_info err = system_error_code();
this->priv_close();
throw interprocess_exception(err);
}
m_mode = mode;
return true;
}
inline bool shared_memory_object::remove(const char *filename)
{
try{
//Make sure a temporary path is created for shared memory
std::string shmfile;
ipcdetail::shared_filepath(filename, shmfile);
return ipcdetail::delete_file(shmfile.c_str());
}
catch(...){
return false;
}
}
inline void shared_memory_object::truncate(offset_t length)
{
if(!ipcdetail::truncate_file(m_handle, length)){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline void shared_memory_object::priv_close()
{
if(m_handle != ipcdetail::invalid_file()){
ipcdetail::close_file(m_handle);
m_handle = ipcdetail::invalid_file();
}
}
#else //!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
namespace shared_memory_object_detail {
#ifdef BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
#if defined(__FreeBSD__)
inline bool use_filesystem_based_posix()
{
int jailed = 0;
std::size_t len = sizeof(jailed);
::sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0);
return jailed != 0;
}
#else
#error "Not supported platform for BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY"
#endif
#endif
} //shared_memory_object_detail
inline bool shared_memory_object::priv_open_or_create
(ipcdetail::create_enum_t type,
const char *filename,
mode_t mode, const permissions &perm)
{
#if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
const bool add_leading_slash = false;
#elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix();
#else
const bool add_leading_slash = true;
#endif
if(add_leading_slash){
ipcdetail::add_leading_slash(filename, m_filename);
}
else{
ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, m_filename);
}
//Create new mapping
int oflag = 0;
if(mode == read_only){
oflag |= O_RDONLY;
}
else if(mode == read_write){
oflag |= O_RDWR;
}
else{
error_info err(mode_error);
throw interprocess_exception(err);
}
int unix_perm = perm.get_permissions();
switch(type){
case ipcdetail::DoOpen:
{
//No oflag addition
m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
}
break;
case ipcdetail::DoCreate:
{
oflag |= (O_CREAT | O_EXCL);
m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
if(m_handle >= 0){
::fchmod(m_handle, unix_perm);
}
}
break;
case ipcdetail::DoOpenOrCreate:
{
//We need a create/open loop to change permissions correctly using fchmod, since
//with "O_CREAT" only we don't know if we've created or opened the shm.
while(1){
//Try to create shared memory
m_handle = shm_open(m_filename.c_str(), oflag | (O_CREAT | O_EXCL), unix_perm);
//If successful change real permissions
if(m_handle >= 0){
::fchmod(m_handle, unix_perm);
}
//If already exists, try to open
else if(errno == EEXIST){
m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
//If open fails and errno tells the file does not exist
//(shm was removed between creation and opening tries), just retry
if(m_handle < 0 && errno == ENOENT){
continue;
}
}
//Exit retries
break;
}
}
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Check for error
if(m_handle < 0){
error_info err = errno;
this->priv_close();
throw interprocess_exception(err);
}
m_filename = filename;
m_mode = mode;
return true;
}
inline bool shared_memory_object::remove(const char *filename)
{
try{
std::string filepath;
#if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
const bool add_leading_slash = false;
#elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix();
#else
const bool add_leading_slash = true;
#endif
if(add_leading_slash){
ipcdetail::add_leading_slash(filename, filepath);
}
else{
ipcdetail::shared_filepath(filename, filepath);
}
return 0 == shm_unlink(filepath.c_str());
}
catch(...){
return false;
}
}
inline void shared_memory_object::truncate(offset_t length)
{
if(0 != ftruncate(m_handle, length)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline void shared_memory_object::priv_close()
{
if(m_handle != -1){
::close(m_handle);
m_handle = -1;
}
}
#endif
//!A class that stores the name of a shared memory
//!and calls shared_memory_object::remove(name) in its destructor
//!Useful to remove temporary shared memory objects in the presence
//!of exceptions
class remove_shared_memory_on_destroy
{
const char * m_name;
public:
remove_shared_memory_on_destroy(const char *name)
: m_name(name)
{}
~remove_shared_memory_on_destroy()
{ shared_memory_object::remove(m_name); }
};
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
+491
View File
@@ -0,0 +1,491 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's sstream file. Modified by Ion Gaztanaga 2005-2012.
// Changed internal SGI string to a buffer. Added efficient
// internal buffer get/set/swap functions, so that we can obtain/establish the
// internal buffer without any reallocation or copy. Kill those temporaries!
///////////////////////////////////////////////////////////////////////////////
/*
* Copyright (c) 1998
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/
//!\file
//!This file defines basic_bufferbuf, basic_ibufferstream,
//!basic_obufferstream, and basic_bufferstream classes. These classes
//!represent streamsbufs and streams whose sources or destinations
//!are fixed size character buffers.
#ifndef BOOST_INTERPROCESS_BUFFERSTREAM_HPP
#define BOOST_INTERPROCESS_BUFFERSTREAM_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 <iosfwd>
#include <ios>
#include <istream>
#include <ostream>
#include <string> // char traits
#include <cstddef> // ptrdiff_t
#include <boost/assert.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
namespace boost { namespace interprocess {
//!A streambuf class that controls the transmission of elements to and from
//!a basic_xbufferstream. The elements are transmitted from a to a fixed
//!size buffer
template <class CharT, class CharTraits>
class basic_bufferbuf
: public std::basic_streambuf<CharT, CharTraits>
{
public:
typedef CharT char_type;
typedef typename CharTraits::int_type int_type;
typedef typename CharTraits::pos_type pos_type;
typedef typename CharTraits::off_type off_type;
typedef CharTraits traits_type;
typedef std::basic_streambuf<char_type, traits_type> basic_streambuf_t;
public:
//!Constructor.
//!Does not throw.
explicit basic_bufferbuf(std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: basic_streambuf_t(), m_mode(mode), m_buffer(0), m_length(0)
{}
//!Constructor. Assigns formatting buffer.
//!Does not throw.
explicit basic_bufferbuf(CharT *buf, std::size_t length,
std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: basic_streambuf_t(), m_mode(mode), m_buffer(buf), m_length(length)
{ this->set_pointers(); }
virtual ~basic_bufferbuf(){}
public:
//!Returns the pointer and size of the internal buffer.
//!Does not throw.
std::pair<CharT *, std::size_t> buffer() const
{ return std::pair<CharT *, std::size_t>(m_buffer, m_length); }
//!Sets the underlying buffer to a new value
//!Does not throw.
void buffer(CharT *buf, std::size_t length)
{ m_buffer = buf; m_length = length; this->set_pointers(); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
void set_pointers()
{
// The initial read position is the beginning of the buffer.
if(m_mode & std::ios_base::in)
this->setg(m_buffer, m_buffer, m_buffer + m_length);
// The initial write position is the beginning of the buffer.
if(m_mode & std::ios_base::out)
this->setp(m_buffer, m_buffer + m_length);
}
protected:
virtual int_type underflow()
{
// Precondition: gptr() >= egptr(). Returns a character, if available.
return this->gptr() != this->egptr() ?
CharTraits::to_int_type(*this->gptr()) : CharTraits::eof();
}
virtual int_type pbackfail(int_type c = CharTraits::eof())
{
if(this->gptr() != this->eback()) {
if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) {
this->gbump(-1);
return c;
}
else if(m_mode & std::ios_base::out) {
this->gbump(-1);
*this->gptr() = c;
return c;
}
else
return CharTraits::eof();
}
else {
this->gbump(-1);
return CharTraits::not_eof(c);
}
}
else
return CharTraits::eof();
}
virtual int_type overflow(int_type c = CharTraits::eof())
{
if(m_mode & std::ios_base::out) {
if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
// if(!(m_mode & std::ios_base::in)) {
// if(this->pptr() != this->epptr()) {
// *this->pptr() = CharTraits::to_char_type(c);
// this->pbump(1);
// return c;
// }
// else
// return CharTraits::eof();
// }
// else {
if(this->pptr() == this->epptr()) {
//We can't append to a static buffer
return CharTraits::eof();
}
else {
*this->pptr() = CharTraits::to_char_type(c);
this->pbump(1);
return c;
}
// }
}
else // c is EOF, so we don't have to do anything
return CharTraits::not_eof(c);
}
else // Overflow always fails if it's read-only.
return CharTraits::eof();
}
virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
{
bool in = false;
bool out = false;
const std::ios_base::openmode inout =
std::ios_base::in | std::ios_base::out;
if((mode & inout) == inout) {
if(dir == std::ios_base::beg || dir == std::ios_base::end)
in = out = true;
}
else if(mode & std::ios_base::in)
in = true;
else if(mode & std::ios_base::out)
out = true;
if(!in && !out)
return pos_type(off_type(-1));
else if((in && (!(m_mode & std::ios_base::in) || (off != 0 && this->gptr() == 0) )) ||
(out && (!(m_mode & std::ios_base::out) || (off != 0 && this->pptr() == 0))))
return pos_type(off_type(-1));
std::streamoff newoff;
switch(dir) {
case std::ios_base::beg:
newoff = 0;
break;
case std::ios_base::end:
newoff = static_cast<std::streamoff>(m_length);
break;
case std::ios_base::cur:
newoff = in ? static_cast<std::streamoff>(this->gptr() - this->eback())
: static_cast<std::streamoff>(this->pptr() - this->pbase());
break;
default:
return pos_type(off_type(-1));
}
off += newoff;
if(in) {
std::ptrdiff_t n = this->egptr() - this->eback();
if(off < 0 || off > n)
return pos_type(off_type(-1));
else
this->setg(this->eback(), this->eback() + off, this->eback() + n);
}
if(out) {
std::ptrdiff_t n = this->epptr() - this->pbase();
if(off < 0 || off > n)
return pos_type(off_type(-1));
else {
this->setp(this->pbase(), this->pbase() + n);
this->pbump(off);
}
}
return pos_type(off);
}
virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
{ return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode); }
private:
std::ios_base::openmode m_mode;
CharT * m_buffer;
std::size_t m_length;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
//!A basic_istream class that uses a fixed size character buffer
//!as its formatting buffer.
template <class CharT, class CharTraits>
class basic_ibufferstream :
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private basic_bufferbuf<CharT, CharTraits>,
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public std::basic_istream<CharT, CharTraits>
{
public: // Typedefs
typedef typename std::basic_ios
<CharT, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
typedef basic_bufferbuf<CharT, CharTraits> bufferbuf_t;
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_istream<char_type, CharTraits> basic_streambuf_t;
bufferbuf_t & get_buf() { return *this; }
const bufferbuf_t & get_buf() const{ return *this; }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Constructor.
//!Does not throw.
basic_ibufferstream(std::ios_base::openmode mode = std::ios_base::in)
: //basic_ios_t() is called first (lefting it uninitialized) as it's a
//virtual base of basic_istream. The class will be initialized when
//basic_istream is constructed calling basic_ios_t::init().
//As bufferbuf_t's constructor does not throw there is no risk of
//calling the basic_ios_t's destructor without calling basic_ios_t::init()
bufferbuf_t(mode | std::ios_base::in)
, basic_streambuf_t(this)
{}
//!Constructor. Assigns formatting buffer.
//!Does not throw.
basic_ibufferstream(const CharT *buf, std::size_t length,
std::ios_base::openmode mode = std::ios_base::in)
: //basic_ios_t() is called first (lefting it uninitialized) as it's a
//virtual base of basic_istream. The class will be initialized when
//basic_istream is constructed calling basic_ios_t::init().
//As bufferbuf_t's constructor does not throw there is no risk of
//calling the basic_ios_t's destructor without calling basic_ios_t::init()
bufferbuf_t(const_cast<CharT*>(buf), length, mode | std::ios_base::in)
, basic_streambuf_t(this)
{}
~basic_ibufferstream(){};
public:
//!Returns the address of the stored
//!stream buffer.
basic_bufferbuf<CharT, CharTraits>* rdbuf() const
{ return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&get_buf()); }
//!Returns the pointer and size of the internal buffer.
//!Does not throw.
std::pair<const CharT *, std::size_t> buffer() const
{ return get_buf().buffer(); }
//!Sets the underlying buffer to a new value. Resets
//!stream position. Does not throw.
void buffer(const CharT *buf, std::size_t length)
{ get_buf().buffer(const_cast<CharT*>(buf), length); }
};
//!A basic_ostream class that uses a fixed size character buffer
//!as its formatting buffer.
template <class CharT, class CharTraits>
class basic_obufferstream :
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private basic_bufferbuf<CharT, CharTraits>,
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public std::basic_ostream<CharT, CharTraits>
{
public:
typedef typename std::basic_ios
<CharT, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
typedef basic_bufferbuf<CharT, CharTraits> bufferbuf_t;
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_ostream<char_type, CharTraits> basic_ostream_t;
bufferbuf_t & get_buf() { return *this; }
const bufferbuf_t & get_buf() const{ return *this; }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Constructor.
//!Does not throw.
basic_obufferstream(std::ios_base::openmode mode = std::ios_base::out)
: //basic_ios_t() is called first (lefting it uninitialized) as it's a
//virtual base of basic_istream. The class will be initialized when
//basic_istream is constructed calling basic_ios_t::init().
//As bufferbuf_t's constructor does not throw there is no risk of
//calling the basic_ios_t's destructor without calling basic_ios_t::init()
bufferbuf_t(mode | std::ios_base::out)
, basic_ostream_t(this)
{}
//!Constructor. Assigns formatting buffer.
//!Does not throw.
basic_obufferstream(CharT *buf, std::size_t length,
std::ios_base::openmode mode = std::ios_base::out)
: //basic_ios_t() is called first (lefting it uninitialized) as it's a
//virtual base of basic_istream. The class will be initialized when
//basic_istream is constructed calling basic_ios_t::init().
//As bufferbuf_t's constructor does not throw there is no risk of
//calling the basic_ios_t's destructor without calling basic_ios_t::init()
bufferbuf_t(buf, length, mode | std::ios_base::out)
, basic_ostream_t(this)
{}
~basic_obufferstream(){}
public:
//!Returns the address of the stored
//!stream buffer.
basic_bufferbuf<CharT, CharTraits>* rdbuf() const
{ return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&get_buf()); }
//!Returns the pointer and size of the internal buffer.
//!Does not throw.
std::pair<CharT *, std::size_t> buffer() const
{ return get_buf().buffer(); }
//!Sets the underlying buffer to a new value. Resets
//!stream position. Does not throw.
void buffer(CharT *buf, std::size_t length)
{ get_buf().buffer(buf, length); }
};
//!A basic_iostream class that uses a fixed size character buffer
//!as its formatting buffer.
template <class CharT, class CharTraits>
class basic_bufferstream :
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private basic_bufferbuf<CharT, CharTraits>,
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public std::basic_iostream<CharT, CharTraits>
{
public: // Typedefs
typedef typename std::basic_ios
<CharT, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
typedef basic_bufferbuf<CharT, CharTraits> bufferbuf_t;
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_iostream<char_type, CharTraits> basic_iostream_t;
bufferbuf_t & get_buf() { return *this; }
const bufferbuf_t & get_buf() const{ return *this; }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Constructor.
//!Does not throw.
basic_bufferstream(std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: //basic_ios_t() is called first (lefting it uninitialized) as it's a
//virtual base of basic_istream. The class will be initialized when
//basic_istream is constructed calling basic_ios_t::init().
//As bufferbuf_t's constructor does not throw there is no risk of
//calling the basic_ios_t's destructor without calling basic_ios_t::init()
bufferbuf_t(mode)
, basic_iostream_t(this)
{}
//!Constructor. Assigns formatting buffer.
//!Does not throw.
basic_bufferstream(CharT *buf, std::size_t length,
std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: //basic_ios_t() is called first (lefting it uninitialized) as it's a
//virtual base of basic_istream. The class will be initialized when
//basic_istream is constructed calling basic_ios_t::init().
//As bufferbuf_t's constructor does not throw there is no risk of
//calling the basic_ios_t's destructor without calling basic_ios_t::init()
bufferbuf_t(buf, length, mode)
, basic_iostream_t(this)
{}
~basic_bufferstream(){}
public:
//!Returns the address of the stored
//!stream buffer.
basic_bufferbuf<CharT, CharTraits>* rdbuf() const
{ return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&get_buf()); }
//!Returns the pointer and size of the internal buffer.
//!Does not throw.
std::pair<CharT *, std::size_t> buffer() const
{ return get_buf().buffer(); }
//!Sets the underlying buffer to a new value. Resets
//!stream position. Does not throw.
void buffer(CharT *buf, std::size_t length)
{ get_buf().buffer(buf, length); }
};
//Some typedefs to simplify usage
typedef basic_bufferbuf<char> bufferbuf;
typedef basic_bufferstream<char> bufferstream;
typedef basic_ibufferstream<char> ibufferstream;
typedef basic_obufferstream<char> obufferstream;
typedef basic_bufferbuf<wchar_t> wbufferbuf;
typedef basic_bufferstream<wchar_t> wbufferstream;
typedef basic_ibufferstream<wchar_t> wibufferstream;
typedef basic_obufferstream<wchar_t> wobufferstream;
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif /* BOOST_INTERPROCESS_BUFFERSTREAM_HPP */
@@ -0,0 +1,81 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP
#define BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/spin/wait.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class MutexType>
bool try_based_timed_lock(MutexType &m, const boost::posix_time::ptime &abs_time)
{
//Same as lock()
if(abs_time == boost::posix_time::pos_infin){
m.lock();
return true;
}
//Always try to lock to achieve POSIX guarantees:
// "Under no circumstance shall the function fail with a timeout if the mutex
// can be locked immediately. The validity of the abs_timeout parameter need not
// be checked if the mutex can be locked immediately."
else if(m.try_lock()){
return true;
}
else{
spin_wait swait;
while(microsec_clock::universal_time() < abs_time){
if(m.try_lock()){
return true;
}
swait.yield();
}
return false;
}
}
template<class MutexType>
void try_based_lock(MutexType &m)
{
if(!m.try_lock()){
spin_wait swait;
do{
if(m.try_lock()){
break;
}
else{
swait.yield();
}
}
while(1);
}
}
} //namespace ipcdetail
} //namespace interprocess
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP
+101
View File
@@ -0,0 +1,101 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_LOCKS_HPP
#define BOOST_INTERPROCESS_DETAIL_LOCKS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class Lock>
class internal_mutex_lock
{
typedef void (internal_mutex_lock::*unspecified_bool_type)();
public:
typedef typename Lock::mutex_type::internal_mutex_type mutex_type;
internal_mutex_lock(Lock &l)
: l_(l)
{}
mutex_type* mutex() const
{ return l_ ? &l_.mutex()->internal_mutex() : 0; }
void lock() { l_.lock(); }
void unlock() { l_.unlock(); }
operator unspecified_bool_type() const
{ return l_ ? &internal_mutex_lock::lock : 0; }
private:
Lock &l_;
};
template <class Lock>
class lock_inverter
{
Lock &l_;
public:
lock_inverter(Lock &l)
: l_(l)
{}
void lock() { l_.unlock(); }
void unlock() { l_.lock(); }
};
template <class Lock>
class lock_to_sharable
{
Lock &l_;
public:
explicit lock_to_sharable(Lock &l)
: l_(l)
{}
void lock() { l_.lock_sharable(); }
bool try_lock(){ return l_.try_lock_sharable(); }
void unlock() { l_.unlock_sharable(); }
};
template <class Lock>
class lock_to_wait
{
Lock &l_;
public:
explicit lock_to_wait(Lock &l)
: l_(l)
{}
void lock() { l_.wait(); }
bool try_lock(){ return l_.try_wait(); }
};
} //namespace ipcdetail
} //namespace interprocess
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_LOCKS_HPP
@@ -0,0 +1,188 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//
// Parts of the pthread code come from Boost Threads code.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_MUTEX_HPP
#define BOOST_INTERPROCESS_MUTEX_HPP
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/assert.hpp>
#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
#include <boost/interprocess/sync/posix/mutex.hpp>
#define BOOST_INTERPROCESS_USE_POSIX
//Experimental...
#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS)
#include <boost/interprocess/sync/windows/mutex.hpp>
#define BOOST_INTERPROCESS_USE_WINDOWS
#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#include <boost/interprocess/sync/spin/mutex.hpp>
#define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
namespace boost {
namespace interprocess {
namespace ipcdetail{
namespace robust_emulation_helpers {
template<class T>
class mutex_traits;
}}}}
#endif
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!\file
//!Describes a mutex class that can be placed in memory shared by
//!several processes.
namespace boost {
namespace interprocess {
class interprocess_condition;
//!Wraps a interprocess_mutex that can be placed in shared memory and can be
//!shared between processes. Allows timed lock tries
class interprocess_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
interprocess_mutex(const interprocess_mutex &);
interprocess_mutex &operator=(const interprocess_mutex &);
friend class interprocess_condition;
public:
#if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
#undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
typedef ipcdetail::spin_mutex internal_mutex_type;
private:
friend class ipcdetail::robust_emulation_helpers::mutex_traits<interprocess_mutex>;
void take_ownership(){ m_mutex.take_ownership(); }
public:
#elif defined(BOOST_INTERPROCESS_USE_POSIX)
#undef BOOST_INTERPROCESS_USE_POSIX
typedef ipcdetail::posix_mutex internal_mutex_type;
#elif defined(BOOST_INTERPROCESS_USE_WINDOWS)
#undef BOOST_INTERPROCESS_USE_WINDOWS
typedef ipcdetail::windows_mutex internal_mutex_type;
#else
#error "Unknown platform for interprocess_mutex"
#endif
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Constructor.
//!Throws interprocess_exception on error.
interprocess_mutex();
//!Destructor. If any process uses the mutex after the destructor is called
//!the result is undefined. Does not throw.
~interprocess_mutex();
//!Effects: The calling thread tries to obtain ownership of the mutex, and
//! if another thread has ownership of the mutex, it waits until it can
//! obtain the ownership. If a thread takes ownership of the mutex the
//! mutex must be unlocked by the same mutex.
//!Throws: interprocess_exception on error.
void lock();
//!Effects: The calling thread tries to obtain ownership of the mutex, and
//! if another thread has ownership of the mutex returns immediately.
//!Returns: If the thread acquires ownership of the mutex, returns true, if
//! the another thread has ownership of the mutex, returns false.
//!Throws: interprocess_exception on error.
bool try_lock();
//!Effects: The calling thread will try to obtain exclusive ownership of the
//! mutex if it can do so in until the specified time is reached. If the
//! mutex supports recursive locking, the mutex must be unlocked the same
//! number of times it is locked.
//!Returns: If the thread acquires ownership of the mutex, returns true, if
//! the timeout expires returns false.
//!Throws: interprocess_exception on error.
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Effects: The calling thread releases the exclusive ownership of the mutex.
//!Throws: interprocess_exception on error.
void unlock();
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
internal_mutex_type &internal_mutex()
{ return m_mutex; }
const internal_mutex_type &internal_mutex() const
{ return m_mutex; }
private:
internal_mutex_type m_mutex;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
} //namespace interprocess {
} //namespace boost {
namespace boost {
namespace interprocess {
inline interprocess_mutex::interprocess_mutex(){}
inline interprocess_mutex::~interprocess_mutex(){}
inline void interprocess_mutex::lock()
{
#ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING
boost::posix_time::ptime wait_time
= microsec_clock::universal_time()
+ boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS);
if (!m_mutex.timed_lock(wait_time))
{
throw interprocess_exception(timeout_when_locking_error
, "Interprocess mutex timeout when locking. Possible deadlock: "
"owner died without unlocking?");
}
#else
m_mutex.lock();
#endif
}
inline bool interprocess_mutex::try_lock()
{ return m_mutex.try_lock(); }
inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return m_mutex.timed_lock(abs_time); }
inline void interprocess_mutex::unlock()
{ m_mutex.unlock(); }
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MUTEX_HPP
+63
View File
@@ -0,0 +1,63 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_LOCK_OPTIONS_HPP
#define BOOST_INTERPROCESS_LOCK_OPTIONS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
//!\file
//!Describes the lock options with associated with interprocess_mutex lock constructors.
namespace boost {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace posix_time
{ class ptime; }
#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace interprocess {
//!Type to indicate to a mutex lock constructor that must not lock the mutex.
struct defer_lock_type{};
//!Type to indicate to a mutex lock constructor that must try to lock the mutex.
struct try_to_lock_type {};
//!Type to indicate to a mutex lock constructor that the mutex is already locked.
struct accept_ownership_type{};
//!An object indicating that the locking
//!must be deferred.
static const defer_lock_type defer_lock = defer_lock_type();
//!An object indicating that a try_lock()
//!operation must be executed.
static const try_to_lock_type try_to_lock = try_to_lock_type();
//!An object indicating that the ownership of lockable
//!object must be accepted by the new owner.
static const accept_ownership_type accept_ownership = accept_ownership_type();
} // namespace interprocess {
} // namespace boost{
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_LOCK_OPTIONS_HPP
+175
View File
@@ -0,0 +1,175 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_NAMED_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/permissions.hpp>
#if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
#include <boost/interprocess/sync/posix/named_mutex.hpp>
#define BOOST_INTERPROCESS_USE_POSIX_SEMAPHORES
#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS)
#include <boost/interprocess/sync/windows/named_mutex.hpp>
#define BOOST_INTERPROCESS_USE_WINDOWS
#else
#include <boost/interprocess/sync/shm/named_mutex.hpp>
#endif
//!\file
//!Describes a named mutex class for inter-process synchronization
namespace boost {
namespace interprocess {
class named_condition;
//!A mutex with a global name, so it can be found from different
//!processes. This mutex can't be placed in shared memory, and
//!each process should have it's own named_mutex.
class named_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
named_mutex();
named_mutex(const named_mutex &);
named_mutex &operator=(const named_mutex &);
friend class named_condition;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Creates a global mutex with a name.
//!Throws interprocess_exception on error.
named_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions());
//!Opens or creates a global mutex with a name.
//!If the mutex is created, this call is equivalent to
//!named_mutex(create_only_t, ... )
//!If the mutex is already created, this call is equivalent
//!named_mutex(open_only_t, ... )
//!Does not throw
named_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions());
//!Opens a global mutex with a name if that mutex is previously
//!created. If it is not previously created this function throws
//!interprocess_exception.
named_mutex(open_only_t open_only, const char *name);
//!Destroys *this and indicates that the calling process is finished using
//!the resource. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~named_mutex();
//!Unlocks a previously locked
//!mutex.
void unlock();
//!Locks the mutex, sleeps when the mutex is already locked.
//!Throws interprocess_exception if a severe error is found
void lock();
//!Tries to lock the mutex, returns false when the mutex
//!is already locked, returns true when success.
//!Throws interprocess_exception if a severe error is found
bool try_lock();
//!Tries to lock the the mutex until time abs_time,
//!Returns false when timeout expires, returns true when locks.
//!Throws interprocess_exception if a severe error is found
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Erases a named mutex from the system.
//!Returns false on error. Never throws.
static bool remove(const char *name);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction();
public:
#if defined(BOOST_INTERPROCESS_USE_POSIX_SEMAPHORES)
typedef ipcdetail::posix_named_mutex internal_mutex_type;
#undef BOOST_INTERPROCESS_USE_POSIX_SEMAPHORES
#elif defined(BOOST_INTERPROCESS_USE_WINDOWS)
typedef ipcdetail::windows_named_mutex internal_mutex_type;
#undef BOOST_INTERPROCESS_USE_WINDOWS
#else
typedef ipcdetail::shm_named_mutex internal_mutex_type;
#endif
internal_mutex_type &internal_mutex()
{ return m_mut; }
internal_mutex_type m_mut;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inline named_mutex::named_mutex(create_only_t, const char *name, const permissions &perm)
: m_mut(create_only_t(), name, perm)
{}
inline named_mutex::named_mutex(open_or_create_t, const char *name, const permissions &perm)
: m_mut(open_or_create_t(), name, perm)
{}
inline named_mutex::named_mutex(open_only_t, const char *name)
: m_mut(open_only_t(), name)
{}
inline void named_mutex::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_mut); }
inline named_mutex::~named_mutex()
{}
inline void named_mutex::lock()
{ m_mut.lock(); }
inline void named_mutex::unlock()
{ m_mut.unlock(); }
inline bool named_mutex::try_lock()
{ return m_mut.try_lock(); }
inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return m_mut.timed_lock(abs_time); }
inline bool named_mutex::remove(const char *name)
{ return internal_mutex_type::remove(name); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NAMED_MUTEX_HPP
+143
View File
@@ -0,0 +1,143 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//
// Parts of the pthread code come from Boost Threads code:
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP
#define BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <pthread.h>
#include <errno.h>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
# include <boost/interprocess/detail/os_thread_functions.hpp>
# include <boost/interprocess/sync/detail/common_algorithms.hpp>
#endif
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class posix_condition;
class posix_mutex
{
posix_mutex(const posix_mutex &);
posix_mutex &operator=(const posix_mutex &);
public:
posix_mutex();
~posix_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
friend class posix_condition;
private:
pthread_mutex_t m_mut;
};
inline posix_mutex::posix_mutex()
{
mutexattr_wrapper mut_attr;
mutex_initializer mut(m_mut, mut_attr);
mut.release();
}
inline posix_mutex::~posix_mutex()
{
int res = pthread_mutex_destroy(&m_mut);
BOOST_ASSERT(res == 0);(void)res;
}
inline void posix_mutex::lock()
{
if (pthread_mutex_lock(&m_mut) != 0)
throw lock_exception();
}
inline bool posix_mutex::try_lock()
{
int res = pthread_mutex_trylock(&m_mut);
if (!(res == 0 || res == EBUSY))
throw lock_exception();
return res == 0;
}
inline bool posix_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
//Posix does not support infinity absolute time so handle it here
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
timespec ts = ptime_to_timespec(abs_time);
int res = pthread_mutex_timedlock(&m_mut, &ts);
if (res != 0 && res != ETIMEDOUT)
throw lock_exception();
return res == 0;
#else //BOOST_INTERPROCESS_POSIX_TIMEOUTS
return ipcdetail::try_based_timed_lock(*this, abs_time);
#endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS
}
inline void posix_mutex::unlock()
{
int res = 0;
res = pthread_mutex_unlock(&m_mut);
(void)res;
BOOST_ASSERT(res == 0);
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP
@@ -0,0 +1,114 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_POSIX_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_POSIX_NAMED_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/sync/posix/named_semaphore.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class named_condition;
class posix_named_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
posix_named_mutex();
posix_named_mutex(const posix_named_mutex &);
posix_named_mutex &operator=(const posix_named_mutex &);
friend class named_condition;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
posix_named_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions());
posix_named_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions());
posix_named_mutex(open_only_t open_only, const char *name);
~posix_named_mutex();
void unlock();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
static bool remove(const char *name);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
friend class interprocess_tester;
void dont_close_on_destruction();
posix_named_semaphore m_sem;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inline posix_named_mutex::posix_named_mutex(create_only_t, const char *name, const permissions &perm)
: m_sem(create_only, name, 1, perm)
{}
inline posix_named_mutex::posix_named_mutex(open_or_create_t, const char *name, const permissions &perm)
: m_sem(open_or_create, name, 1, perm)
{}
inline posix_named_mutex::posix_named_mutex(open_only_t, const char *name)
: m_sem(open_only, name)
{}
inline void posix_named_mutex::dont_close_on_destruction()
{ interprocess_tester::dont_close_on_destruction(m_sem); }
inline posix_named_mutex::~posix_named_mutex()
{}
inline void posix_named_mutex::lock()
{ m_sem.wait(); }
inline void posix_named_mutex::unlock()
{ m_sem.post(); }
inline bool posix_named_mutex::try_lock()
{ return m_sem.try_wait(); }
inline bool posix_named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return m_sem.timed_wait(abs_time); }
inline bool posix_named_mutex::remove(const char *name)
{ return posix_named_semaphore::remove(name); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_POSIX_NAMED_MUTEX_HPP
@@ -0,0 +1,88 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_POSIX_NAMED_CONDITION_HPP
#define BOOST_INTERPROCESS_POSIX_NAMED_CONDITION_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/posix/semaphore_wrapper.hpp>
namespace boost {
namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace ipcdetail{ class interprocess_tester; }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
namespace ipcdetail {
class posix_named_semaphore
{
posix_named_semaphore();
posix_named_semaphore(const posix_named_semaphore&);
posix_named_semaphore &operator= (const posix_named_semaphore &);
public:
posix_named_semaphore
(create_only_t, const char *name, unsigned int initialCount, const permissions &perm = permissions())
{ semaphore_open(mp_sem, DoCreate, name, initialCount, perm); }
posix_named_semaphore(open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm = permissions())
{ semaphore_open(mp_sem, DoOpenOrCreate, name, initialCount, perm); }
posix_named_semaphore(open_only_t, const char *name)
{ semaphore_open(mp_sem, DoOpen, name); }
~posix_named_semaphore()
{
if(mp_sem != BOOST_INTERPROCESS_POSIX_SEM_FAILED)
semaphore_close(mp_sem);
}
void post()
{ semaphore_post(mp_sem); }
void wait()
{ semaphore_wait(mp_sem); }
bool try_wait()
{ return semaphore_try_wait(mp_sem); }
bool timed_wait(const boost::posix_time::ptime &abs_time)
{ return semaphore_timed_wait(mp_sem, abs_time); }
static bool remove(const char *name)
{ return semaphore_unlink(name); }
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction()
{ mp_sem = BOOST_INTERPROCESS_POSIX_SEM_FAILED; }
sem_t *mp_sem;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_POSIX_NAMED_CONDITION_HPP
@@ -0,0 +1,172 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP
#define BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <pthread.h>
#include <errno.h>
#include <boost/interprocess/exceptions.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail{
#if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED
//!Makes pthread_mutexattr_t cleanup easy when using exceptions
struct mutexattr_wrapper
{
//!Constructor
mutexattr_wrapper(bool recursive = false)
{
if(pthread_mutexattr_init(&m_attr)!=0 ||
pthread_mutexattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0 ||
(recursive &&
pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE)!= 0 ))
throw interprocess_exception("pthread_mutexattr_xxxx failed");
}
//!Destructor
~mutexattr_wrapper() { pthread_mutexattr_destroy(&m_attr); }
//!This allows using mutexattr_wrapper as pthread_mutexattr_t
operator pthread_mutexattr_t&() { return m_attr; }
pthread_mutexattr_t m_attr;
};
//!Makes pthread_condattr_t cleanup easy when using exceptions
struct condattr_wrapper
{
//!Constructor
condattr_wrapper()
{
if(pthread_condattr_init(&m_attr)!=0 ||
pthread_condattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0)
throw interprocess_exception("pthread_condattr_xxxx failed");
}
//!Destructor
~condattr_wrapper() { pthread_condattr_destroy(&m_attr); }
//!This allows using condattr_wrapper as pthread_condattr_t
operator pthread_condattr_t&(){ return m_attr; }
pthread_condattr_t m_attr;
};
//!Makes initialized pthread_mutex_t cleanup easy when using exceptions
class mutex_initializer
{
public:
//!Constructor. Takes interprocess_mutex attributes to initialize the interprocess_mutex
mutex_initializer(pthread_mutex_t &mut, pthread_mutexattr_t &mut_attr)
: mp_mut(&mut)
{
if(pthread_mutex_init(mp_mut, &mut_attr) != 0)
throw interprocess_exception("pthread_mutex_init failed");
}
~mutex_initializer() { if(mp_mut) pthread_mutex_destroy(mp_mut); }
void release() {mp_mut = 0; }
private:
pthread_mutex_t *mp_mut;
};
//!Makes initialized pthread_cond_t cleanup easy when using exceptions
class condition_initializer
{
public:
condition_initializer(pthread_cond_t &cond, pthread_condattr_t &cond_attr)
: mp_cond(&cond)
{
if(pthread_cond_init(mp_cond, &cond_attr)!= 0)
throw interprocess_exception("pthread_cond_init failed");
}
~condition_initializer() { if(mp_cond) pthread_cond_destroy(mp_cond); }
void release() { mp_cond = 0; }
private:
pthread_cond_t *mp_cond;
};
#endif // #if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED
#if defined(BOOST_INTERPROCESS_POSIX_BARRIERS) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
//!Makes pthread_barrierattr_t cleanup easy when using exceptions
struct barrierattr_wrapper
{
//!Constructor
barrierattr_wrapper()
{
if(pthread_barrierattr_init(&m_attr)!=0 ||
pthread_barrierattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0)
throw interprocess_exception("pthread_barrierattr_xxx failed");
}
//!Destructor
~barrierattr_wrapper() { pthread_barrierattr_destroy(&m_attr); }
//!This allows using mutexattr_wrapper as pthread_barrierattr_t
operator pthread_barrierattr_t&() { return m_attr; }
pthread_barrierattr_t m_attr;
};
//!Makes initialized pthread_barrier_t cleanup easy when using exceptions
class barrier_initializer
{
public:
//!Constructor. Takes barrier attributes to initialize the barrier
barrier_initializer(pthread_barrier_t &mut,
pthread_barrierattr_t &mut_attr,
int count)
: mp_barrier(&mut)
{
if(pthread_barrier_init(mp_barrier, &mut_attr, count) != 0)
throw interprocess_exception("pthread_barrier_init failed");
}
~barrier_initializer() { if(mp_barrier) pthread_barrier_destroy(mp_barrier); }
void release() {mp_barrier = 0; }
private:
pthread_barrier_t *mp_barrier;
};
#endif //#if defined(BOOST_INTERPROCESS_POSIX_BARRIERS) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
}//namespace ipcdetail
}//namespace interprocess
}//namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //ifdef BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP
@@ -0,0 +1,48 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP
#define BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
inline timespec ptime_to_timespec (const boost::posix_time::ptime &tm)
{
const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
//Avoid negative absolute times
boost::posix_time::time_duration duration = (tm <= epoch) ? boost::posix_time::time_duration(epoch - epoch)
: boost::posix_time::time_duration(tm - epoch);
timespec ts;
ts.tv_sec = duration.total_seconds();
ts.tv_nsec = duration.total_nanoseconds() % 1000000000;
return ts;
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#endif //ifndef BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP
@@ -0,0 +1,253 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP
#define BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/shared_dir_helpers.hpp>
#include <boost/interprocess/permissions.hpp>
#include <fcntl.h> //O_CREAT, O_*...
#include <unistd.h> //close
#include <string> //std::string
#include <semaphore.h> //sem_* family, SEM_VALUE_MAX
#include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
#include <boost/assert.hpp>
#ifdef SEM_FAILED
#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(SEM_FAILED))
#else
#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(-1))
#endif
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
#else
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/sync/detail/locks.hpp>
#include <boost/interprocess/sync/detail/common_algorithms.hpp>
#endif
namespace boost {
namespace interprocess {
namespace ipcdetail {
#ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
inline bool semaphore_open
(sem_t *&handle, create_enum_t type, const char *origname,
unsigned int count = 0, const permissions &perm = permissions())
{
std::string name;
#ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
add_leading_slash(origname, name);
#else
create_shared_dir_cleaning_old_and_get_filepath(origname, name);
#endif
//Create new mapping
int oflag = 0;
switch(type){
case DoOpen:
{
//No addition
handle = ::sem_open(name.c_str(), oflag);
}
break;
case DoOpenOrCreate:
case DoCreate:
{
while(1){
oflag = (O_CREAT | O_EXCL);
handle = ::sem_open(name.c_str(), oflag, perm.get_permissions(), count);
if(handle != BOOST_INTERPROCESS_POSIX_SEM_FAILED){
//We can't change semaphore permissions!
//::fchmod(handle, perm.get_permissions());
break;
}
else if(errno == EEXIST && type == DoOpenOrCreate){
oflag = 0;
if( (handle = ::sem_open(name.c_str(), oflag)) != BOOST_INTERPROCESS_POSIX_SEM_FAILED
|| (errno != ENOENT) ){
break;
}
}
else{
break;
}
}
}
break;
default:
{
error_info err(other_error);
throw interprocess_exception(err);
}
}
//Check for error
if(handle == BOOST_INTERPROCESS_POSIX_SEM_FAILED){
throw interprocess_exception(error_info(errno));
}
return true;
}
inline void semaphore_close(sem_t *handle)
{
int ret = sem_close(handle);
if(ret != 0){
BOOST_ASSERT(0);
}
}
inline bool semaphore_unlink(const char *semname)
{
try{
std::string sem_str;
#ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
add_leading_slash(semname, sem_str);
#else
shared_filepath(semname, sem_str);
#endif
return 0 == sem_unlink(sem_str.c_str());
}
catch(...){
return false;
}
}
#endif //BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
#ifdef BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES
inline void semaphore_init(sem_t *handle, unsigned int initialCount)
{
int ret = sem_init(handle, 1, initialCount);
//According to SUSV3 version 2003 edition, the return value of a successful
//sem_init call is not defined, but -1 is returned on failure.
//In the future, a successful call might be required to return 0.
if(ret == -1){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline void semaphore_destroy(sem_t *handle)
{
int ret = sem_destroy(handle);
if(ret != 0){
BOOST_ASSERT(0);
}
}
#endif //BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES
inline void semaphore_post(sem_t *handle)
{
int ret = sem_post(handle);
if(ret != 0){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline void semaphore_wait(sem_t *handle)
{
int ret = sem_wait(handle);
if(ret != 0){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline bool semaphore_try_wait(sem_t *handle)
{
int res = sem_trywait(handle);
if(res == 0)
return true;
if(system_error_code() == EAGAIN){
return false;
}
error_info err = system_error_code();
throw interprocess_exception(err);
}
#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
struct semaphore_wrapper_try_wrapper
{
explicit semaphore_wrapper_try_wrapper(sem_t *handle)
: m_handle(handle)
{}
void wait()
{ semaphore_wait(m_handle); }
bool try_wait()
{ return semaphore_try_wait(m_handle); }
private:
sem_t *m_handle;
};
#endif
inline bool semaphore_timed_wait(sem_t *handle, const boost::posix_time::ptime &abs_time)
{
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
//Posix does not support infinity absolute time so handle it here
if(abs_time == boost::posix_time::pos_infin){
semaphore_wait(handle);
return true;
}
timespec tspec = ptime_to_timespec(abs_time);
for (;;){
int res = sem_timedwait(handle, &tspec);
if(res == 0)
return true;
if (res > 0){
//buggy glibc, copy the returned error code to errno
errno = res;
}
if(system_error_code() == ETIMEDOUT){
return false;
}
error_info err = system_error_code();
throw interprocess_exception(err);
}
return false;
#else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
semaphore_wrapper_try_wrapper swtw(handle);
ipcdetail::lock_to_wait<semaphore_wrapper_try_wrapper> lw(swtw);
return ipcdetail::try_based_timed_lock(lw, abs_time);
#endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP
+377
View File
@@ -0,0 +1,377 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//
// This interface is inspired by Howard Hinnant's lock proposal.
// http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SCOPED_LOCK_HPP
#define BOOST_INTERPROCESS_SCOPED_LOCK_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/sync/lock_options.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/detail/simple_swap.hpp>
//!\file
//!Describes the scoped_lock class.
namespace boost {
namespace interprocess {
//!scoped_lock is meant to carry out the tasks for locking, unlocking, try-locking
//!and timed-locking (recursive or not) for the Mutex. The Mutex need not supply all
//!of this functionality. If the client of scoped_lock<Mutex> does not use
//!functionality which the Mutex does not supply, no harm is done. Mutex ownership
//!transfer is supported through the syntax of move semantics. Ownership transfer
//!is allowed both by construction and assignment. The scoped_lock does not support
//!copy semantics. A compile time error results if copy construction or copy
//!assignment is attempted. Mutex ownership can also be moved from an
//!upgradable_lock and sharable_lock via constructor. In this role, scoped_lock
//!shares the same functionality as a write_lock.
template <class Mutex>
class scoped_lock
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
typedef scoped_lock<Mutex> this_type;
BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_lock)
typedef bool this_type::*unspecified_bool_type;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef Mutex mutex_type;
//!Effects: Default constructs a scoped_lock.
//!Postconditions: owns() == false and mutex() == 0.
scoped_lock()
: mp_mutex(0), m_locked(false)
{}
//!Effects: m.lock().
//!Postconditions: owns() == true and mutex() == &m.
//!Notes: The constructor will take ownership of the mutex. If another thread
//! already owns the mutex, this thread will block until the mutex is released.
//! Whether or not this constructor handles recursive locking depends upon the mutex.
explicit scoped_lock(mutex_type& m)
: mp_mutex(&m), m_locked(false)
{ mp_mutex->lock(); m_locked = true; }
//!Postconditions: owns() == false, and mutex() == &m.
//!Notes: The constructor will not take ownership of the mutex. There is no effect
//! required on the referenced mutex.
scoped_lock(mutex_type& m, defer_lock_type)
: mp_mutex(&m), m_locked(false)
{}
//!Postconditions: owns() == true, and mutex() == &m.
//!Notes: The constructor will suppose that the mutex is already locked. There
//! is no effect required on the referenced mutex.
scoped_lock(mutex_type& m, accept_ownership_type)
: mp_mutex(&m), m_locked(true)
{}
//!Effects: m.try_lock().
//!Postconditions: mutex() == &m. owns() == the return value of the
//! m.try_lock() executed within the constructor.
//!Notes: The constructor will take ownership of the mutex if it can do
//! so without waiting. Whether or not this constructor handles recursive
//! locking depends upon the mutex. If the mutex_type does not support try_lock,
//! this constructor will fail at compile time if instantiated, but otherwise
//! have no effect.
scoped_lock(mutex_type& m, try_to_lock_type)
: mp_mutex(&m), m_locked(mp_mutex->try_lock())
{}
//!Effects: m.timed_lock(abs_time).
//!Postconditions: mutex() == &m. owns() == the return value of the
//! m.timed_lock(abs_time) executed within the constructor.
//!Notes: The constructor will take ownership of the mutex if it can do
//! it until abs_time is reached. Whether or not this constructor
//! handles recursive locking depends upon the mutex. If the mutex_type
//! does not support try_lock, this constructor will fail at compile
//! time if instantiated, but otherwise have no effect.
scoped_lock(mutex_type& m, const boost::posix_time::ptime& abs_time)
: mp_mutex(&m), m_locked(mp_mutex->timed_lock(abs_time))
{}
//!Postconditions: mutex() == the value scop.mutex() had before the
//! constructor executes. s1.mutex() == 0. owns() == the value of
//! scop.owns() before the constructor executes. scop.owns().
//!Notes: If the scop scoped_lock owns the mutex, ownership is moved
//! to thisscoped_lock with no blocking. If the scop scoped_lock does not
//! own the mutex, then neither will this scoped_lock. Only a moved
//! scoped_lock's will match this signature. An non-moved scoped_lock
//! can be moved with the expression: "boost::move(lock);". This
//! constructor does not alter the state of the mutex, only potentially
//! who owns it.
scoped_lock(BOOST_RV_REF(scoped_lock) scop)
: mp_mutex(0), m_locked(scop.owns())
{ mp_mutex = scop.release(); }
//!Effects: If upgr.owns() then calls unlock_upgradable_and_lock() on the
//! referenced mutex. upgr.release() is called.
//!Postconditions: mutex() == the value upgr.mutex() had before the construction.
//! upgr.mutex() == 0. owns() == upgr.owns() before the construction.
//! upgr.owns() == false after the construction.
//!Notes: If upgr is locked, this constructor will lock this scoped_lock while
//! unlocking upgr. If upgr is unlocked, then this scoped_lock will be
//! unlocked as well. Only a moved upgradable_lock's will match this
//! signature. An non-moved upgradable_lock can be moved with
//! the expression: "boost::move(lock);" This constructor may block if
//! other threads hold a sharable_lock on this mutex (sharable_lock's can
//! share ownership with an upgradable_lock).
template<class T>
explicit scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr
, typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
: mp_mutex(0), m_locked(false)
{
upgradable_lock<mutex_type> &u_lock = upgr;
if(u_lock.owns()){
u_lock.mutex()->unlock_upgradable_and_lock();
m_locked = true;
}
mp_mutex = u_lock.release();
}
//!Effects: If upgr.owns() then calls try_unlock_upgradable_and_lock() on the
//!referenced mutex:
//! a)if try_unlock_upgradable_and_lock() returns true then mutex() obtains
//! the value from upgr.release() and owns() is set to true.
//! b)if try_unlock_upgradable_and_lock() returns false then upgr is
//! unaffected and this scoped_lock construction as the same effects as
//! a default construction.
//! c)Else upgr.owns() is false. mutex() obtains the value from upgr.release()
//! and owns() is set to false
//!Notes: This construction will not block. It will try to obtain mutex
//! ownership from upgr immediately, while changing the lock type from a
//! "read lock" to a "write lock". If the "read lock" isn't held in the
//! first place, the mutex merely changes type to an unlocked "write lock".
//! If the "read lock" is held, then mutex transfer occurs only if it can
//! do so in a non-blocking manner.
template<class T>
scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr, try_to_lock_type
, typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
: mp_mutex(0), m_locked(false)
{
upgradable_lock<mutex_type> &u_lock = upgr;
if(u_lock.owns()){
if((m_locked = u_lock.mutex()->try_unlock_upgradable_and_lock()) == true){
mp_mutex = u_lock.release();
}
}
else{
u_lock.release();
}
}
//!Effects: If upgr.owns() then calls timed_unlock_upgradable_and_lock(abs_time)
//! on the referenced mutex:
//! a)if timed_unlock_upgradable_and_lock(abs_time) returns true then mutex()
//! obtains the value from upgr.release() and owns() is set to true.
//! b)if timed_unlock_upgradable_and_lock(abs_time) returns false then upgr
//! is unaffected and this scoped_lock construction as the same effects
//! as a default construction.
//! c)Else upgr.owns() is false. mutex() obtains the value from upgr.release()
//! and owns() is set to false
//!Notes: This construction will not block. It will try to obtain mutex ownership
//! from upgr immediately, while changing the lock type from a "read lock" to a
//! "write lock". If the "read lock" isn't held in the first place, the mutex
//! merely changes type to an unlocked "write lock". If the "read lock" is held,
//! then mutex transfer occurs only if it can do so in a non-blocking manner.
template<class T>
scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr, boost::posix_time::ptime &abs_time
, typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
: mp_mutex(0), m_locked(false)
{
upgradable_lock<mutex_type> &u_lock = upgr;
if(u_lock.owns()){
if((m_locked = u_lock.mutex()->timed_unlock_upgradable_and_lock(abs_time)) == true){
mp_mutex = u_lock.release();
}
}
else{
u_lock.release();
}
}
//!Effects: If shar.owns() then calls try_unlock_sharable_and_lock() on the
//!referenced mutex.
//! a)if try_unlock_sharable_and_lock() returns true then mutex() obtains
//! the value from shar.release() and owns() is set to true.
//! b)if try_unlock_sharable_and_lock() returns false then shar is
//! unaffected and this scoped_lock construction has the same
//! effects as a default construction.
//! c)Else shar.owns() is false. mutex() obtains the value from
//! shar.release() and owns() is set to false
//!Notes: This construction will not block. It will try to obtain mutex
//! ownership from shar immediately, while changing the lock type from a
//! "read lock" to a "write lock". If the "read lock" isn't held in the
//! first place, the mutex merely changes type to an unlocked "write lock".
//! If the "read lock" is held, then mutex transfer occurs only if it can
//! do so in a non-blocking manner.
template<class T>
scoped_lock(BOOST_RV_REF(sharable_lock<T>) shar, try_to_lock_type
, typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0)
: mp_mutex(0), m_locked(false)
{
sharable_lock<mutex_type> &s_lock = shar;
if(s_lock.owns()){
if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock()) == true){
mp_mutex = s_lock.release();
}
}
else{
s_lock.release();
}
}
//!Effects: if (owns()) mp_mutex->unlock().
//!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/
~scoped_lock()
{
try{ if(m_locked && mp_mutex) mp_mutex->unlock(); }
catch(...){}
}
//!Effects: If owns() before the call, then unlock() is called on mutex().
//! *this gets the state of scop and scop gets set to a default constructed state.
//!Notes: With a recursive mutex it is possible that both this and scop own
//! the same mutex before the assignment. In this case, this will own the
//! mutex after the assignment (and scop will not), but the mutex's lock
//! count will be decremented by one.
scoped_lock &operator=(BOOST_RV_REF(scoped_lock) scop)
{
if(this->owns())
this->unlock();
m_locked = scop.owns();
mp_mutex = scop.release();
return *this;
}
//!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
//! exception. Calls lock() on the referenced mutex.
//!Postconditions: owns() == true.
//!Notes: The scoped_lock changes from a state of not owning the mutex, to
//! owning the mutex, blocking if necessary.
void lock()
{
if(!mp_mutex || m_locked)
throw lock_exception();
mp_mutex->lock();
m_locked = true;
}
//!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
//! exception. Calls try_lock() on the referenced mutex.
//!Postconditions: owns() == the value returned from mutex()->try_lock().
//!Notes: The scoped_lock changes from a state of not owning the mutex, to
//! owning the mutex, but only if blocking was not required. If the
//! mutex_type does not support try_lock(), this function will fail at
//! compile time if instantiated, but otherwise have no effect.*/
bool try_lock()
{
if(!mp_mutex || m_locked)
throw lock_exception();
m_locked = mp_mutex->try_lock();
return m_locked;
}
//!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
//! exception. Calls timed_lock(abs_time) on the referenced mutex.
//!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time).
//!Notes: The scoped_lock changes from a state of not owning the mutex, to
//! owning the mutex, but only if it can obtain ownership by the specified
//! time. If the mutex_type does not support timed_lock (), this function
//! will fail at compile time if instantiated, but otherwise have no effect.*/
bool timed_lock(const boost::posix_time::ptime& abs_time)
{
if(!mp_mutex || m_locked)
throw lock_exception();
m_locked = mp_mutex->timed_lock(abs_time);
return m_locked;
}
//!Effects: If mutex() == 0 or if not locked, throws a lock_exception()
//! exception. Calls unlock() on the referenced mutex.
//!Postconditions: owns() == false.
//!Notes: The scoped_lock changes from a state of owning the mutex, to not
//! owning the mutex.*/
void unlock()
{
if(!mp_mutex || !m_locked)
throw lock_exception();
mp_mutex->unlock();
m_locked = false;
}
//!Effects: Returns true if this scoped_lock has acquired
//!the referenced mutex.
bool owns() const
{ return m_locked && mp_mutex; }
//!Conversion to bool.
//!Returns owns().
operator unspecified_bool_type() const
{ return m_locked? &this_type::m_locked : 0; }
//!Effects: Returns a pointer to the referenced mutex, or 0 if
//!there is no mutex to reference.
mutex_type* mutex() const
{ return mp_mutex; }
//!Effects: Returns a pointer to the referenced mutex, or 0 if there is no
//! mutex to reference.
//!Postconditions: mutex() == 0 and owns() == false.
mutex_type* release()
{
mutex_type *mut = mp_mutex;
mp_mutex = 0;
m_locked = false;
return mut;
}
//!Effects: Swaps state with moved lock.
//!Throws: Nothing.
void swap( scoped_lock<mutex_type> &other)
{
(simple_swap)(mp_mutex, other.mp_mutex);
(simple_swap)(m_locked, other.m_locked);
}
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
mutex_type *mp_mutex;
bool m_locked;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_SCOPED_LOCK_HPP
@@ -0,0 +1,81 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP
#define BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/container/detail/placement_new.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
struct named_creation_functor_no_arg{};
template <class T, class Arg = named_creation_functor_no_arg>
class named_creation_functor
{
typedef named_creation_functor_no_arg no_arg_t;
public:
named_creation_functor(create_enum_t type, Arg arg = Arg())
: m_creation_type(type), m_arg(arg){}
template<class ArgType>
void construct(void *address, typename enable_if_c<is_same<ArgType, no_arg_t>::value>::type * = 0) const
{ ::new(address, boost_container_new_t())T; }
template<class ArgType>
void construct(void *address, typename enable_if_c<!is_same<ArgType, no_arg_t>::value>::type * = 0) const
{ ::new(address, boost_container_new_t())T(m_arg); }
bool operator()(void *address, std::size_t, bool created) const
{
switch(m_creation_type){
case DoOpen:
return true;
break;
case DoCreate:
case DoOpenOrCreate:
if(created){
construct<Arg>(address);
}
return true;
break;
default:
return false;
break;
}
}
static std::size_t get_min_size()
{ return sizeof(T); }
private:
create_enum_t m_creation_type;
Arg m_arg;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#endif //BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP
+181
View File
@@ -0,0 +1,181 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SHM_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_SHM_NAMED_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/sync/shm/named_creation_functor.hpp>
//!\file
//!Describes a named mutex class for inter-process synchronization
namespace boost {
namespace interprocess {
namespace ipcdetail {
class named_condition;
//!A mutex with a global name, so it can be found from different
//!processes. This mutex can't be placed in shared memory, and
//!each process should have it's own named mutex.
class shm_named_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
shm_named_mutex();
shm_named_mutex(const shm_named_mutex &);
shm_named_mutex &operator=(const shm_named_mutex &);
friend class named_condition;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Creates a global interprocess_mutex with a name.
//!Throws interprocess_exception on error.
shm_named_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions());
//!Opens or creates a global mutex with a name.
//!If the mutex is created, this call is equivalent to
//!shm_named_mutex(create_only_t, ... )
//!If the mutex is already created, this call is equivalent
//!shm_named_mutex(open_only_t, ... )
//!Does not throw
shm_named_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions());
//!Opens a global mutex with a name if that mutex is previously
//!created. If it is not previously created this function throws
//!interprocess_exception.
shm_named_mutex(open_only_t open_only, const char *name);
//!Destroys *this and indicates that the calling process is finished using
//!the resource. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~shm_named_mutex();
//!Unlocks a previously locked
//!interprocess_mutex.
void unlock();
//!Locks interprocess_mutex, sleeps when interprocess_mutex is already locked.
//!Throws interprocess_exception if a severe error is found
void lock();
//!Tries to lock the interprocess_mutex, returns false when interprocess_mutex
//!is already locked, returns true when success.
//!Throws interprocess_exception if a severe error is found
bool try_lock();
//!Tries to lock the interprocess_mutex until time abs_time,
//!Returns false when timeout expires, returns true when locks.
//!Throws interprocess_exception if a severe error is found
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Erases a named mutex from the system.
//!Returns false on error. Never throws.
static bool remove(const char *name);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
typedef interprocess_mutex internal_mutex_type;
interprocess_mutex &internal_mutex()
{ return *static_cast<interprocess_mutex*>(m_shmem.get_user_address()); }
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction();
typedef ipcdetail::managed_open_or_create_impl<shared_memory_object, 0, true, false> open_create_impl_t;
open_create_impl_t m_shmem;
typedef ipcdetail::named_creation_functor<interprocess_mutex> construct_func_t;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inline void shm_named_mutex::dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); }
inline shm_named_mutex::~shm_named_mutex()
{}
inline shm_named_mutex::shm_named_mutex(create_only_t, const char *name, const permissions &perm)
: m_shmem (create_only
,name
,sizeof(interprocess_mutex) +
open_create_impl_t::ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoCreate)
,perm)
{}
inline shm_named_mutex::shm_named_mutex(open_or_create_t, const char *name, const permissions &perm)
: m_shmem (open_or_create
,name
,sizeof(interprocess_mutex) +
open_create_impl_t::ManagedOpenOrCreateUserOffset
,read_write
,0
,construct_func_t(ipcdetail::DoOpenOrCreate)
,perm)
{}
inline shm_named_mutex::shm_named_mutex(open_only_t, const char *name)
: m_shmem (open_only
,name
,read_write
,0
,construct_func_t(ipcdetail::DoOpen))
{}
inline void shm_named_mutex::lock()
{ this->internal_mutex().lock(); }
inline void shm_named_mutex::unlock()
{ this->internal_mutex().unlock(); }
inline bool shm_named_mutex::try_lock()
{ return this->internal_mutex().try_lock(); }
inline bool shm_named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return this->internal_mutex().timed_lock(abs_time); }
inline bool shm_named_mutex::remove(const char *name)
{ return shared_memory_object::remove(name); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_SHM_NAMED_MUTEX_HPP
+87
View File
@@ -0,0 +1,87 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_SPIN_MUTEX_HPP
#define BOOST_INTERPROCESS_DETAIL_SPIN_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/cstdint.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/sync/detail/common_algorithms.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class spin_mutex
{
spin_mutex(const spin_mutex &);
spin_mutex &operator=(const spin_mutex &);
public:
spin_mutex();
~spin_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
void take_ownership(){};
private:
volatile boost::uint32_t m_s;
};
inline spin_mutex::spin_mutex()
: m_s(0)
{
//Note that this class is initialized to zero.
//So zeroed memory can be interpreted as an
//initialized mutex
}
inline spin_mutex::~spin_mutex()
{
//Trivial destructor
}
inline void spin_mutex::lock(void)
{ return ipcdetail::try_based_lock(*this); }
inline bool spin_mutex::try_lock(void)
{
boost::uint32_t prev_s = ipcdetail::atomic_cas32(const_cast<boost::uint32_t*>(&m_s), 1, 0);
return m_s == 1 && prev_s == 0;
}
inline bool spin_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return ipcdetail::try_based_timed_lock(*this, abs_time); }
inline void spin_mutex::unlock(void)
{ ipcdetail::atomic_cas32(const_cast<boost::uint32_t*>(&m_s), 0, 1); }
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_SPIN_MUTEX_HPP
+185
View File
@@ -0,0 +1,185 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Peter Dimov 2008.
// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//Parts of this file come from boost/smart_ptr/detail/yield_k.hpp
//Many thanks to Peter Dimov.
#ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED
#define BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
//#define BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
#ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
#include <iostream>
#endif
// BOOST_INTERPROCESS_SMT_PAUSE
#if defined(_MSC_VER) && ( defined(_M_IX86) || defined(_M_X64) )
extern "C" void _mm_pause();
#pragma intrinsic( _mm_pause )
#define BOOST_INTERPROCESS_SMT_PAUSE _mm_pause();
#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) && !defined(_CRAYC)
#define BOOST_INTERPROCESS_SMT_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" );
#endif
namespace boost{
namespace interprocess{
namespace ipcdetail {
template<int Dummy = 0>
class num_core_holder
{
public:
static unsigned int get()
{
if(!num_cores){
return ipcdetail::get_num_cores();
}
else{
return num_cores;
}
}
private:
static unsigned int num_cores;
};
template<int Dummy>
unsigned int num_core_holder<Dummy>::num_cores = ipcdetail::get_num_cores();
} //namespace ipcdetail {
class spin_wait
{
public:
static const unsigned int nop_pause_limit = 32u;
spin_wait()
: m_count_start(), m_ul_yield_only_counts(), m_k()
{}
#ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
~spin_wait()
{
if(m_k){
std::cout << "final m_k: " << m_k
<< " system tick(us): " << ipcdetail::get_system_tick_us() << std::endl;
}
}
#endif
unsigned int count() const
{ return m_k; }
void yield()
{
//Lazy initialization of limits
if( !m_k){
this->init_limits();
}
//Nop tries
if( m_k < (nop_pause_limit >> 2) ){
}
//Pause tries if the processor supports it
#if defined(BOOST_INTERPROCESS_SMT_PAUSE)
else if( m_k < nop_pause_limit ){
BOOST_INTERPROCESS_SMT_PAUSE
}
#endif
//Yield/Sleep strategy
else{
//Lazy initialization of tick information
if(m_k == nop_pause_limit){
this->init_tick_info();
}
else if( this->yield_or_sleep() ){
ipcdetail::thread_yield();
}
else{
ipcdetail::thread_sleep_tick();
}
}
++m_k;
}
void reset()
{
m_k = 0u;
}
private:
void init_limits()
{
unsigned int num_cores = ipcdetail::num_core_holder<0>::get();
m_k = num_cores > 1u ? 0u : nop_pause_limit;
}
void init_tick_info()
{
m_ul_yield_only_counts = ipcdetail::get_system_tick_in_highres_counts();
m_count_start = ipcdetail::get_current_system_highres_count();
}
//Returns true if yield must be called, false is sleep must be called
bool yield_or_sleep()
{
if(!m_ul_yield_only_counts){ //If yield-only limit was reached then yield one in every two tries
return (m_k & 1u) != 0;
}
else{ //Try to see if we've reched yield-only time limit
const ipcdetail::OS_highres_count_t now = ipcdetail::get_current_system_highres_count();
const ipcdetail::OS_highres_count_t elapsed = ipcdetail::system_highres_count_subtract(now, m_count_start);
if(!ipcdetail::system_highres_count_less_ul(elapsed, m_ul_yield_only_counts)){
#ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
std::cout << "elapsed!\n"
<< " m_ul_yield_only_counts: " << m_ul_yield_only_counts
<< " system tick(us): " << ipcdetail::get_system_tick_us() << '\n'
<< " m_k: " << m_k << " elapsed counts: ";
ipcdetail::ostream_highres_count(std::cout, elapsed) << std::endl;
#endif
//Yield-only time reached, now it's time to sleep
m_ul_yield_only_counts = 0ul;
return false;
}
}
return true; //Otherwise yield
}
ipcdetail::OS_highres_count_t m_count_start;
unsigned long m_ul_yield_only_counts;
unsigned int m_k;
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED
+118
View File
@@ -0,0 +1,118 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP
#define BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/detail/win32_api.hpp>
#include <boost/interprocess/detail/windows_intermodule_singleton.hpp>
#include <boost/interprocess/sync/windows/sync_utils.hpp>
#include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
#include <boost/interprocess/exceptions.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class windows_mutex
{
windows_mutex(const windows_mutex &);
windows_mutex &operator=(const windows_mutex &);
public:
windows_mutex();
~windows_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
void take_ownership(){};
private:
const sync_id id_;
};
inline windows_mutex::windows_mutex()
: id_(this)
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
//Create mutex with the initial count
bool open_or_created;
(void)handles.obtain_mutex(this->id_, &open_or_created);
//The mutex must be created, never opened
BOOST_ASSERT(open_or_created);
BOOST_ASSERT(open_or_created && winapi::get_last_error() != winapi::error_already_exists);
(void)open_or_created;
}
inline windows_mutex::~windows_mutex()
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
handles.destroy_handle(this->id_);
}
inline void windows_mutex::lock(void)
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
//This can throw
winapi_mutex_functions mut(handles.obtain_mutex(this->id_));
mut.lock();
}
inline bool windows_mutex::try_lock(void)
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
//This can throw
winapi_mutex_functions mut(handles.obtain_mutex(this->id_));
return mut.try_lock();
}
inline bool windows_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
//This can throw
winapi_mutex_functions mut(handles.obtain_mutex(this->id_));
return mut.timed_lock(abs_time);
}
inline void windows_mutex::unlock(void)
{
sync_handles &handles =
windows_intermodule_singleton<sync_handles>::get();
//This can throw
winapi_mutex_functions mut(handles.obtain_mutex(this->id_));
return mut.unlock();
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP
@@ -0,0 +1,179 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_WINDOWS_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_WINDOWS_NAMED_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/windows/sync_utils.hpp>
#include <boost/interprocess/sync/windows/named_sync.hpp>
#include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <limits>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class windows_named_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
windows_named_mutex();
windows_named_mutex(const windows_named_mutex &);
windows_named_mutex &operator=(const windows_named_mutex &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
windows_named_mutex(create_only_t, const char *name, const permissions &perm = permissions());
windows_named_mutex(open_or_create_t, const char *name, const permissions &perm = permissions());
windows_named_mutex(open_only_t, const char *name);
~windows_named_mutex();
void unlock();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
static bool remove(const char *name);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
friend class interprocess_tester;
void dont_close_on_destruction();
winapi_mutex_wrapper m_mtx_wrapper;
windows_named_sync m_named_sync;
class named_mut_callbacks : public windows_named_sync_interface
{
public:
named_mut_callbacks(winapi_mutex_wrapper &mtx_wrapper)
: m_mtx_wrapper(mtx_wrapper)
{}
virtual std::size_t get_data_size() const
{ return 0u; }
virtual const void *buffer_with_init_data_to_file()
{ return 0; }
virtual const void *buffer_with_final_data_to_file()
{ return 0; }
virtual void *buffer_to_store_init_data_from_file()
{ return 0; }
virtual bool open(create_enum_t, const char *id_name)
{
std::string aux_str = "Global\\bipc.mut.";
aux_str += id_name;
//
permissions mut_perm;
mut_perm.set_unrestricted();
return m_mtx_wrapper.open_or_create(aux_str.c_str(), mut_perm);
}
virtual void close()
{
m_mtx_wrapper.close();
}
virtual ~named_mut_callbacks()
{}
private:
winapi_mutex_wrapper& m_mtx_wrapper;
};
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
inline windows_named_mutex::~windows_named_mutex()
{
named_mut_callbacks callbacks(m_mtx_wrapper);
m_named_sync.close(callbacks);
}
inline void windows_named_mutex::dont_close_on_destruction()
{}
inline windows_named_mutex::windows_named_mutex
(create_only_t, const char *name, const permissions &perm)
: m_mtx_wrapper()
{
named_mut_callbacks callbacks(m_mtx_wrapper);
m_named_sync.open_or_create(DoCreate, name, perm, callbacks);
}
inline windows_named_mutex::windows_named_mutex
(open_or_create_t, const char *name, const permissions &perm)
: m_mtx_wrapper()
{
named_mut_callbacks callbacks(m_mtx_wrapper);
m_named_sync.open_or_create(DoOpenOrCreate, name, perm, callbacks);
}
inline windows_named_mutex::windows_named_mutex(open_only_t, const char *name)
: m_mtx_wrapper()
{
named_mut_callbacks callbacks(m_mtx_wrapper);
m_named_sync.open_or_create(DoOpen, name, permissions(), callbacks);
}
inline void windows_named_mutex::unlock()
{
m_mtx_wrapper.unlock();
}
inline void windows_named_mutex::lock()
{
m_mtx_wrapper.lock();
}
inline bool windows_named_mutex::try_lock()
{
return m_mtx_wrapper.try_lock();
}
inline bool windows_named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
return m_mtx_wrapper.timed_lock(abs_time);
}
inline bool windows_named_mutex::remove(const char *name)
{
return windows_named_sync::remove(name);
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_WINDOWS_NAMED_MUTEX_HPP
@@ -0,0 +1,219 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_WINDOWS_NAMED_SYNC_HPP
#define BOOST_INTERPROCESS_WINDOWS_NAMED_SYNC_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/shared_dir_helpers.hpp>
#include <boost/interprocess/sync/windows/sync_utils.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <string>
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class windows_named_sync_interface
{
public:
virtual std::size_t get_data_size() const = 0;
virtual const void *buffer_with_final_data_to_file() = 0;
virtual const void *buffer_with_init_data_to_file() = 0;
virtual void *buffer_to_store_init_data_from_file() = 0;
virtual bool open(create_enum_t creation_type, const char *id_name) = 0;
virtual void close() = 0;
virtual ~windows_named_sync_interface() = 0;
};
inline windows_named_sync_interface::~windows_named_sync_interface()
{}
class windows_named_sync
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
windows_named_sync(const windows_named_sync &);
windows_named_sync &operator=(const windows_named_sync &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
windows_named_sync();
void open_or_create(create_enum_t creation_type, const char *name, const permissions &perm, windows_named_sync_interface &sync_interface);
void close(windows_named_sync_interface &sync_interface);
static bool remove(const char *name);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
void *m_file_hnd;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
inline windows_named_sync::windows_named_sync()
: m_file_hnd(winapi::invalid_handle_value)
{}
inline void windows_named_sync::close(windows_named_sync_interface &sync_interface)
{
const std::size_t buflen = sync_interface.get_data_size();
const std::size_t sizeof_file_info = sizeof(sync_id::internal_type) + buflen;
winapi::interprocess_overlapped overlapped;
if(winapi::lock_file_ex
(m_file_hnd, winapi::lockfile_exclusive_lock, 0, sizeof_file_info, 0, &overlapped)){
if(winapi::set_file_pointer_ex(m_file_hnd, sizeof(sync_id::internal_type), 0, winapi::file_begin)){
const void *buf = sync_interface.buffer_with_final_data_to_file();
unsigned long written_or_read = 0;
if(winapi::write_file(m_file_hnd, buf, buflen, &written_or_read, 0)){
//...
}
}
}
sync_interface.close();
if(m_file_hnd != winapi::invalid_handle_value){
winapi::close_handle(m_file_hnd);
m_file_hnd = winapi::invalid_handle_value;
}
}
inline void windows_named_sync::open_or_create
( create_enum_t creation_type
, const char *name
, const permissions &perm
, windows_named_sync_interface &sync_interface)
{
std::string aux_str(name);
m_file_hnd = winapi::invalid_handle_value;
//Use a file to emulate POSIX lifetime semantics. After this logic
//we'll obtain the ID of the native handle to open in aux_str
{
create_shared_dir_cleaning_old_and_get_filepath(name, aux_str);
//Create a file with required permissions.
m_file_hnd = winapi::create_file
( aux_str.c_str()
, winapi::generic_read | winapi::generic_write
, creation_type == DoOpen ? winapi::open_existing :
(creation_type == DoCreate ? winapi::create_new : winapi::open_always)
, 0
, (winapi::interprocess_security_attributes*)perm.get_permissions());
//Obtain OS error in case something has failed
error_info err;
bool success = false;
if(m_file_hnd != winapi::invalid_handle_value){
//Now lock the file
const std::size_t buflen = sync_interface.get_data_size();
typedef __int64 unique_id_type;
const std::size_t sizeof_file_info = sizeof(unique_id_type) + buflen;
winapi::interprocess_overlapped overlapped;
if(winapi::lock_file_ex
(m_file_hnd, winapi::lockfile_exclusive_lock, 0, sizeof_file_info, 0, &overlapped)){
__int64 filesize = 0;
//Obtain the unique id to open the native semaphore.
//If file size was created
if(winapi::get_file_size(m_file_hnd, filesize)){
unsigned long written_or_read = 0;
unique_id_type unique_id_val;
if(static_cast<std::size_t>(filesize) != sizeof_file_info){
winapi::set_end_of_file(m_file_hnd);
winapi::query_performance_counter(&unique_id_val);
const void *buf = sync_interface.buffer_with_init_data_to_file();
//Write unique ID in file. This ID will be used to calculate the semaphore name
if(winapi::write_file(m_file_hnd, &unique_id_val, sizeof(unique_id_val), &written_or_read, 0) &&
written_or_read == sizeof(unique_id_val) &&
winapi::write_file(m_file_hnd, buf, buflen, &written_or_read, 0) &&
written_or_read == buflen ){
success = true;
}
winapi::get_file_size(m_file_hnd, filesize);
BOOST_ASSERT(std::size_t(filesize) == sizeof_file_info);
}
else{
void *buf = sync_interface.buffer_to_store_init_data_from_file();
if(winapi::read_file(m_file_hnd, &unique_id_val, sizeof(unique_id_val), &written_or_read, 0) &&
written_or_read == sizeof(unique_id_val) &&
winapi::read_file(m_file_hnd, buf, buflen, &written_or_read, 0) &&
written_or_read == buflen ){
success = true;
}
}
if(success){
//Now create a global semaphore name based on the unique id
char unique_id_name[sizeof(unique_id_val)*2+1];
std::size_t name_suffix_length = sizeof(unique_id_name);
bytes_to_str(&unique_id_val, sizeof(unique_id_val), &unique_id_name[0], name_suffix_length);
success = sync_interface.open(creation_type, unique_id_name);
}
}
//Obtain OS error in case something has failed
err = system_error_code();
//If this fails we have no possible rollback so don't check the return
if(!winapi::unlock_file_ex(m_file_hnd, 0, sizeof_file_info, 0, &overlapped)){
err = system_error_code();
}
}
else{
//Obtain OS error in case something has failed
err = system_error_code();
}
}
else{
err = system_error_code();
}
if(!success){
if(m_file_hnd != winapi::invalid_handle_value){
winapi::close_handle(m_file_hnd);
m_file_hnd = winapi::invalid_handle_value;
}
//Throw as something went wrong
throw interprocess_exception(err);
}
}
}
inline bool windows_named_sync::remove(const char *name)
{
try{
//Make sure a temporary path is created for shared memory
std::string semfile;
ipcdetail::shared_filepath(name, semfile);
return winapi::unlink_file(semfile.c_str());
}
catch(...){
return false;
}
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_WINDOWS_NAMED_SYNC_HPP
@@ -0,0 +1,240 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP
#define BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/win32_api.hpp>
#include <boost/interprocess/sync/spin/mutex.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp>
#include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
//Shield against external warnings
#include <boost/interprocess/detail/config_external_begin.hpp>
#include <boost/unordered/unordered_map.hpp>
#include <boost/interprocess/detail/config_external_end.hpp>
#include <boost/container/map.hpp>
#include <cstddef>
namespace boost {
namespace interprocess {
namespace ipcdetail {
inline bool bytes_to_str(const void *mem, const std::size_t mem_length, char *out_str, std::size_t &out_length)
{
const std::size_t need_mem = mem_length*2+1;
if(out_length < need_mem){
out_length = need_mem;
return false;
}
const char Characters [] =
{ '0', '1', '2', '3', '4', '5', '6', '7'
, '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
std::size_t char_counter = 0;
const char *buf = (const char *)mem;
for(std::size_t i = 0; i != mem_length; ++i){
out_str[char_counter++] = Characters[(buf[i]&0xF0)>>4];
out_str[char_counter++] = Characters[(buf[i]&0x0F)];
}
out_str[char_counter] = 0;
return true;
}
class sync_id
{
public:
typedef __int64 internal_type;
sync_id(const void *map_addr)
: map_addr_(map_addr)
{ winapi::query_performance_counter(&rand_); }
explicit sync_id(internal_type val, const void *map_addr)
: map_addr_(map_addr)
{ rand_ = val; }
const internal_type &internal_pod() const
{ return rand_; }
internal_type &internal_pod()
{ return rand_; }
const void *map_address() const
{ return map_addr_; }
friend std::size_t hash_value(const sync_id &m)
{ return boost::hash_value(m.rand_); }
friend bool operator==(const sync_id &l, const sync_id &r)
{ return l.rand_ == r.rand_ && l.map_addr_ == r.map_addr_; }
private:
internal_type rand_;
const void * const map_addr_;
};
class sync_handles
{
public:
enum type { MUTEX, SEMAPHORE };
private:
struct address_less
{
bool operator()(sync_id const * const l, sync_id const * const r) const
{ return l->map_address() < r->map_address(); }
};
typedef boost::unordered_map<sync_id, void*> umap_type;
typedef boost::container::map<const sync_id*, umap_type::iterator, address_less> map_type;
static const std::size_t LengthOfGlobal = sizeof("Global\\boost.ipc")-1;
static const std::size_t StrSize = LengthOfGlobal + (sizeof(sync_id)*2+1);
typedef char NameBuf[StrSize];
void fill_name(NameBuf &name, const sync_id &id)
{
const char *n = "Global\\boost.ipc";
std::size_t i = 0;
do{
name[i] = n[i];
++i;
} while(n[i]);
std::size_t len = sizeof(NameBuf) - LengthOfGlobal;
bytes_to_str(&id.internal_pod(), sizeof(id.internal_pod()), &name[LengthOfGlobal], len);
}
void throw_if_error(void *hnd_val)
{
if(!hnd_val){
error_info err(winapi::get_last_error());
throw interprocess_exception(err);
}
}
void* open_or_create_semaphore(const sync_id &id, unsigned int initial_count)
{
NameBuf name;
fill_name(name, id);
permissions unrestricted_security;
unrestricted_security.set_unrestricted();
winapi_semaphore_wrapper sem_wrapper;
bool created;
sem_wrapper.open_or_create
(name, (long)initial_count, winapi_semaphore_wrapper::MaxCount, unrestricted_security, created);
throw_if_error(sem_wrapper.handle());
return sem_wrapper.release();
}
void* open_or_create_mutex(const sync_id &id)
{
NameBuf name;
fill_name(name, id);
permissions unrestricted_security;
unrestricted_security.set_unrestricted();
winapi_mutex_wrapper mtx_wrapper;
mtx_wrapper.open_or_create(name, unrestricted_security);
throw_if_error(mtx_wrapper.handle());
return mtx_wrapper.release();
}
public:
void *obtain_mutex(const sync_id &id, bool *popen_created = 0)
{
umap_type::value_type v(id, (void*)0);
scoped_lock<spin_mutex> lock(mtx_);
umap_type::iterator it = umap_.insert(v).first;
void *&hnd_val = it->second;
if(!hnd_val){
map_[&it->first] = it;
hnd_val = open_or_create_mutex(id);
if(popen_created) *popen_created = true;
}
else if(popen_created){
*popen_created = false;
}
return hnd_val;
}
void *obtain_semaphore(const sync_id &id, unsigned int initial_count, bool *popen_created = 0)
{
umap_type::value_type v(id, (void*)0);
scoped_lock<spin_mutex> lock(mtx_);
umap_type::iterator it = umap_.insert(v).first;
void *&hnd_val = it->second;
if(!hnd_val){
map_[&it->first] = it;
hnd_val = open_or_create_semaphore(id, initial_count);
if(popen_created) *popen_created = true;
}
else if(popen_created){
*popen_created = false;
}
return hnd_val;
}
void destroy_handle(const sync_id &id)
{
scoped_lock<spin_mutex> lock(mtx_);
umap_type::iterator it = umap_.find(id);
umap_type::iterator itend = umap_.end();
if(it != itend){
winapi::close_handle(it->second);
const map_type::key_type &k = &it->first;
map_.erase(k);
umap_.erase(it);
}
}
void destroy_syncs_in_range(const void *addr, std::size_t size)
{
const sync_id low_id(addr);
const sync_id hig_id(static_cast<const char*>(addr)+size);
scoped_lock<spin_mutex> lock(mtx_);
map_type::iterator itlow(map_.lower_bound(&low_id)),
ithig(map_.lower_bound(&hig_id));
while(itlow != ithig){
void * const hnd = umap_[*itlow->first];
winapi::close_handle(hnd);
umap_.erase(*itlow->first);
itlow = map_.erase(itlow);
}
}
private:
spin_mutex mtx_;
umap_type umap_;
map_type map_;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP
@@ -0,0 +1,134 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP
#define BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/win32_api.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/windows/winapi_wrapper_common.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <limits>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class winapi_mutex_functions
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
winapi_mutex_functions(const winapi_mutex_functions &);
winapi_mutex_functions &operator=(const winapi_mutex_functions &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
winapi_mutex_functions(void *mtx_hnd)
: m_mtx_hnd(mtx_hnd)
{}
void unlock()
{ winapi::release_mutex(m_mtx_hnd); }
void lock()
{ return winapi_wrapper_wait_for_single_object(m_mtx_hnd); }
bool try_lock()
{ return winapi_wrapper_try_wait_for_single_object(m_mtx_hnd); }
bool timed_lock(const boost::posix_time::ptime &abs_time)
{ return winapi_wrapper_timed_wait_for_single_object(m_mtx_hnd, abs_time); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
protected:
void *m_mtx_hnd;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
//Swappable mutex wrapper
class winapi_mutex_wrapper
: public winapi_mutex_functions
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
winapi_mutex_wrapper(const winapi_mutex_wrapper &);
winapi_mutex_wrapper &operator=(const winapi_mutex_wrapper &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//Note that Windows API does not return winapi::invalid_handle_value
//when failing to create/open a mutex, but a nullptr
public:
winapi_mutex_wrapper(void *mtx_hnd = 0)
: winapi_mutex_functions(mtx_hnd)
{}
~winapi_mutex_wrapper()
{ this->close(); }
void *release()
{
void *hnd = m_mtx_hnd;
m_mtx_hnd = 0;
return hnd;
}
void *handle() const
{ return m_mtx_hnd; }
bool open_or_create(const char *name, const permissions &perm)
{
if(m_mtx_hnd == 0){
m_mtx_hnd = winapi::open_or_create_mutex
( name
, false
, (winapi::interprocess_security_attributes*)perm.get_permissions()
);
return m_mtx_hnd != 0;
}
else{
return false;
}
}
void close()
{
if(m_mtx_hnd != 0){
winapi::close_handle(m_mtx_hnd);
m_mtx_hnd = 0;
}
}
void swap(winapi_mutex_wrapper &other)
{ void *tmp = m_mtx_hnd; m_mtx_hnd = other.m_mtx_hnd; other.m_mtx_hnd = tmp; }
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP
@@ -0,0 +1,168 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_WINAPI_SEMAPHORE_WRAPPER_HPP
#define BOOST_INTERPROCESS_DETAIL_WINAPI_SEMAPHORE_WRAPPER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/win32_api.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/windows/winapi_wrapper_common.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <limits>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class winapi_semaphore_functions
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
winapi_semaphore_functions(const winapi_semaphore_functions &);
winapi_semaphore_functions &operator=(const winapi_semaphore_functions &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
winapi_semaphore_functions(void *hnd)
: m_sem_hnd(hnd)
{}
void post(long count = 1)
{
long prev_count;
winapi::release_semaphore(m_sem_hnd, count, &prev_count);
}
void wait()
{ return winapi_wrapper_wait_for_single_object(m_sem_hnd); }
bool try_wait()
{ return winapi_wrapper_try_wait_for_single_object(m_sem_hnd); }
bool timed_wait(const boost::posix_time::ptime &abs_time)
{ return winapi_wrapper_timed_wait_for_single_object(m_sem_hnd, abs_time); }
long value() const
{
long l_count, l_limit;
if(!winapi::get_semaphore_info(m_sem_hnd, l_count, l_limit))
return 0;
return l_count;
}
long limit() const
{
long l_count, l_limit;
if(!winapi::get_semaphore_info(m_sem_hnd, l_count, l_limit))
return 0;
return l_limit;
}
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
protected:
void *m_sem_hnd;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
//Swappable semaphore wrapper
class winapi_semaphore_wrapper
: public winapi_semaphore_functions
{
winapi_semaphore_wrapper(const winapi_semaphore_wrapper &);
winapi_semaphore_wrapper &operator=(const winapi_semaphore_wrapper &);
public:
//Long is 32 bits in windows
static const long MaxCount = long(0x7FFFFFFF);
winapi_semaphore_wrapper(void *hnd = winapi::invalid_handle_value)
: winapi_semaphore_functions(hnd)
{}
~winapi_semaphore_wrapper()
{ this->close(); }
void *release()
{
void *hnd = m_sem_hnd;
m_sem_hnd = winapi::invalid_handle_value;
return hnd;
}
void *handle() const
{ return m_sem_hnd; }
bool open_or_create( const char *name
, long sem_count
, long max_count
, const permissions &perm
, bool &created)
{
if(m_sem_hnd == winapi::invalid_handle_value){
m_sem_hnd = winapi::open_or_create_semaphore
( name
, sem_count
, max_count
, (winapi::interprocess_security_attributes*)perm.get_permissions()
);
created = winapi::get_last_error() != winapi::error_already_exists;
return m_sem_hnd != winapi::invalid_handle_value;
}
else{
return false;
}
}
bool open_semaphore(const char *name)
{
if(m_sem_hnd == winapi::invalid_handle_value){
m_sem_hnd = winapi::open_semaphore(name);
return m_sem_hnd != winapi::invalid_handle_value;
}
else{
return false;
}
}
void close()
{
if(m_sem_hnd != winapi::invalid_handle_value){
winapi::close_handle(m_sem_hnd);
m_sem_hnd = winapi::invalid_handle_value;
}
}
void swap(winapi_semaphore_wrapper &other)
{ void *tmp = m_sem_hnd; m_sem_hnd = other.m_sem_hnd; other.m_sem_hnd = tmp; }
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_SEMAPHORE_WRAPPER_HPP
@@ -0,0 +1,97 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_WINAPI_WRAPPER_COMMON_HPP
#define BOOST_INTERPROCESS_DETAIL_WINAPI_WRAPPER_COMMON_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/win32_api.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <limits>
namespace boost {
namespace interprocess {
namespace ipcdetail {
inline void winapi_wrapper_wait_for_single_object(void *handle)
{
unsigned long ret = winapi::wait_for_single_object(handle, winapi::infinite_time);
if(ret != winapi::wait_object_0){
if(ret != winapi::wait_abandoned){
error_info err = system_error_code();
throw interprocess_exception(err);
}
else{ //Special case for orphaned mutexes
winapi::release_mutex(handle);
throw interprocess_exception(owner_dead_error);
}
}
}
inline bool winapi_wrapper_try_wait_for_single_object(void *handle)
{
unsigned long ret = winapi::wait_for_single_object(handle, 0);
if(ret == winapi::wait_object_0){
return true;
}
else if(ret == winapi::wait_timeout){
return false;
}
else{
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline bool winapi_wrapper_timed_wait_for_single_object(void *handle, const boost::posix_time::ptime &abs_time)
{
//Windows does not support infinity abs_time so check it
if(abs_time == boost::posix_time::pos_infin){
winapi_wrapper_wait_for_single_object(handle);
return true;
}
const boost::posix_time::ptime cur_time = microsec_clock::universal_time();
//Windows uses relative wait times so check for negative waits
//and implement as 0 wait to allow try-semantics as POSIX mandates.
unsigned long ret = winapi::wait_for_single_object
( handle
, (abs_time <= cur_time) ? 0u
: (abs_time - cur_time).total_milliseconds()
);
if(ret == winapi::wait_object_0){
return true;
}
else if(ret == winapi::wait_timeout){
return false;
}
else{
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP