mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2026-06-23 08:08:43 -04:00
Squashed 'boost/' content from commit b4feb19f2
git-subtree-dir: boost git-subtree-split: b4feb19f287ee92d87a9624b5d36b7cf46aeadeb
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 ↦
|
||||
}
|
||||
//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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user