From 1a78a62555be32868418fe52f8e330c9d0f95d5a Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 30 Oct 2012 12:57:26 -0700 Subject: Imported Upstream version 1.49.0 --- boost/interprocess/detail/atomic.hpp | 593 +++++++ boost/interprocess/detail/cast_tags.hpp | 29 + boost/interprocess/detail/config_begin.hpp | 47 + boost/interprocess/detail/config_end.hpp | 17 + boost/interprocess/detail/file_wrapper.hpp | 202 +++ boost/interprocess/detail/in_place_interface.hpp | 73 + .../interprocess/detail/intermodule_singleton.hpp | 1184 +++++++++++++ boost/interprocess/detail/interprocess_tester.hpp | 31 + boost/interprocess/detail/intersegment_ptr.hpp | 1040 ++++++++++++ boost/interprocess/detail/managed_memory_impl.hpp | 750 +++++++++ .../detail/managed_multi_shared_memory.hpp | 408 +++++ .../detail/managed_open_or_create_impl.hpp | 483 ++++++ boost/interprocess/detail/math_functions.hpp | 110 ++ boost/interprocess/detail/min_max.hpp | 40 + boost/interprocess/detail/move.hpp | 28 + boost/interprocess/detail/mpl.hpp | 152 ++ .../interprocess/detail/multi_segment_services.hpp | 46 + boost/interprocess/detail/named_proxy.hpp | 349 ++++ boost/interprocess/detail/os_file_functions.hpp | 696 ++++++++ boost/interprocess/detail/os_thread_functions.hpp | 211 +++ boost/interprocess/detail/pointer_type.hpp | 74 + boost/interprocess/detail/posix_time_types_wrk.hpp | 42 + boost/interprocess/detail/preprocessor.hpp | 137 ++ boost/interprocess/detail/ptime_wrk.hpp | 33 + boost/interprocess/detail/robust_emulation.hpp | 439 +++++ .../interprocess/detail/segment_manager_helper.hpp | 513 ++++++ boost/interprocess/detail/tmp_dir_helpers.hpp | 174 ++ boost/interprocess/detail/transform_iterator.hpp | 195 +++ boost/interprocess/detail/type_traits.hpp | 145 ++ boost/interprocess/detail/utilities.hpp | 160 ++ .../detail/variadic_templates_tools.hpp | 153 ++ boost/interprocess/detail/win32_api.hpp | 1766 ++++++++++++++++++++ boost/interprocess/detail/workaround.hpp | 148 ++ .../detail/xsi_shared_memory_device.hpp | 392 +++++ .../detail/xsi_shared_memory_file_wrapper.hpp | 80 + 35 files changed, 10940 insertions(+) create mode 100644 boost/interprocess/detail/atomic.hpp create mode 100644 boost/interprocess/detail/cast_tags.hpp create mode 100644 boost/interprocess/detail/config_begin.hpp create mode 100644 boost/interprocess/detail/config_end.hpp create mode 100644 boost/interprocess/detail/file_wrapper.hpp create mode 100644 boost/interprocess/detail/in_place_interface.hpp create mode 100644 boost/interprocess/detail/intermodule_singleton.hpp create mode 100644 boost/interprocess/detail/interprocess_tester.hpp create mode 100644 boost/interprocess/detail/intersegment_ptr.hpp create mode 100644 boost/interprocess/detail/managed_memory_impl.hpp create mode 100644 boost/interprocess/detail/managed_multi_shared_memory.hpp create mode 100644 boost/interprocess/detail/managed_open_or_create_impl.hpp create mode 100644 boost/interprocess/detail/math_functions.hpp create mode 100644 boost/interprocess/detail/min_max.hpp create mode 100644 boost/interprocess/detail/move.hpp create mode 100644 boost/interprocess/detail/mpl.hpp create mode 100644 boost/interprocess/detail/multi_segment_services.hpp create mode 100644 boost/interprocess/detail/named_proxy.hpp create mode 100644 boost/interprocess/detail/os_file_functions.hpp create mode 100644 boost/interprocess/detail/os_thread_functions.hpp create mode 100644 boost/interprocess/detail/pointer_type.hpp create mode 100644 boost/interprocess/detail/posix_time_types_wrk.hpp create mode 100644 boost/interprocess/detail/preprocessor.hpp create mode 100644 boost/interprocess/detail/ptime_wrk.hpp create mode 100644 boost/interprocess/detail/robust_emulation.hpp create mode 100644 boost/interprocess/detail/segment_manager_helper.hpp create mode 100644 boost/interprocess/detail/tmp_dir_helpers.hpp create mode 100644 boost/interprocess/detail/transform_iterator.hpp create mode 100644 boost/interprocess/detail/type_traits.hpp create mode 100644 boost/interprocess/detail/utilities.hpp create mode 100644 boost/interprocess/detail/variadic_templates_tools.hpp create mode 100644 boost/interprocess/detail/win32_api.hpp create mode 100644 boost/interprocess/detail/workaround.hpp create mode 100644 boost/interprocess/detail/xsi_shared_memory_device.hpp create mode 100644 boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp (limited to 'boost/interprocess/detail') diff --git a/boost/interprocess/detail/atomic.hpp b/boost/interprocess/detail/atomic.hpp new file mode 100644 index 0000000000..f7551f3dda --- /dev/null +++ b/boost/interprocess/detail/atomic.hpp @@ -0,0 +1,593 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2011 +// (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 + +#include +#include +#include + +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 + +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(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(mem))-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) +{ winapi::interlocked_exchange(reinterpret_cast(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(mem), with, cmp); } + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +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; +/* + asm volatile( "lock\n\t" + "cmpxchg %3,%1" + : "=a" (prev), "=m" (*(mem)) + : "0" (prev), "r" (with) + : "memory", "cc"); +*/ +/* + boost::uint32_t prev; + + asm volatile ("lock; cmpxchgl %1, %2" + : "=a" (prev) + : "r" (with), "m" (*(mem)), "0"(cmp)); + asm volatile("" : : : "memory"); + + return prev; +*/ +} + +//! Atomically add 'val' to an boost::uint32_t +//! "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; +/* + asm volatile( "lock\n\t; xaddl %0,%1" + : "=r"(val), "=m"(*mem) + : "0"(val), "m"(*mem)); + asm volatile("" : : : "memory"); + + return val; +*/ +} + +//! Atomically increment an apr_uint32_t by 1 +//! "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; } + +//! 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__) && (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 ("0:\n\t" // retry local label + "lwarx %0,0,%2\n\t" // load prev and reserve + "add %1,%0,%3\n\t" // temp = prev + val + "stwcx. %1,0,%2\n\t" // conditionally store + "bne- 0b" // start over if we lost + // the reservation + //XXX find a cleaner way to define the temp + //it's not an output + : "=&r" (prev), "=&r" (temp) // output, temp + : "b" (mem), "r" (val) // inputs + : "memory", "cc"); // clobbered + 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 ("0:\n\t" // retry local label + "lwarx %0,0,%1\n\t" // load prev and reserve + "cmpw %0,%3\n\t" // does it match cmp? + "bne- 1f\n\t" // ...no, bail out + "stwcx. %2,0,%1\n\t" // ...yes, conditionally + // store with + "bne- 0b\n\t" // start over if we lost + // the reservation + "1:" // exit local label + + : "=&r"(prev) // output + : "b" (mem), "r" (with), "r"(cmp) // inputs + : "memory", "cc"); // clobbered + 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) +{ 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(__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(mem), val); } + +//! Atomically increment an apr_uint32_t by 1 +//! "mem": pointer to the object +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) +{ return atomic_add32(mem, 1); } + +//! Atomically decrement an boost::uint32_t by 1 +//! "mem": pointer to the atomic value +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) +{ return atomic_add32(mem, (boost::uint32_t)-1); } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ return *mem; } + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! Returns the old value of *mem +inline boost::uint32_t atomic_cas32 + (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) +{ return __sync_val_compare_and_swap(const_cast(mem), cmp, with); } + +//! Atomically set an boost::uint32_t in memory +//! "mem": pointer to the object +//! "param": val value that the object will assume +inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ *mem = val; } + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#elif (defined(sun) || defined(__sun)) + +#include + +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(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(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(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(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 +#include + +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 + +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(__lwarx(reinterpret_cast(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(mem), static_cast(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 + +#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 + +#endif //BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP diff --git a/boost/interprocess/detail/cast_tags.hpp b/boost/interprocess/detail/cast_tags.hpp new file mode 100644 index 0000000000..bd91d1b6bb --- /dev/null +++ b/boost/interprocess/detail/cast_tags.hpp @@ -0,0 +1,29 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CAST_TAGS_HPP +#define BOOST_INTERPROCESS_CAST_TAGS_HPP + +#include +#include + +namespace boost { namespace interprocess { namespace ipcdetail { + +struct static_cast_tag {}; +struct const_cast_tag {}; +struct dynamic_cast_tag {}; +struct reinterpret_cast_tag {}; + +}}} //namespace boost { namespace interprocess { namespace ipcdetail { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_CAST_TAGS_HPP + diff --git a/boost/interprocess/detail/config_begin.hpp b/boost/interprocess/detail/config_begin.hpp new file mode 100644 index 0000000000..559331ab32 --- /dev/null +++ b/boost/interprocess/detail/config_begin.hpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_CONFIG_INCLUDED +#define BOOST_INTERPROCESS_CONFIG_INCLUDED +#include +#endif + +#ifdef BOOST_MSVC + #ifndef _CRT_SECURE_NO_DEPRECATE + #define BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE + #define _CRT_SECURE_NO_DEPRECATE + #endif + #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 : 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 +#endif diff --git a/boost/interprocess/detail/config_end.hpp b/boost/interprocess/detail/config_end.hpp new file mode 100644 index 0000000000..422458e855 --- /dev/null +++ b/boost/interprocess/detail/config_end.hpp @@ -0,0 +1,17 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#if defined BOOST_MSVC + #pragma warning (pop) + #ifdef BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE + #undef BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE + #undef _CRT_SECURE_NO_DEPRECATE + #endif +#endif + diff --git a/boost/interprocess/detail/file_wrapper.hpp b/boost/interprocess/detail/file_wrapper.hpp new file mode 100644 index 0000000000..7b53f36ac8 --- /dev/null +++ b/boost/interprocess/detail/file_wrapper.hpp @@ -0,0 +1,202 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP +#define BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +class file_wrapper +{ + /// @cond + BOOST_MOVABLE_BUT_NOT_COPYABLE(file_wrapper) + /// @endcond + public: + + //!Default constructor. + //!Represents an empty file_wrapper. + file_wrapper(); + + //!Creates a file object with name "name" and mode "mode", with the access mode "mode" + //!If the file previously exists, throws an error. + file_wrapper(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm); } + + //!Tries to create a file with name "name" and mode "mode", with the + //!access mode "mode". If the file previously exists, it tries to open it with mode "mode". + //!Otherwise throws an error. + file_wrapper(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm); } + + //!Tries to open a file with name "name", with the access mode "mode". + //!If the file does not previously exist, it throws an error. + file_wrapper(open_only_t, const char *name, mode_t mode) + { this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); } + + //!Moves the ownership of "moved"'s file to *this. + //!After the call, "moved" does not represent any file. + //!Does not throw + file_wrapper(BOOST_RV_REF(file_wrapper) moved) + : m_handle(file_handle_t(ipcdetail::invalid_file())) + { this->swap(moved); } + + //!Moves the ownership of "moved"'s file to *this. + //!After the call, "moved" does not represent any file. + //!Does not throw + file_wrapper &operator=(BOOST_RV_REF(file_wrapper) moved) + { + file_wrapper tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps to file_wrappers. + //!Does not throw + void swap(file_wrapper &other); + + //!Erases a file from the system. + //!Returns false on error. Never throws + static bool remove(const char *name); + + //!Sets the size of the file + void truncate(offset_t length); + + //!Closes the + //!file + ~file_wrapper(); + + //!Returns the name of the file + //!used in the constructor + const char *get_name() const; + + //!Returns the name of the file + //!used in the constructor + bool get_size(offset_t &size) const; + + //!Returns access mode + //!used in the constructor + mode_t get_mode() const; + + //!Get mapping handle + //!to use with mapped_region + mapping_handle_t get_mapping_handle() const; + + private: + //!Closes a previously opened file mapping. Never throws. + void priv_close(); + //!Closes a previously opened file mapping. Never throws. + bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm); + + file_handle_t m_handle; + mode_t m_mode; + std::string m_filename; +}; + +inline file_wrapper::file_wrapper() + : m_handle(file_handle_t(ipcdetail::invalid_file())) +{} + +inline file_wrapper::~file_wrapper() +{ this->priv_close(); } + +inline const char *file_wrapper::get_name() const +{ return m_filename.c_str(); } + +inline bool file_wrapper::get_size(offset_t &size) const +{ return get_file_size((file_handle_t)m_handle, size); } + +inline void file_wrapper::swap(file_wrapper &other) +{ + std::swap(m_handle, other.m_handle); + std::swap(m_mode, other.m_mode); + m_filename.swap(other.m_filename); +} + +inline mapping_handle_t file_wrapper::get_mapping_handle() const +{ return mapping_handle_from_file_handle(m_handle); } + +inline mode_t file_wrapper::get_mode() const +{ return m_mode; } + +inline bool file_wrapper::priv_open_or_create + (ipcdetail::create_enum_t type, + const char *filename, + mode_t mode, + const permissions &perm = permissions()) +{ + m_filename = filename; + + if(mode != read_only && mode != read_write){ + error_info err(mode_error); + throw interprocess_exception(err); + } + + //Open file existing native API to obtain the handle + switch(type){ + case ipcdetail::DoOpen: + m_handle = open_existing_file(filename, mode); + break; + case ipcdetail::DoCreate: + m_handle = create_new_file(filename, mode, perm); + break; + case ipcdetail::DoOpenOrCreate: + m_handle = create_or_open_file(filename, mode, perm); + break; + default: + { + error_info err = other_error; + throw interprocess_exception(err); + } + } + + //Check for error + if(m_handle == invalid_file()){ + throw interprocess_exception(error_info(system_error_code())); + } + + m_mode = mode; + return true; +} + +inline bool file_wrapper::remove(const char *filename) +{ return delete_file(filename); } + +inline void file_wrapper::truncate(offset_t length) +{ + if(!truncate_file(m_handle, length)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } +} + +inline void file_wrapper::priv_close() +{ + if(m_handle != invalid_file()){ + close_file(m_handle); + m_handle = invalid_file(); + } +} + +} //namespace ipcdetail{ +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP diff --git a/boost/interprocess/detail/in_place_interface.hpp b/boost/interprocess/detail/in_place_interface.hpp new file mode 100644 index 0000000000..0e69452a40 --- /dev/null +++ b/boost/interprocess/detail/in_place_interface.hpp @@ -0,0 +1,73 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP +#define BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include //typeid + +//!\file +//!Describes an abstract interface for placement construction and destruction. + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +struct in_place_interface +{ + in_place_interface(std::size_t alignm, std::size_t sz, const char *tname) + : alignment(alignm), size(sz), type_name(tname) + {} + + std::size_t alignment; + std::size_t size; + const char *type_name; + + virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) = 0; + virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed) = 0; + virtual ~in_place_interface(){} +}; + +template +struct placement_destroy : public in_place_interface +{ + placement_destroy() + : in_place_interface(::boost::alignment_of::value, sizeof(T), typeid(T).name()) + {} + + virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed) + { + T* memory = static_cast(mem); + for(destroyed = 0; destroyed < num; ++destroyed) + (memory++)->~T(); + } + + virtual void construct_n(void *, std::size_t, std::size_t &) {} + + private: + void destroy(void *mem) + { static_cast(mem)->~T(); } +}; + +} +} +} //namespace boost { namespace interprocess { namespace ipcdetail { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP diff --git a/boost/interprocess/detail/intermodule_singleton.hpp b/boost/interprocess/detail/intermodule_singleton.hpp new file mode 100644 index 0000000000..4bffbe9d4e --- /dev/null +++ b/boost/interprocess/detail/intermodule_singleton.hpp @@ -0,0 +1,1184 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_INTERMODULE_SINGLETON_HPP +#define BOOST_INTERPROCESS_INTERMODULE_SINGLETON_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include +#include + +#if defined(BOOST_INTERPROCESS_WINDOWS) +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_WINDOWS) +#include +#include + +#include +#else +#include +#include +#include +#endif + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +struct intermodule_singleton_mutex_family +{ + typedef boost::interprocess::ipcdetail::spin_mutex mutex_type; + typedef boost::interprocess::ipcdetail::spin_recursive_mutex recursive_mutex_type; +}; + +struct intermodule_types +{ + //We must use offset_ptr since a loaded DLL can map the singleton holder shared memory + //at a different address than other DLLs/main executables + typedef rbtree_best_fit > mem_algo; + template + struct open_or_create + { + typedef managed_open_or_create_impl + type; + }; +}; + +template +class basic_managed_global_memory + : public basic_managed_memory_impl + < char + , intermodule_types::mem_algo + , iset_index + , intermodule_types::open_or_create::type::ManagedOpenOrCreateUserOffset + > + , private intermodule_types::open_or_create::type +{ + /// @cond + typedef typename intermodule_types::template open_or_create::type base2_t; + + typedef basic_managed_memory_impl + < char + , intermodule_types::mem_algo + , iset_index + , base2_t::ManagedOpenOrCreateUserOffset + > base_t; + + typedef create_open_func create_open_func_t; + + basic_managed_global_memory *get_this_pointer() + { return this; } + + public: + typedef typename base_t::size_type size_type; + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_global_memory) + /// @endcond + + public: //functions +/* + basic_managed_global_memory() + {} + + basic_managed_global_memory(create_only_t create_only, const char *name, + size_type size, const void *addr = 0, const permissions& perm = permissions()) + : base_t() + , base2_t(create_only, name, size, read_write, addr, + create_open_func_t(get_this_pointer(), DoCreate), perm) + {} +*/ + basic_managed_global_memory (open_or_create_t open_or_create, + const char *name, size_type size, + const void *addr = 0, const permissions& perm = permissions()) + : base_t() + , base2_t(open_or_create, name, size, read_write, addr, + create_open_func_t(get_this_pointer(), + DoOpenOrCreate), perm) + {} + + basic_managed_global_memory (open_only_t open_only, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, read_write, addr, + create_open_func_t(get_this_pointer(), + DoOpen)) + {} + +/* + basic_managed_global_memory (open_copy_on_write_t, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, copy_on_write, addr, + create_open_func_t(get_this_pointer(), + DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager. + //!in read-only mode. + //!This can throw. + basic_managed_global_memory (open_read_only_t, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, read_only, addr, + create_open_func_t(get_this_pointer(), + DoOpen)) + {} + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_global_memory(BOOST_RV_REF(basic_managed_global_memory) moved) + { + basic_managed_global_memory tmp; + this->swap(moved); + tmp.swap(moved); + } + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_global_memory &operator=(BOOST_RV_REF(basic_managed_global_memory) moved) + { + basic_managed_global_memory tmp(boost::move(moved)); + this->swap(tmp); + return *this; + }*/ +}; + +#if defined(BOOST_INTERPROCESS_WINDOWS) +typedef basic_managed_global_memory windows_managed_global_memory; +#endif + +typedef basic_managed_global_memory managed_global_memory; + +namespace file_locking_helpers { + +inline void get_pid_creation_time_str(std::string &s) +{ + std::stringstream stream; + stream << get_current_process_id() << '_'; + stream.precision(6); + stream << std::fixed << get_current_process_creation_time(); + s = stream.str(); +} + +inline void create_tmp_subdir_and_get_pid_based_filepath(const char *subdir_name, const char *file_prefix, OS_process_id_t pid, std::string &s, bool creation_time = false) +{ + //Let's create a lock file for each process gmem that will mark if + //the process is alive or not + create_tmp_and_clean_old(s); + s += "/"; + s += subdir_name; + if(!open_or_create_directory(s.c_str())){ + throw interprocess_exception(error_info(system_error_code())); + } + s += "/"; + s += file_prefix; + if(creation_time){ + std::string sstamp; + get_pid_creation_time_str(sstamp); + s += sstamp; + } + else{ + pid_str_t pid_str; + get_pid_str(pid_str, pid); + s += pid_str; + } +} + +inline bool check_if_filename_complies_with_pid + (const char *filename, const char *prefix, OS_process_id_t pid, std::string &file_suffix, bool creation_time = false) +{ + //Check if filename complies with lock file name pattern + std::string fname(filename); + std::string fprefix(prefix); + if(fname.size() <= fprefix.size()){ + return false; + } + fname.resize(fprefix.size()); + if(fname != fprefix){ + return false; + } + + //If not our lock file, delete it if we can lock it + fname = filename; + fname.erase(0, fprefix.size()); + pid_str_t pid_str; + get_pid_str(pid_str, pid); + file_suffix = pid_str; + if(creation_time){ + std::size_t p = fname.find('_'); + if (p == std::string::npos){ + return false; + } + std::string save_suffix(fname); + fname.erase(p); + fname.swap(file_suffix); + bool ret = (file_suffix == fname); + file_suffix.swap(save_suffix); + return ret; + } + else{ + fname.swap(file_suffix); + return (file_suffix == fname); + } +} + +} //file_locking_helpers + +namespace intermodule_singleton_helpers { + +const int GMemMarkToBeRemoved = -1; +const int GMemNotPresent = -2; + +inline const char *get_lock_file_subdir_name() +{ return "gmem"; } + +inline const char *get_lock_file_base_name() +{ return "lck"; } + +inline void create_and_get_singleton_lock_file_path(std::string &s) +{ + file_locking_helpers::create_tmp_subdir_and_get_pid_based_filepath + (get_lock_file_subdir_name(), get_lock_file_base_name(), get_current_process_id(), s, true); +} + +inline const char *get_shm_base_name() +{ return "bip.gmem.shm."; } + +inline void get_shm_name(std::string &shm_name) +{ + file_locking_helpers::get_pid_creation_time_str(shm_name); + shm_name.insert(0, get_shm_base_name()); +} + +inline std::size_t get_shm_size() +{ return 65536; } + +template +struct managed_sh_dependant +{ + static void apply_gmem_erase_logic(const char *filepath, const char *filename); + + static bool remove_old_gmem() + { + std::string refcstrRootDirectory; + tmp_folder(refcstrRootDirectory); + refcstrRootDirectory += "/"; + refcstrRootDirectory += get_lock_file_subdir_name(); + return for_each_file_in_dir(refcstrRootDirectory.c_str(), apply_gmem_erase_logic); + } +}; + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +template<> +struct managed_sh_dependant +{ + static void apply_gmem_erase_logic(const char *, const char *){} + + static bool remove_old_gmem() + { return true; } +}; + + +struct locking_file_serial_id +{ + int fd; + unsigned long dwVolumeSerialNumber; + unsigned long nFileIndexHigh; + unsigned long nFileIndexLow; + //This reference count counts the number of modules attached + //to the shared memory and lock file. This serves to unlink + //the locking file and shared memory when all modules are + //done with the global memory (shared memory) + volatile boost::uint32_t modules_attached_to_gmem_count; +}; + +inline bool lock_locking_file(int fd) +{ + int ret = 0; + while(ret != 0 && errno == EDEADLK){ + ret = _locking(fd, _LK_LOCK, 1/*lock_file_contents_length()*/); + } + return 0 == ret; +} + +inline bool try_lock_locking_file(int fd) +{ + return 0 == _locking(fd, _LK_NBLCK , 1); +} + +inline int open_or_create_and_lock_file(const char *name) +{ + permissions p; + p.set_unrestricted(); + while(1){ + file_handle_t handle = create_or_open_file(name, read_write, p); + int fd = _open_osfhandle((intptr_t)handle, _O_TEXT); + if(fd < 0){ + close_file(handle); + return fd; + } + if(!try_lock_locking_file(fd)){ + _close(fd); + return -1; + } + struct _stat s; + if(0 == _stat(name, &s)){ + return fd; + } + else{ + _close(fd); + } + } +} + +inline int try_open_and_lock_file(const char *name) +{ + file_handle_t handle = open_existing_file(name, read_write); + int fd = _open_osfhandle((intptr_t)handle, _O_TEXT); + if(fd < 0){ + close_file(handle); + return fd; + } + if(!try_lock_locking_file(fd)){ + _close(fd); + return -1; + } + return fd; +} + +inline void close_lock_file(int fd) +{ _close(fd); } + +inline bool is_valid_fd(int fd) +{ + struct _stat s; + return EBADF != _fstat(fd, &s); +} + +inline bool is_normal_file(int fd) +{ + if(_isatty(fd)) + return false; + struct _stat s; + if(0 != _fstat(fd, &s)) + return false; + return 0 != (s.st_mode & _S_IFREG); +} + +inline std::size_t get_size(int fd) +{ + struct _stat s; + if(0 != _fstat(fd, &s)) + return 0u; + return (std::size_t)s.st_size; +} + +inline bool fill_file_serial_id(int fd, locking_file_serial_id &id) +{ + winapi::interprocess_by_handle_file_information info; + if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info)) + return false; + id.fd = fd; + id.dwVolumeSerialNumber = info.dwVolumeSerialNumber; + id.nFileIndexHigh = info.nFileIndexHigh; + id.nFileIndexLow = info.nFileIndexLow; + id.modules_attached_to_gmem_count = 1; //Initialize attached count + return true; +} + +inline bool compare_file_serial(int fd, const locking_file_serial_id &id) +{ + winapi::interprocess_by_handle_file_information info; + if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info)) + return false; + + return id.dwVolumeSerialNumber == info.dwVolumeSerialNumber && + id.nFileIndexHigh == info.nFileIndexHigh && + id.nFileIndexLow == info.nFileIndexLow; +} + +#else //UNIX + +struct locking_file_serial_id +{ + int fd; + dev_t st_dev; + ino_t st_ino; + //This reference count counts the number of modules attached + //to the shared memory and lock file. This serves to unlink + //the locking file and shared memory when all modules are + //done with the global memory (shared memory) + volatile boost::uint32_t modules_attached_to_gmem_count; +}; + +inline bool lock_locking_file(int fd) +{ + int ret = 0; + while(ret != 0 && errno != EINTR){ + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + ret = fcntl (fd, F_SETLKW, &lock); + } + return 0 == ret; +} + +inline bool try_lock_locking_file(int fd) +{ + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + return 0 == fcntl (fd, F_SETLK, &lock); +} + +inline int open_or_create_and_lock_file(const char *name) +{ + permissions p; + p.set_unrestricted(); + while(1){ + int fd = create_or_open_file(name, read_write, p); + if(fd < 0){ + return fd; + } + if(!try_lock_locking_file(fd)){ + close(fd); + return -1; + } + struct stat s; + if(0 == stat(name, &s)){ + return fd; + } + else{ + close(fd); + } + } +} + +inline int try_open_and_lock_file(const char *name) +{ + int fd = open_existing_file(name, read_write); + if(fd < 0){ + return fd; + } + if(!try_lock_locking_file(fd)){ + close(fd); + return -1; + } + return fd; +} + +inline void close_lock_file(int fd) +{ close(fd); } + +inline bool is_valid_fd(int fd) +{ + struct stat s; + return EBADF != fstat(fd, &s); +} + +inline bool is_normal_file(int fd) +{ + struct stat s; + if(0 != fstat(fd, &s)) + return false; + return 0 != (s.st_mode & S_IFREG); +} + +inline std::size_t get_size(int fd) +{ + struct stat s; + if(0 != fstat(fd, &s)) + return 0u; + return (std::size_t)s.st_size; +} + +inline bool fill_file_serial_id(int fd, locking_file_serial_id &id) +{ + struct stat s; + if(0 != fstat(fd, &s)) + return false; + id.fd = fd; + id.st_dev = s.st_dev; + id.st_ino = s.st_ino; + id.modules_attached_to_gmem_count = 1; //Initialize attached count + return true; +} + +inline bool compare_file_serial(int fd, const locking_file_serial_id &id) +{ + struct stat info; + if(0 != fstat(fd, &info)) + return false; + + return id.st_dev == info.st_dev && + id.st_ino == info.st_ino; +} + +#endif + +template +struct gmem_erase_func +{ + gmem_erase_func(const char *shm_name, const char *singleton_lock_file_path, ManagedShMem & shm) + :shm_name_(shm_name), singleton_lock_file_path_(singleton_lock_file_path), shm_(shm) + {} + + void operator()() + { + locking_file_serial_id *pserial_id = shm_.template find("lock_file_fd").first; + if(pserial_id){ + pserial_id->fd = GMemMarkToBeRemoved; + } + delete_file(singleton_lock_file_path_); + shared_memory_object::remove(shm_name_); + } + + const char * const shm_name_; + const char * const singleton_lock_file_path_; + ManagedShMem & shm_; +}; + +//This function applies shared memory erasure logic based on the passed lock file. +template +void managed_sh_dependant:: + apply_gmem_erase_logic(const char *filepath, const char *filename) +{ + int fd = GMemMarkToBeRemoved; + try{ + std::string str; + //If the filename is current process lock file, then avoid it + if(file_locking_helpers::check_if_filename_complies_with_pid + (filename, get_lock_file_base_name(), get_current_process_id(), str, true)){ + return; + } + //Open and lock the other process' lock file + fd = try_open_and_lock_file(filepath); + if(fd < 0){ + return; + } + //If done, then the process is dead so take global shared memory name + //(the name is based on the lock file name) and try to apply erasure logic + str.insert(0, get_shm_base_name()); + try{ + ManagedShMem shm(open_only, str.c_str()); + gmem_erase_func func(str.c_str(), filepath, shm); + shm.try_atomic_func(func); + } + catch(interprocess_exception &e){ + //If shared memory is not found erase the lock file + if(e.get_error_code() == not_found_error){ + delete_file(filepath); + } + } + } + catch(...){ + + } + if(fd >= 0){ + close_lock_file(fd); + } +} + +} //namespace intermodule_singleton_helpers { + + + +namespace intermodule_singleton_helpers { + +//The lock file logic creates uses a unique instance to a file +template +struct lock_file_logic +{ + lock_file_logic(ManagedShMem &shm) + : mshm(shm) + { shm.atomic_func(*this); } + + void operator()(void) + { + retry_with_new_shm = false; + + //First find the file locking descriptor id + locking_file_serial_id *pserial_id = + mshm.template find("lock_file_fd").first; + + int fd; + //If not found schedule a creation + if(!pserial_id){ + fd = GMemNotPresent; + } + //Else get it + else{ + fd = pserial_id->fd; + } + //If we need to create a new one, do it + if(fd == GMemNotPresent){ + std::string lck_str; + //Create a unique current pid based lock file path + create_and_get_singleton_lock_file_path(lck_str); + //Open or create and lock file + int fd = intermodule_singleton_helpers::open_or_create_and_lock_file(lck_str.c_str()); + //If failed, write a bad file descriptor to notify other modules that + //something was wrong and unlink shared memory. Mark the function object + //to tell caller to retry with another shared memory + if(fd < 0){ + this->register_lock_file(GMemMarkToBeRemoved); + std::string s; + get_shm_name(s); + shared_memory_object::remove(s.c_str()); + retry_with_new_shm = true; + } + //If successful, register the file descriptor + else{ + this->register_lock_file(fd); + } + } + //If the fd was invalid (maybe a previous try failed) notify caller that + //should retry creation logic, since this shm might have been already + //unlinked since the shm was removed + else if (fd == GMemMarkToBeRemoved){ + retry_with_new_shm = true; + } + //If the stored fd is not valid (a open fd, a normal file with the + //expected size, or does not have the same file id number, + //then it's an old shm from an old process with the same pid. + //If that's the case, mark it as invalid + else if(!is_valid_fd(fd) || + !is_normal_file(fd) || + 0 != get_size(fd) || + !compare_file_serial(fd, *pserial_id)){ + pserial_id->fd = GMemMarkToBeRemoved; + std::string s; + get_shm_name(s); + shared_memory_object::remove(s.c_str()); + retry_with_new_shm = true; + } + else{ + //If the lock file is ok, increment reference count of + //attached modules to shared memory + atomic_inc32(&pserial_id->modules_attached_to_gmem_count); + } + } + + private: + locking_file_serial_id * register_lock_file(int fd) + { + locking_file_serial_id *pinfo = mshm.template construct("lock_file_fd")(); + fill_file_serial_id(fd, *pinfo); + return pinfo; + } + + public: + ManagedShMem &mshm; + bool retry_with_new_shm; +}; + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +template<> +struct lock_file_logic +{ + lock_file_logic(windows_managed_global_memory &) + : retry_with_new_shm(false) + {} + + void operator()(void){} + const bool retry_with_new_shm; +}; + +#endif + +} //namespace intermodule_singleton_helpers { + +//This class contains common code for all singleton types, so that we instantiate this +//code just once per module. This class also holds a reference counted shared memory +//to be used by all instances + +template +class intermodule_singleton_common +{ + public: + typedef void*(singleton_constructor_t)(ManagedShMem &); + typedef void (singleton_destructor_t)(void *, ManagedShMem &); + + static const ::boost::uint32_t Uninitialized = 0u; + static const ::boost::uint32_t Initializing = 1u; + static const ::boost::uint32_t Initialized = 2u; + static const ::boost::uint32_t Broken = 3u; + + static void finalize_singleton_logic(void *ptr, singleton_destructor_t destructor) + { + if(ptr) + destructor(ptr, get_shm()); + //If this is the last singleton of this module + //apply shm destruction. + //Note: singletons are destroyed when the module is unloaded + //so no threads should be executing or holding references + //to this module + if(1 == atomic_dec32(&this_module_singleton_count)){ + destroy_shm(); + } + } + + static void initialize_singleton_logic + (void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_constructor_t ini_func); + + private: + static ManagedShMem &get_shm() + { + return *static_cast(static_cast(&mem_holder.shm_mem)); + } + + static void initialize_shm(); + static void destroy_shm(); + //Static data, zero-initalized without any dependencies + //this_module_singleton_count is the number of singletons used by this module + static volatile boost::uint32_t this_module_singleton_count; + //this_module_shm_initialized is the state of this module's shm class object + static volatile boost::uint32_t this_module_shm_initialized; + static struct mem_holder_t + { + ::boost::detail::max_align aligner; + char shm_mem [sizeof(ManagedShMem)]; + } mem_holder; +}; + +template +volatile boost::uint32_t intermodule_singleton_common::this_module_singleton_count; + +template +volatile boost::uint32_t intermodule_singleton_common::this_module_shm_initialized; + +template +typename intermodule_singleton_common::mem_holder_t + intermodule_singleton_common::mem_holder; + +template +void intermodule_singleton_common::initialize_shm() +{ + //Obtain unique shm name and size + std::string s; + while(1){ + //Try to pass shm state to initializing + ::boost::uint32_t tmp = atomic_cas32(&this_module_shm_initialized, Initializing, Uninitialized); + if(tmp >= Initialized){ + break; + } + //If some other thread is doing the work wait + else if(tmp == Initializing){ + thread_yield(); + } + else{ //(tmp == Uninitialized) + //If not initialized try it again? + try{ + //Remove old shared memory from the system + intermodule_singleton_helpers::managed_sh_dependant::remove_old_gmem(); + // + if(s.empty()){ + intermodule_singleton_helpers::get_shm_name(s); + } + const char *ShmName = s.c_str(); + const std::size_t ShmSize = intermodule_singleton_helpers::get_shm_size();; + + //in-place construction of the shared memory class + ::new (&get_shm())ManagedShMem(open_or_create, ShmName, ShmSize); + //Use shared memory internal lock to initialize the lock file + //that will mark this gmem as "in use". + intermodule_singleton_helpers::lock_file_logic f(get_shm()); + //If function failed (maybe a competing process has erased the shared + //memory between creation and file locking), retry with a new instance. + if(f.retry_with_new_shm){ + get_shm().~ManagedShMem(); + atomic_write32(&this_module_shm_initialized, Uninitialized); + } + else{ + //Locking succeeded, so this shared memory module-instance is ready + atomic_write32(&this_module_shm_initialized, Initialized); + break; + } + } + catch(...){ + // + throw; + } + } + } +} + +template +struct unlink_shmlogic +{ + unlink_shmlogic(ManagedShMem &mshm) + : mshm_(mshm) + { mshm.atomic_func(*this); } + void operator()() + { + intermodule_singleton_helpers::locking_file_serial_id *pserial_id = + mshm_.template find + ("lock_file_fd").first; + BOOST_ASSERT(0 != pserial_id); + if(1 == atomic_dec32(&pserial_id->modules_attached_to_gmem_count)){ + int fd = pserial_id->fd; + if(fd > 0){ + pserial_id->fd = intermodule_singleton_helpers::GMemMarkToBeRemoved; + std::string s; + intermodule_singleton_helpers::create_and_get_singleton_lock_file_path(s); + delete_file(s.c_str()); + intermodule_singleton_helpers::close_lock_file(fd); + intermodule_singleton_helpers::get_shm_name(s); + shared_memory_object::remove(s.c_str()); + } + } + } + ManagedShMem &mshm_; +}; + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +template<> +struct unlink_shmlogic +{ + unlink_shmlogic(windows_managed_global_memory &) + {} + void operator()(){} +}; + +#endif + + +template +void intermodule_singleton_common::destroy_shm() +{ + if(!atomic_read32(&this_module_singleton_count)){ + //This module is being unloaded, so destroy + //the shared memory object of this module + //and unlink the shared memory if it's the last + unlink_shmlogic f(get_shm()); + (get_shm()).~ManagedShMem(); + atomic_write32(&this_module_shm_initialized, Uninitialized); + //Do some cleanup for other processes old gmem instances + intermodule_singleton_helpers::managed_sh_dependant::remove_old_gmem(); + } +} + +//Initialize this_module_singleton_ptr, creates the shared memory if needed and also creates an unique +//opaque type in shared memory through a singleton_constructor_t function call, +//initializing the passed pointer to that unique instance. +// +//We have two concurrency types here. a)the shared memory/singleton creation must +//be safe between threads of this process but in different modules/dlls. b) +//the pointer to the singleton is per-module, so we have to protect this +//initization between threads of the same module. +// +//All static variables declared here are shared between inside a module +//so atomic operations will synchronize only threads of the same module. +template +void intermodule_singleton_common::initialize_singleton_logic + (void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_constructor_t constructor) +{ + //If current module is not initialized enter to lock free logic + if(atomic_read32(&this_module_singleton_initialized) != Initialized){ + //Now a single thread of the module will succeed in this CAS. + //trying to pass from Uninitialized to Initializing + ::boost::uint32_t previous_module_singleton_initialized = atomic_cas32 + (&this_module_singleton_initialized, Initializing, Uninitialized); + //If the thread succeeded the CAS (winner) it will compete with other + //winner threads from other modules to create the shared memory + if(previous_module_singleton_initialized == Uninitialized){ + try{ + //Now initialize shm, this function solves concurrency issues + //between threads of several modules + initialize_shm(); + //Increment the module reference count that reflects how many + //singletons this module holds, so that we can safely destroy + //module shared memory object when no singleton is left + atomic_inc32(&this_module_singleton_count); + //Now try to create the singleton in shared memory. + //This function solves concurrency issues + //between threads of several modules + void *tmp = constructor(get_shm()); + //Insert a barrier before assigning the pointer to + //make sure this assignment comes after the initialization + atomic_write32(&this_module_singleton_initialized, Initializing); + //Assign the singleton address to the module-local pointer + ptr = tmp; + //Memory barrier inserted, all previous operations should complete + //before this one. Now marked as initialized + atomic_inc32(&this_module_singleton_initialized); + } + catch(...){ + //Mark singleton failed to initialize + atomic_write32(&this_module_singleton_initialized, Broken); + throw; + } + } + //If previous state was initializing, this means that another winner thread is + //trying to initialize the singleton. Just wait until completes its work. + else if(previous_module_singleton_initialized == Initializing){ + while(1){ + previous_module_singleton_initialized = atomic_read32(&this_module_singleton_initialized); + if(previous_module_singleton_initialized >= Initialized){ + //Already initialized, or exception thrown by initializer thread + break; + } + else if(previous_module_singleton_initialized == Initializing){ + thread_yield(); + } + else{ + //This can't be happening! + BOOST_ASSERT(0); + } + } + } + else if(previous_module_singleton_initialized == Initialized){ + //Nothing to do here, the singleton is ready + } + //If previous state was greater than initialized, then memory is broken + //trying to initialize the singleton. + else{//(previous_module_singleton_initialized > Initialized) + throw interprocess_exception("boost::interprocess::intermodule_singleton initialization failed"); + } + } + BOOST_ASSERT(ptr != 0); +} + +//Now this class is a singleton, initializing the singleton in +//the first get() function call if LazyInit is false. If true +//then the singleton will be initialized when loading the module. +template +class intermodule_singleton_impl +{ + public: + static C& get() //Let's make inlining easy + { + if(!this_module_singleton_ptr){ + if(lifetime.dummy_function()) //This forces lifetime instantiation, for reference counted destruction + intermodule_singleton_common::initialize_singleton_logic + (this_module_singleton_ptr, this_module_singleton_initialized, singleton_constructor); + } + return *static_cast(this_module_singleton_ptr); + } + + private: + + struct ref_count_ptr + { + ref_count_ptr(C *p, boost::uint32_t count) + : ptr(p), singleton_ref_count(count) + {} + C *ptr; + //This reference count serves to count the number of attached + //modules to this singleton + volatile boost::uint32_t singleton_ref_count; + }; + + //These statics will be zero-initialized without any constructor call dependency + //this_module_singleton_ptr will be a module-local pointer to the singleton + static void* this_module_singleton_ptr; + //this_module_singleton_count will be used to synchronize threads of the same module + //for access to a singleton instance, and to flag the state of the + //singleton. + static volatile boost::uint32_t this_module_singleton_initialized; + + //This class destructor will trigger singleton destruction + struct lifetime_type_lazy + { + bool dummy_function() + { return m_dummy == 0; } + + ~lifetime_type_lazy() + { + intermodule_singleton_common::finalize_singleton_logic + (this_module_singleton_ptr, singleton_destructor); + } + //Dummy volatile so that the compiler can't resolve its value at compile-time + //and can't avoid lifetime_type instantiation if dummy_function() is called. + static volatile int m_dummy; + }; + + struct lifetime_type_static + : public lifetime_type_lazy + { + lifetime_type_static() + { + intermodule_singleton_common::initialize_singleton_logic + (this_module_singleton_ptr, this_module_singleton_initialized, singleton_constructor); + } + }; + + typedef typename if_c + ::type lifetime_type; + + static lifetime_type lifetime; + + //A functor to be executed inside shared memory lock that just + //searches for the singleton in shm and if not present creates a new one. + //If singleton constructor throws, the exception is propagated + struct init_atomic_func + { + init_atomic_func(ManagedShMem &m) + : mshm(m) + {} + + void operator()() + { + ref_count_ptr *rcount = mshm.template find(unique_instance).first; + if(!rcount){ + C *p = new C(); + try{ + rcount = mshm.template construct(unique_instance)(p, 0u); + } + catch(...){ + delete p; + throw; + } + } + atomic_inc32(&rcount->singleton_ref_count); + ret_ptr = rcount->ptr; + } + ManagedShMem &mshm; + void *ret_ptr; + }; + + //A functor to be executed inside shared memory lock that just + //deletes the singleton in shm if the attached count reaches to zero + struct fini_atomic_func + { + fini_atomic_func(ManagedShMem &m) + : mshm(m) + {} + + void operator()() + { + ref_count_ptr *rcount = mshm.template find(unique_instance).first; + //The object must exist + BOOST_ASSERT(rcount); + //Check if last reference + if(atomic_dec32(&rcount->singleton_ref_count) == 1){ + //If last, destroy the object + BOOST_ASSERT(rcount->ptr != 0); + delete rcount->ptr; + //Now destroy shm entry + bool destroyed = mshm.template destroy(unique_instance); + (void)destroyed; BOOST_ASSERT(destroyed == true); + } + } + ManagedShMem &mshm; + void *ret_ptr; + }; + + //A wrapper to execute init_atomic_func + static void *singleton_constructor(ManagedShMem &mshm) + { + init_atomic_func f(mshm); + mshm.atomic_func(f); + return f.ret_ptr; + } + + //A wrapper to execute fini_atomic_func + static void singleton_destructor(void *p, ManagedShMem &mshm) + { (void)p; + fini_atomic_func f(mshm); + mshm.atomic_func(f); + } +}; + +template +volatile int intermodule_singleton_impl::lifetime_type_lazy::m_dummy = 0; + +//These will be zero-initialized by the loader +template +void *intermodule_singleton_impl::this_module_singleton_ptr = 0; + +template +volatile boost::uint32_t intermodule_singleton_impl::this_module_singleton_initialized = 0; + +template +typename intermodule_singleton_impl::lifetime_type + intermodule_singleton_impl::lifetime; + +template +class portable_intermodule_singleton + : public intermodule_singleton_impl +{}; + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +template +class windows_intermodule_singleton + : public intermodule_singleton_impl + < C + , LazyInit + , windows_managed_global_memory + > +{}; + +#endif + +//Now this class is a singleton, initializing the singleton in +//the first get() function call if LazyInit is false. If true +//then the singleton will be initialized when loading the module. +template +class intermodule_singleton + #ifdef BOOST_INTERPROCESS_WINDOWS + : public windows_intermodule_singleton + #else + : public portable_intermodule_singleton + #endif +{}; + + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif diff --git a/boost/interprocess/detail/interprocess_tester.hpp b/boost/interprocess/detail/interprocess_tester.hpp new file mode 100644 index 0000000000..2581776745 --- /dev/null +++ b/boost/interprocess/detail/interprocess_tester.hpp @@ -0,0 +1,31 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at 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 + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +class interprocess_tester +{ + public: + template + 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 + diff --git a/boost/interprocess/detail/intersegment_ptr.hpp b/boost/interprocess/detail/intersegment_ptr.hpp new file mode 100644 index 0000000000..92970923d0 --- /dev/null +++ b/boost/interprocess/detail/intersegment_ptr.hpp @@ -0,0 +1,1040 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP +#define BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include //vector +#include //set +#include +#include +#include +#include +#include //BOOST_STATIC_ASSERT +#include //CHAR_BIT +#include +#include //BOOST_ASSERT +#include + +//!\file +//! +namespace boost { + +//Predeclarations +template +struct has_trivial_constructor; + +template +struct has_trivial_destructor; + +namespace interprocess { + +template +struct is_multisegment_ptr; + +struct intersegment_base +{ + typedef intersegment_base self_t; + BOOST_STATIC_ASSERT((sizeof(std::size_t) == sizeof(void*))); + BOOST_STATIC_ASSERT((sizeof(void*)*CHAR_BIT == 32 || sizeof(void*)*CHAR_BIT == 64)); + static const std::size_t size_t_bits = (sizeof(void*)*CHAR_BIT == 32) ? 32 : 64; + static const std::size_t ctrl_bits = 2; + static const std::size_t align_bits = 12; + static const std::size_t align = std::size_t(1) << align_bits; + static const std::size_t max_segment_size_bits = size_t_bits - 2; + static const std::size_t max_segment_size = std::size_t(1) << max_segment_size_bits; + + static const std::size_t begin_bits = max_segment_size_bits - align_bits; + static const std::size_t pow_size_bits_helper = static_log2::value; + static const std::size_t pow_size_bits = + (max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ? + pow_size_bits_helper : pow_size_bits_helper + 1; + static const std::size_t frc_size_bits = + size_t_bits - ctrl_bits - begin_bits - pow_size_bits; + + BOOST_STATIC_ASSERT(((size_t_bits - pow_size_bits - frc_size_bits) >= ctrl_bits )); + + static const std::size_t relative_size_bits = + size_t_bits - max_segment_size_bits - ctrl_bits; + + static const std::size_t is_pointee_outside = 0; + static const std::size_t is_in_stack = 1; + static const std::size_t is_relative = 2; + static const std::size_t is_segmented = 3; + static const std::size_t is_max_mode = 4; + + intersegment_base() + { + this->set_mode(is_pointee_outside); + this->set_null(); + } + + struct relative_addressing + { + std::size_t ctrl : 2; + std::size_t pow : pow_size_bits; + std::size_t frc : frc_size_bits; + std::size_t beg : begin_bits; + std::ptrdiff_t off : sizeof(std::ptrdiff_t)*CHAR_BIT - 2; + std::ptrdiff_t bits : 2; + }; + + struct direct_addressing + { + std::size_t ctrl : 2; + std::size_t dummy : sizeof(std::size_t)*CHAR_BIT - 2; + void * addr; + }; + + struct segmented_addressing + { + std::size_t ctrl : 2; + std::size_t segment : sizeof(std::size_t)*CHAR_BIT - 2; + std::size_t off : sizeof(std::size_t)*CHAR_BIT - 2; + std::size_t bits : 2; + }; + + union members_t{ + relative_addressing relative; + direct_addressing direct; + segmented_addressing segmented; + } members; + + BOOST_STATIC_ASSERT(sizeof(members_t) == 2*sizeof(std::size_t)); + + void *relative_calculate_begin_addr() const + { + const std::size_t mask = ~(align - 1); + std::size_t beg = this->members.relative.beg; + return reinterpret_cast((((std::size_t)this) & mask) - (beg << align_bits)); + } + + void relative_set_begin_from_base(void *addr) + { + BOOST_ASSERT(addr < static_cast(this)); + std::size_t off = reinterpret_cast(this) - reinterpret_cast(addr); + members.relative.beg = off >> align_bits; + } + + //!Obtains the address pointed by the + //!object + std::size_t relative_size() const + { + std::size_t pow = members.relative.pow; + std::size_t size = (std::size_t(1u) << pow); + BOOST_ASSERT(pow >= frc_size_bits); + size |= members.relative.frc << (pow - frc_size_bits); + return size; + } + + static std::size_t calculate_size(std::size_t orig_size, std::size_t &pow, std::size_t &frc) + { + if(orig_size < align) + orig_size = align; + orig_size = ipcdetail::get_rounded_size_po2(orig_size, align); + pow = ipcdetail::floor_log2(orig_size); + std::size_t low_size = (std::size_t(1) << pow); + std::size_t diff = orig_size - low_size; + BOOST_ASSERT(pow >= frc_size_bits); + std::size_t rounded = ipcdetail::get_rounded_size_po2 + (diff, (std::size_t)(1u << (pow - frc_size_bits))); + if(rounded == low_size){ + ++pow; + frc = 0; + rounded = 0; + } + else{ + frc = rounded >> (pow - frc_size_bits); + } + BOOST_ASSERT(((frc << (pow - frc_size_bits)) & (align-1))==0); + return low_size + rounded; + } + + std::size_t get_mode()const + { return members.direct.ctrl; } + + void set_mode(std::size_t mode) + { + BOOST_ASSERT(mode < is_max_mode); + members.direct.ctrl = mode; + } + + //!Returns true if object represents + //!null pointer + bool is_null() const + { + return (this->get_mode() < is_relative) && + !members.direct.dummy && + !members.direct.addr; + } + + //!Sets the object to represent + //!the null pointer + void set_null() + { + if(this->get_mode() >= is_relative){ + this->set_mode(is_pointee_outside); + } + members.direct.dummy = 0; + members.direct.addr = 0; + } + + static std::size_t round_size(std::size_t orig_size) + { + std::size_t pow, frc; + return calculate_size(orig_size, pow, frc); + } +}; + + + +//!Configures intersegment_ptr with the capability to address: +//!2^(sizeof(std::size_t)*CHAR_BIT/2) segment groups +//!2^(sizeof(std::size_t)*CHAR_BIT/2) segments per group. +//!2^(sizeof(std::size_t)*CHAR_BIT/2)-1 bytes maximum per segment. +//!The mapping is implemented through flat_maps synchronized with mutexes. +template +struct flat_map_intersegment + : public intersegment_base +{ + typedef flat_map_intersegment self_t; + + void set_from_pointer(const volatile void *ptr) + { this->set_from_pointer(const_cast(ptr)); } + + //!Obtains the address pointed + //!by the object + void *to_raw_pointer() const + { + if(is_null()){ + return 0; + } + switch(this->get_mode()){ + case is_relative: + return const_cast(reinterpret_cast(this)) + members.relative.off; + break; + case is_segmented: + { + segment_info_t segment_info; + std::size_t offset; + void *this_base; + get_segment_info_and_offset(this, segment_info, offset, this_base); + char *base = static_cast(segment_info.group->address_of(this->members.segmented.segment)); + return base + this->members.segmented.off; + } + break; + case is_in_stack: + case is_pointee_outside: + return members.direct.addr; + break; + default: + return 0; + break; + } + } + + //!Calculates the distance between two basic_intersegment_ptr-s. + //!This only works with two basic_intersegment_ptr pointing + //!to the same segment. Otherwise undefined + std::ptrdiff_t diff(const self_t &other) const + { return static_cast(this->to_raw_pointer()) - static_cast(other.to_raw_pointer()); } + + //!Returns true if both point to + //!the same object + bool equal(const self_t &y) const + { return this->to_raw_pointer() == y.to_raw_pointer(); } + + //!Returns true if *this is less than other. + //!This only works with two basic_intersegment_ptr pointing + //!to the same segment group. Otherwise undefined. Never throws + bool less(const self_t &y) const + { return this->to_raw_pointer() < y.to_raw_pointer(); } + + void swap(self_t &other) + { + void *ptr_this = this->to_raw_pointer(); + void *ptr_other = other.to_raw_pointer(); + other.set_from_pointer(ptr_this); + this->set_from_pointer(ptr_other); + } + + //!Sets the object internals to represent the + //!address pointed by ptr + void set_from_pointer(const void *ptr) + { + if(!ptr){ + this->set_null(); + return; + } + + std::size_t mode = this->get_mode(); + if(mode == is_in_stack){ + members.direct.addr = const_cast(ptr); + return; + } + if(mode == is_relative){ + char *beg_addr = static_cast(this->relative_calculate_begin_addr()); + std::size_t seg_size = this->relative_size(); + if(ptr >= beg_addr && ptr < (beg_addr + seg_size)){ + members.relative.off = static_cast(ptr) - reinterpret_cast(this); + return; + } + } + std::size_t ptr_offset; + std::size_t this_offset; + segment_info_t ptr_info; + segment_info_t this_info; + void *ptr_base; + void *this_base; + get_segment_info_and_offset(this, this_info, this_offset, this_base); + + if(!this_info.group){ + this->set_mode(is_in_stack); + this->members.direct.addr = const_cast(ptr); + } + else{ + get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base); + + if(ptr_info.group != this_info.group){ + this->set_mode(is_pointee_outside); + this->members.direct.addr = const_cast(ptr); + } + else if(ptr_info.id == this_info.id){ + this->set_mode(is_relative); + members.relative.off = (static_cast(ptr) - reinterpret_cast(this)); + this->relative_set_begin_from_base(this_base); + std::size_t pow, frc; + std::size_t s = calculate_size(this_info.size, pow, frc); + (void)s; + BOOST_ASSERT(this_info.size == s); + this->members.relative.pow = pow; + this->members.relative.frc = frc; + } + else{ + this->set_mode(is_segmented); + this->members.segmented.segment = ptr_info.id; + this->members.segmented.off = ptr_offset; + } + } + } + + //!Sets the object internals to represent the address pointed + //!by another flat_map_intersegment + void set_from_other(const self_t &other) + { + this->set_from_pointer(other.to_raw_pointer()); + } + + //!Increments internal + //!offset + void inc_offset(std::ptrdiff_t bytes) + { + this->set_from_pointer(static_cast(this->to_raw_pointer()) + bytes); + } + + //!Decrements internal + //!offset + void dec_offset(std::ptrdiff_t bytes) + { + this->set_from_pointer(static_cast(this->to_raw_pointer()) - bytes); + } + + ////////////////////////////////////// + ////////////////////////////////////// + ////////////////////////////////////// + + flat_map_intersegment() + : intersegment_base() + {} + + ~flat_map_intersegment() + {} + + private: + + class segment_group_t + { + struct segment_data + { + void *addr; + std::size_t size; + }; + vector m_segments; + multi_segment_services &m_ms_services; + + public: + segment_group_t(multi_segment_services &ms_services) + : m_ms_services(ms_services) + {} + + void push_back(void *addr, std::size_t size) + { + segment_data d = { addr, size }; + m_segments.push_back(d); + } + + void pop_back() + { + BOOST_ASSERT(!m_segments.empty()); + m_segments.erase(--m_segments.end()); + } + + + void *address_of(std::size_t segment_id) + { + BOOST_ASSERT(segment_id < (std::size_t)m_segments.size()); + return m_segments[segment_id].addr; + } + + void clear_segments() + { m_segments.clear(); } + + std::size_t get_size() const + { return m_segments.size(); } + + multi_segment_services &get_multi_segment_services() const + { return m_ms_services; } + + friend bool operator< (const segment_group_t&l, const segment_group_t &r) + { return &l.m_ms_services < &r.m_ms_services; } + }; + + struct segment_info_t + { + std::size_t size; + std::size_t id; + segment_group_t *group; + segment_info_t() + : size(0), id(0), group(0) + {} + }; + + typedef set segment_groups_t; + + typedef boost::interprocess::flat_map + > ptr_to_segment_info_t; + + struct mappings_t : Mutex + { + //!Mutex to preserve integrity in multi-threaded + //!enviroments + typedef Mutex mutex_type; + //!Maps base addresses and segment information + //!(size and segment group and id)* + + ptr_to_segment_info_t m_ptr_to_segment_info; + + ~mappings_t() + { + //Check that all mappings have been erased + BOOST_ASSERT(m_ptr_to_segment_info.empty()); + } + }; + + //Static members + static mappings_t s_map; + static segment_groups_t s_groups; + public: + + typedef segment_group_t* segment_group_id; + + //!Returns the segment and offset + //!of an address + static void get_segment_info_and_offset(const void *ptr, segment_info_t &segment, std::size_t &offset, void *&base) + { + //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + base = 0; + if(s_map.m_ptr_to_segment_info.empty()){ + segment = segment_info_t(); + offset = reinterpret_cast(ptr) - static_cast(0); + return; + } + //Find the first base address greater than ptr + typename ptr_to_segment_info_t::iterator it + = s_map.m_ptr_to_segment_info.upper_bound(ptr); + if(it == s_map.m_ptr_to_segment_info.begin()){ + segment = segment_info_t(); + offset = reinterpret_cast(ptr) - static_cast(0); + } + //Go to the previous one + --it; + char * segment_base = const_cast(reinterpret_cast(it->first)); + std::size_t segment_size = it->second.size; + + if(segment_base <= reinterpret_cast(ptr) && + (segment_base + segment_size) >= reinterpret_cast(ptr)){ + segment = it->second; + offset = reinterpret_cast(ptr) - segment_base; + base = segment_base; + } + else{ + segment = segment_info_t(); + offset = reinterpret_cast(ptr) - static_cast(0); + } + } + + //!Associates a segment defined by group/id with a base address and size. + //!Returns false if the group is not found or there is an error + static void insert_mapping(segment_group_id group_id, void *ptr, std::size_t size) + { + //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + + typedef typename ptr_to_segment_info_t::value_type value_type; + typedef typename ptr_to_segment_info_t::iterator iterator; + typedef std::pair it_b_t; + + segment_info_t info; + info.group = group_id; + info.size = size; + info.id = group_id->get_size(); + + it_b_t ret = s_map.m_ptr_to_segment_info.insert(value_type(ptr, info)); + BOOST_ASSERT(ret.second); + + value_eraser v_eraser(s_map.m_ptr_to_segment_info, ret.first); + group_id->push_back(ptr, size); + v_eraser.release(); + } + + static bool erase_last_mapping(segment_group_id group_id) + { + //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + if(!group_id->get_size()){ + return false; + } + else{ + void *addr = group_id->address_of(group_id->get_size()-1); + group_id->pop_back(); + std::size_t erased = s_map.m_ptr_to_segment_info.erase(addr); + (void)erased; + BOOST_ASSERT(erased); + return true; + } + } + + static segment_group_id new_segment_group(multi_segment_services *services) + { + { //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + typedef typename segment_groups_t::iterator iterator; + std::pair ret = + s_groups.insert(segment_group_t(*services)); + BOOST_ASSERT(ret.second); + return &*ret.first; + } + } + + static bool delete_group(segment_group_id id) + { + { //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + bool success = 1u == s_groups.erase(segment_group_t(*id)); + if(success){ + typedef typename ptr_to_segment_info_t::iterator ptr_to_segment_info_it; + ptr_to_segment_info_it it(s_map.m_ptr_to_segment_info.begin()); + while(it != s_map.m_ptr_to_segment_info.end()){ + if(it->second.group == id){ + it = s_map.m_ptr_to_segment_info.erase(it); + } + else{ + ++it; + } + } + } + return success; + } + } +}; + +//!Static map-segment_info associated with +//!flat_map_intersegment<> +template +typename flat_map_intersegment::mappings_t + flat_map_intersegment::s_map; + +//!Static segment group container associated with +//!flat_map_intersegment<> +template +typename flat_map_intersegment::segment_groups_t + flat_map_intersegment::s_groups; + +//!A smart pointer that can point to a pointee that resides in another memory +//!memory mapped or shared memory segment. +template +class intersegment_ptr : public flat_map_intersegment +{ + typedef flat_map_intersegment PT; + typedef intersegment_ptr self_t; + typedef PT base_t; + + void unspecified_bool_type_func() const {} + typedef void (self_t::*unspecified_bool_type)() const; + + public: + typedef T * pointer; + typedef typename ipcdetail::add_reference::type reference; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + + public: //Public Functions + + //!Constructor from raw pointer (allows "0" pointer conversion). + //!Never throws. + intersegment_ptr(pointer ptr = 0) + { base_t::set_from_pointer(ptr); } + + //!Constructor from other pointer. + //!Never throws. + template + intersegment_ptr(U *ptr){ base_t::set_from_pointer(pointer(ptr)); } + + //!Constructor from other intersegment_ptr + //!Never throws + intersegment_ptr(const intersegment_ptr& ptr) + { base_t::set_from_other(ptr); } + + //!Constructor from other intersegment_ptr. If pointers of pointee types are + //!convertible, intersegment_ptrs will be convertibles. Never throws. + template + intersegment_ptr(const intersegment_ptr &ptr) + { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); } + + //!Emulates static_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, ipcdetail::static_cast_tag) + { base_t::set_from_pointer(static_cast(r.get())); } + + //!Emulates const_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, ipcdetail::const_cast_tag) + { base_t::set_from_pointer(const_cast(r.get())); } + + //!Emulates dynamic_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, ipcdetail::dynamic_cast_tag) + { base_t::set_from_pointer(dynamic_cast(r.get())); } + + //!Emulates reinterpret_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, ipcdetail::reinterpret_cast_tag) + { base_t::set_from_pointer(reinterpret_cast(r.get())); } + + //!Obtains raw pointer from offset. + //!Never throws. + pointer get()const + { return static_cast(base_t::to_raw_pointer()); } + + //!Pointer-like -> operator. It can return 0 pointer. + //!Never throws. + pointer operator->() const + { return self_t::get(); } + + //!Dereferencing operator, if it is a null intersegment_ptr behavior + //!is undefined. Never throws. + reference operator* () const + { return *(self_t::get()); } + + //!Indexing operator. + //!Never throws. + reference operator[](std::ptrdiff_t idx) const + { return self_t::get()[idx]; } + + //!Assignment from pointer (saves extra conversion). + //!Never throws. + intersegment_ptr& operator= (pointer from) + { base_t::set_from_pointer(from); return *this; } + + //!Assignment from other intersegment_ptr. + //!Never throws. + intersegment_ptr& operator= (const intersegment_ptr &ptr) + { base_t::set_from_other(ptr); return *this; } + + //!Assignment from related intersegment_ptr. If pointers of pointee types + //!are assignable, intersegment_ptrs will be assignable. Never throws. + template + intersegment_ptr& operator= (const intersegment_ptr & ptr) + { + pointer p(ptr.get()); (void)p; + base_t::set_from_other(ptr); return *this; + } + + //!intersegment_ptr + std::ptrdiff_t. + //!Never throws. + intersegment_ptr operator+ (std::ptrdiff_t idx) const + { + intersegment_ptr result (*this); + result.inc_offset(idx*sizeof(T)); + return result; + } + + //!intersegment_ptr - std::ptrdiff_t. + //!Never throws. + intersegment_ptr operator- (std::ptrdiff_t idx) const + { + intersegment_ptr result (*this); + result.dec_offset(idx*sizeof(T)); + return result; + } + + //!intersegment_ptr += std::ptrdiff_t. + //!Never throws. + intersegment_ptr &operator+= (std::ptrdiff_t offset) + { base_t::inc_offset(offset*sizeof(T)); return *this; } + + //!intersegment_ptr -= std::ptrdiff_t. + //!Never throws. + intersegment_ptr &operator-= (std::ptrdiff_t offset) + { base_t::dec_offset(offset*sizeof(T)); return *this; } + + //!++intersegment_ptr. + //!Never throws. + intersegment_ptr& operator++ (void) + { base_t::inc_offset(sizeof(T)); return *this; } + + //!intersegment_ptr++. + //!Never throws. + intersegment_ptr operator++ (int) + { intersegment_ptr temp(*this); ++*this; return temp; } + + //!--intersegment_ptr. + //!Never throws. + intersegment_ptr& operator-- (void) + { base_t::dec_offset(sizeof(T)); return *this; } + + //!intersegment_ptr--. + //!Never throws. + intersegment_ptr operator-- (int) + { intersegment_ptr temp(*this); --*this; return temp; } + + //!Safe bool conversion operator. + //!Never throws. + operator unspecified_bool_type() const + { return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func; } + + //!Not operator. Not needed in theory, but improves portability. + //!Never throws. + bool operator! () const + { return base_t::is_null(); } + + //!Swaps two intersegment_ptr-s. More efficient than std::swap. + //!Never throws. + void swap(intersegment_ptr &other) + { base_t::swap(other); } + + //!Calculates the distance between two intersegment_ptr-s. + //!This only works with two basic_intersegment_ptr pointing + //!to the same segment. Otherwise undefined + template + std::ptrdiff_t _diff(const intersegment_ptr &other) const + { return base_t::diff(other); } + + //!Returns true if both point to the + //!same object + template + bool _equal(const intersegment_ptr&other) const + { return base_t::equal(other); } + + //!Returns true if *this is less than other. + //!This only works with two basic_intersegment_ptr pointing + //!to the same segment group. Otherwise undefined. Never throws + template + bool _less(const intersegment_ptr &other) const + { return base_t::less(other); } +}; + +//!Compares the equality of two intersegment_ptr-s. +//!Never throws. +template inline +bool operator ==(const intersegment_ptr &left, + const intersegment_ptr &right) +{ + //Make sure both pointers can be compared + bool e = typename intersegment_ptr::pointer(0) == + typename intersegment_ptr::pointer(0); + (void)e; + return left._equal(right); +} + +//!Returns true if *this is less than other. +//!This only works with two basic_intersegment_ptr pointing +//!to the same segment group. Otherwise undefined. Never throws +template inline +bool operator <(const intersegment_ptr &left, + const intersegment_ptr &right) +{ + //Make sure both pointers can be compared + bool e = typename intersegment_ptr::pointer(0) < + typename intersegment_ptr::pointer(0); + (void)e; + return left._less(right); +} + +template inline +bool operator!= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 ==pt2); } + +//!intersegment_ptr <= intersegment_ptr. +//!Never throws. +template inline +bool operator<= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 > pt2); } + +//!intersegment_ptr > intersegment_ptr. +//!Never throws. +template inline +bool operator> (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return (pt2 < pt1); } + +//!intersegment_ptr >= intersegment_ptr. +//!Never throws. +template inline +bool operator>= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 < pt2); } + +//!operator<< +template inline +std::basic_ostream & operator<< + (std::basic_ostream & os, const intersegment_ptr & p) +{ return os << p.get(); } + +//!operator>> +template inline +std::basic_istream & operator>> + (std::basic_istream & os, intersegment_ptr & p) +{ U * tmp; return os >> tmp; p = tmp; } + +//!std::ptrdiff_t + intersegment_ptr. +//!The result is another pointer of the same segment +template inline +intersegment_ptr operator+ + (std::ptrdiff_t diff, const intersegment_ptr& right) +{ return right + diff; } + +//!intersegment_ptr - intersegment_ptr. +//!This only works with two intersegment_ptr-s that point to the +//!same segment +template inline +std::ptrdiff_t operator- (const intersegment_ptr &pt, + const intersegment_ptr &pt2) +{ return pt._diff(pt2)/sizeof(T); } + +//! swap specialization +template inline +void swap (boost::interprocess::intersegment_ptr &pt, + boost::interprocess::intersegment_ptr &pt2) +{ pt.swap(pt2); } + +//!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr. +//!Never throws. +template inline +T * to_raw_pointer(boost::interprocess::intersegment_ptr const & p) +{ return p.get(); } + +//!Simulation of static_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr static_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::ipcdetail::static_cast_tag()); } + +//!Simulation of const_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr const_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::ipcdetail::const_cast_tag()); } + +//!Simulation of dynamic_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr dynamic_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::ipcdetail::dynamic_cast_tag()); } + +//!Simulation of reinterpret_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::ipcdetail::reinterpret_cast_tag()); } + +//!Trait class to detect if an smart pointer has +//!multi-segment addressing capabilities. +template +struct is_multisegment_ptr + > +{ + static const bool value = true; +}; + +} //namespace interprocess { + +#if defined(_MSC_VER) && (_MSC_VER < 1400) +//!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr. +//!Never throws. +template inline +T * to_raw_pointer(boost::interprocess::intersegment_ptr const & p) +{ return p.get(); } +#endif + +//!has_trivial_constructor<> == true_type specialization +//!for optimizations +template +struct has_trivial_constructor + < boost::interprocess::intersegment_ptr > + : public true_type{}; + +//!has_trivial_destructor<> == true_type specialization +//!for optimizations +template +struct has_trivial_destructor + < boost::interprocess::intersegment_ptr > + : public true_type{}; + +} //namespace boost { + +#if 0 + +//bits +//-> is_segmented +//-> is_relative +//-> is_in_stack +//-> is_pointee_outside + +//Data + + + + +//segmented: +// +// std::size_t ctrl : CTRL_BITS; +// std::size_t segment : MAX_SEGMENT_BITS; +// std::size_t offset; + +//RELATIVE_SIZE_BITS = SIZE_T_BITS - +// MAX_SEGMENT_BITS - +// CTRL_BITS 10 10 +//MAX_SEGMENT_SIZE = SIZE_T_BITS - ALIGN_BITS 20 52 + +//SIZE_T_BITS - 1 - ALIGN_BITS 19 51 +//POW_SIZE_BITS = upper_log2 +// (SIZE_T_BITS - 1 - ALIGN_BITS) 5 6 +//FRC_SIZE_BITS = SIZE_T_BITS - CTRL_BITS +// MAX_SEGMENT_SIZE_ALIGNBITS - POW_SIZE_BITS 6 5 + +//relative: +// +// std::size_t ctrl : CTRL_BITS; 2 2 +// std::size_t size_pow : POW_SIZE_BITS 5 6 +// std::size_t size_frc : FRC_SIZE_BITS; 6 5 +// std::size_t start : MAX_SEGMENT_SIZE_ALIGNBITS;19 51 +// std::ptrdiff_t distance : SIZE_T_BITS; 32 64 + +//direct: +// +// std::size_t ctrl : CTRL_BITS; 2 2 +// std::size_t dummy : SIZE_T_BITS - CTRL_BITS 30 62 +// void *addr : SIZE_T_BITS; 32 64 + +//32 bits systems: +//Page alignment: 2**12 +// + +//!Obtains the address pointed by the +//!object +void *to_raw_pointer() const +{ + if(this->is_pointee_outside() || this->is_in_stack()){ + return raw_address(); + } + else if(this->is_relative()){ + return (const_cast(reinterpret_cast(this))) + this->relative_pointee_offset(); + } + else{ + group_manager *m = get_segment_group_manager(addr); + char *base = static_cast(m->get_id_address(this->segmented_id())); + return base + this->segmented_offset(); + } +} + +void set_from_pointer(const void *ptr) +{ + if(!ptr){ + this->set_pointee_outside(); + this->raw_address(ptr); + } + else if(this->is_in_stack()){ + this->raw_address(ptr); + } + else if(this->is_relative() && + ( (ptr >= this->relative_start()) + &&(ptr < this->relative_start() + this->relative_size())) + ){ + this->relative_offset(ptr - this); + } + else{ + segment_info_t ptr_info = get_id_from_addr(ptr); + segment_info_t this_info = get_id_from_addr(this); + if(ptr_info.segment_group != this_info.segment_group){ + if(!ptr_info.segment_group){ + this->set_in_stack(); + } + else{ + this->set_pointee_outside(); + } + } + else if(ptr_info.segment_id == this_info.segment_id){ + set_relative(); + this->relative_size (ptr_info.size); + this->relative_offset(static_cast(ptr) - reinterpret_cast(this)); + this->relative_start (ptr_info.base); + } + } +} + +void set_from_other(const self_t &other) +{ this->set_from_pointer(other.to_raw_pointer()); } + +#endif + +#include + +#endif //#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP diff --git a/boost/interprocess/detail/managed_memory_impl.hpp b/boost/interprocess/detail/managed_memory_impl.hpp new file mode 100644 index 0000000000..31c3804439 --- /dev/null +++ b/boost/interprocess/detail/managed_memory_impl.hpp @@ -0,0 +1,750 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP +#define BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +// +#include +// +#include +#include +#include +#include + +//!\file +//!Describes a named shared memory allocation user class. +//! + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +class create_open_func; + +template< + class CharType, + class MemoryAlgorithm, + template class IndexType + > +struct segment_manager_type +{ + typedef segment_manager type; +}; + +//!This class is designed to be a base class to classes that manage +//!creation of objects in a fixed size memory buffer. Apart +//!from allocating raw memory, the user can construct named objects. To +//!achieve this, this class uses the reserved space provided by the allocation +//!algorithm to place a named_allocator_algo, who takes care of name mappings. +//!The class can be customized with the char type used for object names +//!and the memory allocation algorithm to be used.*/ +template < class CharType + , class MemoryAlgorithm + , template class IndexType + , std::size_t Offset = 0 + > +class basic_managed_memory_impl +{ + //Non-copyable + basic_managed_memory_impl(const basic_managed_memory_impl &); + basic_managed_memory_impl &operator=(const basic_managed_memory_impl &); + + template + friend class create_open_func; + + public: + typedef typename segment_manager_type + ::type segment_manager; + typedef CharType char_type; + typedef MemoryAlgorithm memory_algorithm; + typedef typename MemoryAlgorithm::mutex_family mutex_family; + typedef CharType char_t; + typedef typename MemoryAlgorithm::size_type size_type; + typedef typename MemoryAlgorithm::difference_type difference_type; + typedef difference_type handle_t; + typedef typename segment_manager:: + const_named_iterator const_named_iterator; + typedef typename segment_manager:: + const_unique_iterator const_unique_iterator; + + /// @cond + + typedef typename + segment_manager::char_ptr_holder_t char_ptr_holder_t; + //Experimental. Don't use. + + typedef typename segment_manager::multiallocation_chain multiallocation_chain; + + /// @endcond + + static const size_type PayloadPerAllocation = segment_manager::PayloadPerAllocation; + + private: + typedef basic_managed_memory_impl + self_t; + protected: + template + static bool grow(const char *filename, size_type extra_bytes) + { + typedef typename ManagedMemory::device_type device_type; + //Increase file size + try{ + offset_t old_size; + { + device_type f(open_or_create, filename, read_write); + if(!f.get_size(old_size)) + return false; + f.truncate(old_size + extra_bytes); + } + ManagedMemory managed_memory(open_only, filename); + //Grow always works + managed_memory.self_t::grow(extra_bytes); + } + catch(...){ + return false; + } + return true; + } + + template + static bool shrink_to_fit(const char *filename) + { + typedef typename ManagedMemory::device_type device_type; + size_type new_size; + try{ + ManagedMemory managed_memory(open_only, filename); + managed_memory.get_size(); + managed_memory.self_t::shrink_to_fit(); + new_size = managed_memory.get_size(); + } + catch(...){ + return false; + } + + //Decrease file size + { + device_type f(open_or_create, filename, read_write); + f.truncate(new_size); + } + return true; + } + + //!Constructor. Allocates basic resources. Never throws. + basic_managed_memory_impl() + : mp_header(0){} + + //!Destructor. Calls close. Never throws. + ~basic_managed_memory_impl() + { this->close_impl(); } + + //!Places segment manager in the reserved space. This can throw. + bool create_impl (void *addr, size_type size) + { + if(mp_header) return false; + + //Check if there is enough space + if(size < segment_manager::get_min_size()) + return false; + + //This function should not throw. The index construction can + //throw if constructor allocates memory. So we must catch it. + BOOST_TRY{ + //Let's construct the allocator in memory + mp_header = new(addr) segment_manager(size); + } + BOOST_CATCH(...){ + return false; + } + BOOST_CATCH_END + return true; + } + + //!Connects to a segment manager in the reserved buffer. Never throws. + bool open_impl (void *addr, size_type) + { + if(mp_header) return false; + mp_header = static_cast(addr); + return true; + } + + //!Frees resources. Never throws. + bool close_impl() + { + bool ret = mp_header != 0; + mp_header = 0; + return ret; + } + + //!Frees resources and destroys common resources. Never throws. + bool destroy_impl() + { + if(mp_header == 0) + return false; + mp_header->~segment_manager(); + this->close_impl(); + return true; + } + + //! + void grow(size_type extra_bytes) + { mp_header->grow(extra_bytes); } + + void shrink_to_fit() + { mp_header->shrink_to_fit(); } + + public: + + //!Returns segment manager. Never throws. + segment_manager *get_segment_manager() const + { return mp_header; } + + //!Returns the base address of the memory in this process. Never throws. + void * get_address () const + { return reinterpret_cast(mp_header) - Offset; } + + //!Returns the size of memory segment. Never throws. + size_type get_size () const + { return mp_header->get_size() + Offset; } + + //!Returns the number of free bytes of the memory + //!segment + size_type get_free_memory() const + { return mp_header->get_free_memory(); } + + //!Returns the result of "all_memory_deallocated()" function + //!of the used memory algorithm + bool all_memory_deallocated() + { return mp_header->all_memory_deallocated(); } + + //!Returns the result of "check_sanity()" function + //!of the used memory algorithm + bool check_sanity() + { return mp_header->check_sanity(); } + + //!Writes to zero free memory (memory not yet allocated) of + //!the memory algorithm + void zero_free_memory() + { mp_header->zero_free_memory(); } + + //!Transforms an absolute address into an offset from base address. + //!The address must belong to the memory segment. Never throws. + handle_t get_handle_from_address (const void *ptr) const + { + return (handle_t)(reinterpret_cast(ptr) - + reinterpret_cast(this->get_address())); + } + + //!Returns true if the address belongs to the managed memory segment + bool belongs_to_segment (const void *ptr) const + { + return ptr >= this->get_address() && + ptr < (reinterpret_cast(this->get_address()) + this->get_size()); + } + + //!Transforms previously obtained offset into an absolute address in the + //!process space of the current process. Never throws.*/ + void * get_address_from_handle (handle_t offset) const + { return reinterpret_cast(this->get_address()) + offset; } + + //!Searches for nbytes of free memory in the segment, marks the + //!memory as used and return the pointer to the memory. If no + //!memory is available throws a boost::interprocess::bad_alloc exception + void* allocate (size_type nbytes) + { return mp_header->allocate(nbytes); } + + //!Searches for nbytes of free memory in the segment, marks the + //!memory as used and return the pointer to the memory. If no memory + //!is available returns 0. Never throws. + void* allocate (size_type nbytes, std::nothrow_t nothrow) + { return mp_header->allocate(nbytes, nothrow); } + + //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" + //!must be power of two. If no memory + //!is available returns 0. Never throws. + void * allocate_aligned (size_type nbytes, size_type alignment, std::nothrow_t nothrow) + { return mp_header->allocate_aligned(nbytes, alignment, nothrow); } + + template + std::pair + allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type preferred_size,size_type &received_size, + T *reuse_ptr = 0) + { + return mp_header->allocation_command + (command, limit_size, preferred_size, received_size, reuse_ptr); + } + + //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" + //!must be power of two. If no + //!memory is available throws a boost::interprocess::bad_alloc exception + void * allocate_aligned(size_type nbytes, size_type alignment) + { return mp_header->allocate_aligned(nbytes, alignment); } + + /// @cond + + //Experimental. Don't use. + + //!Allocates n_elements of elem_size bytes. + multiallocation_chain allocate_many(size_type elem_bytes, size_type num_elements) + { return mp_header->allocate_many(elem_bytes, num_elements); } + + //!Allocates n_elements, each one of elem_sizes[i] bytes. + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements) + { return mp_header->allocate_many(elem_sizes, n_elements); } + + //!Allocates n_elements of elem_size bytes. + multiallocation_chain allocate_many(size_type elem_bytes, size_type num_elements, std::nothrow_t nothrow) + { return mp_header->allocate_many(elem_bytes, num_elements, nothrow); } + + //!Allocates n_elements, each one of elem_sizes[i] bytes. + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements, std::nothrow_t nothrow) + { return mp_header->allocate_many(elem_sizes, n_elements, nothrow); } + + //!Allocates n_elements, each one of elem_sizes[i] bytes. + void deallocate_many(multiallocation_chain chain) + { return mp_header->deallocate_many(boost::move(chain)); } + + /// @endcond + + //!Marks previously allocated memory as free. Never throws. + void deallocate (void *addr) + { if (mp_header) mp_header->deallocate(addr); } + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find (char_ptr_holder_t name) + { return mp_header->template find(name); } + + //!Creates a named object or array in memory + //! + //!Allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. If an array is being constructed all objects are + //!created using the same parameters given to this function. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and if an + //!array was being constructed, destructors of created objects are called + //!before freeing the memory. + template + typename segment_manager::template construct_proxy::type + construct(char_ptr_holder_t name) + { return mp_header->template construct(name); } + + //!Finds or creates a named object or array in memory + //! + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. If an array is being constructed all objects are + //!created using the same parameters given to this function. + //! + //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and if an + //!array was being constructed, destructors of created objects are called + //!before freeing the memory. + template + typename segment_manager::template construct_proxy::type + find_or_construct(char_ptr_holder_t name) + { return mp_header->template find_or_construct(name); } + + //!Creates a named object or array in memory + //! + //!Allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. If an array is being constructed all objects are + //!created using the same parameters given to this function. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> Returns 0 if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and if an + //!array was being constructed, destructors of created objects are called + //!before freeing the memory. + template + typename segment_manager::template construct_proxy::type + construct(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->template construct(name, nothrow); } + + //!Finds or creates a named object or array in memory + //! + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. If an array is being constructed all objects are + //!created using the same parameters given to this function. + //! + //!-> Returns 0 if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and if an + //!array was being constructed, destructors of created objects are called + //!before freeing the memory. + template + typename segment_manager::template construct_proxy::type + find_or_construct(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->template find_or_construct(name, nothrow); } + + //!Creates a named array from iterators in memory + //! + //!Allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. Each element in the array is created using the + //!objects returned when dereferencing iterators as parameters + //!and incrementing all iterators for each element. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and + //!destructors of created objects are called before freeing the memory. + template + typename segment_manager::template construct_iter_proxy::type + construct_it(char_ptr_holder_t name) + { return mp_header->template construct_it(name); } + + //!Finds or creates a named array from iterators in memory + //! + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. Each element in the array is created using the + //!objects returned when dereferencing iterators as parameters + //!and incrementing all iterators for each element. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and + //!destructors of created objects are called before freeing the memory. + template + typename segment_manager::template construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name) + { return mp_header->template find_or_construct_it(name); } + + //!Creates a named array from iterators in memory + //! + //!Allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. Each element in the array is created using the + //!objects returned when dereferencing iterators as parameters + //!and incrementing all iterators for each element. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> If there is no available memory, returns 0. + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and + //!destructors of created objects are called before freeing the memory.*/ + template + typename segment_manager::template construct_iter_proxy::type + construct_it(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->template construct_it(name, nothrow); } + + //!Finds or creates a named array from iterators in memory + //! + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. Each element in the array is created using the + //!objects returned when dereferencing iterators as parameters + //!and incrementing all iterators for each element. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> If there is no available memory, returns 0. + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and + //!destructors of created objects are called before freeing the memory.*/ + template + typename segment_manager::template construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->template find_or_construct_it(name, nothrow); } + + //!Calls a functor and guarantees that no new construction, search or + //!destruction will be executed by any process while executing the object + //!function call. If the functor throws, this function throws. + template + void atomic_func(Func &f) + { mp_header->atomic_func(f); } + + //!Tries to call a functor guaranteeing that no new construction, search or + //!destruction will be executed by any process while executing the object + //!function call. If the atomic function can't be immediatelly executed + //!because the internal mutex is already locked, returns false. + //!If the functor throws, this function throws. + template + bool try_atomic_func(Func &f) + { return mp_header->try_atomic_func(f); } + + //!Destroys a named memory object or array. + //! + //!Finds the object with the given name, calls its destructors, + //!frees used memory and returns true. + //! + //!-> If the object is not found, it returns false. + //! + //!Exception Handling: + //! + //!When deleting a dynamically object or array, the Standard + //!does not guarantee that dynamically allocated memory, will be released. + //!Also, when deleting arrays, the Standard doesn't require calling + //!destructors for the rest of the objects if for one of them the destructor + //!terminated with an exception. + //! + //!Destroying an object: + //! + //!If the destructor throws, the memory will be freed and that exception + //!will be thrown. + //! + //!Destroying an array: + //! + //!When destroying an array, if a destructor throws, the rest of + //!destructors are called. If any of these throws, the exceptions are + //!ignored. The name association will be erased, memory will be freed and + //!the first exception will be thrown. This guarantees the unlocking of + //!mutexes and other resources. + //! + //!For all theses reasons, classes with throwing destructors are not + //!recommended. + template + bool destroy(const CharType *name) + { return mp_header->template destroy(name); } + + //!Destroys the unique instance of type T + //! + //!Calls the destructor, frees used memory and returns true. + //! + //!Exception Handling: + //! + //!When deleting a dynamically object, the Standard does not + //!guarantee that dynamically allocated memory will be released. + //! + //!Destroying an object: + //! + //!If the destructor throws, the memory will be freed and that exception + //!will be thrown. + //! + //!For all theses reasons, classes with throwing destructors are not + //!recommended for memory. + template + bool destroy(const unique_instance_t *const ) + { return mp_header->template destroy(unique_instance); } + + //!Destroys the object (named, unique, or anonymous) + //! + //!Calls the destructor, frees used memory and returns true. + //! + //!Exception Handling: + //! + //!When deleting a dynamically object, the Standard does not + //!guarantee that dynamically allocated memory will be released. + //! + //!Destroying an object: + //! + //!If the destructor throws, the memory will be freed and that exception + //!will be thrown. + //! + //!For all theses reasons, classes with throwing destructors are not + //!recommended for memory. + template + void destroy_ptr(const T *ptr) + { mp_header->template destroy_ptr(ptr); } + + //!Returns the name of an object created with construct/find_or_construct + //!functions. Does not throw + template + static const char_type *get_instance_name(const T *ptr) + { return segment_manager::get_instance_name(ptr); } + + //!Returns is the type an object created with construct/find_or_construct + //!functions. Does not throw. + template + static instance_type get_instance_type(const T *ptr) + { return segment_manager::get_instance_type(ptr); } + + //!Returns the length of an object created with construct/find_or_construct + //!functions (1 if is a single element, >=1 if it's an array). Does not throw. + template + static size_type get_instance_length(const T *ptr) + { return segment_manager::get_instance_length(ptr); } + + //!Preallocates needed index resources to optimize the + //!creation of "num" named objects in the memory segment. + //!Can throw boost::interprocess::bad_alloc if there is no enough memory. + void reserve_named_objects(size_type num) + { mp_header->reserve_named_objects(num); } + + //!Preallocates needed index resources to optimize the + //!creation of "num" unique objects in the memory segment. + //!Can throw boost::interprocess::bad_alloc if there is no enough memory. + void reserve_unique_objects(size_type num) + { mp_header->reserve_unique_objects(num); } + + //!Calls shrink_to_fit in both named and unique object indexes + //to try to free unused memory from those indexes. + void shrink_to_fit_indexes() + { mp_header->shrink_to_fit_indexes(); } + + //!Returns the number of named objects stored + //!in the managed segment. + size_type get_num_named_objects() + { return mp_header->get_num_named_objects(); } + + //!Returns the number of unique objects stored + //!in the managed segment. + size_type get_num_unique_objects() + { return mp_header->get_num_unique_objects(); } + + //!Returns a constant iterator to the index storing the + //!named allocations. NOT thread-safe. Never throws. + const_named_iterator named_begin() const + { return mp_header->named_begin(); } + + //!Returns a constant iterator to the end of the index + //!storing the named allocations. NOT thread-safe. Never throws. + const_named_iterator named_end() const + { return mp_header->named_end(); } + + //!Returns a constant iterator to the index storing the + //!unique allocations. NOT thread-safe. Never throws. + const_unique_iterator unique_begin() const + { return mp_header->unique_begin(); } + + //!Returns a constant iterator to the end of the index + //!storing the unique allocations. NOT thread-safe. Never throws. + const_unique_iterator unique_end() const + { return mp_header->unique_end(); } + + //!This is the default allocator to allocate types T + //!from this managed segment + template + struct allocator + { + typedef typename segment_manager::template allocator::type type; + }; + + //!Returns an instance of the default allocator for type T + //!initialized that allocates memory from this segment manager. + template + typename allocator::type + get_allocator() + { return mp_header->template get_allocator(); } + + //!This is the default deleter to delete types T + //!from this managed segment. + template + struct deleter + { + typedef typename segment_manager::template deleter::type type; + }; + + //!Returns an instance of the default allocator for type T + //!initialized that allocates memory from this segment manager. + template + typename deleter::type + get_deleter() + { return mp_header->template get_deleter(); } + + /// @cond + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find_no_lock (char_ptr_holder_t name) + { return mp_header->template find_no_lock(name); } + /// @endcond + + protected: + //!Swaps the segment manager's managed by this managed memory segment. + //!NOT thread-safe. Never throws. + void swap(basic_managed_memory_impl &other) + { std::swap(mp_header, other.mp_header); } + + private: + segment_manager *mp_header; +}; + +template +class create_open_func +{ + public: + create_open_func(BasicManagedMemoryImpl * const frontend, create_enum_t type) + : m_frontend(frontend), m_type(type){} + + bool operator()(void *addr, typename BasicManagedMemoryImpl::size_type size, bool created) const + { + if(((m_type == DoOpen) && created) || + ((m_type == DoCreate) && !created)) + return false; + + if(created) + return m_frontend->create_impl(addr, size); + else + return m_frontend->open_impl (addr, size); + } + + private: + BasicManagedMemoryImpl *m_frontend; + create_enum_t m_type; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP + diff --git a/boost/interprocess/detail/managed_multi_shared_memory.hpp b/boost/interprocess/detail/managed_multi_shared_memory.hpp new file mode 100644 index 0000000000..579d1ad6ff --- /dev/null +++ b/boost/interprocess/detail/managed_multi_shared_memory.hpp @@ -0,0 +1,408 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include //list +#include //mapped_region +#include +#include +#include //managed_open_or_create_impl +#include +#include +#include +#include +#include +//These includes needed to fulfill default template parameters of +//predeclarations in interprocess_fwd.hpp +#include +#include + +//!\file +//!Describes a named shared memory object allocation user class. + +namespace boost { + +namespace interprocess { + +//TODO: We must somehow obtain the permissions of the first segment +//to apply them to subsequent segments +//-Use GetSecurityInfo? +//-Change everything to use only a shared memory object expanded via truncate()? + +//!A basic shared memory named object creation class. Initializes the +//!shared memory segment. Inherits all basic functionality from +//!basic_managed_memory_impl +template + < + class CharType, + class MemoryAlgorithm, + template class IndexType + > +class basic_managed_multi_shared_memory + : public ipcdetail::basic_managed_memory_impl + +{ + + typedef basic_managed_multi_shared_memory + self_t; + typedef ipcdetail::basic_managed_memory_impl + base_t; + + typedef typename MemoryAlgorithm::void_pointer void_pointer; + typedef typename ipcdetail:: + managed_open_or_create_impl managed_impl; + typedef typename void_pointer::segment_group_id segment_group_id; + typedef typename base_t::size_type size_type; + + //////////////////////////////////////////////////////////////////////// + // + // Some internal helper structs/functors + // + //////////////////////////////////////////////////////////////////////// + //!This class defines an operator() that creates a shared memory + //!of the requested size. The rest of the parameters are + //!passed in the constructor. The class a template parameter + //!to be used with create_from_file/create_from_istream functions + //!of basic_named_object classes + +// class segment_creator +// { +// public: +// segment_creator(shared_memory &shmem, +// const char *mem_name, +// const void *addr) +// : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){} +// +// void *operator()(size_type size) +// { +// if(!m_shmem.create(m_mem_name, size, m_addr)) +// return 0; +// return m_shmem.get_address(); +// } +// private: +// shared_memory &m_shmem; +// const char *m_mem_name; +// const void *m_addr; +// }; + + class group_services + : public multi_segment_services + { + public: + typedef std::pair result_type; + typedef basic_managed_multi_shared_memory frontend_t; + typedef typename + basic_managed_multi_shared_memory::void_pointer void_pointer; + typedef typename void_pointer::segment_group_id segment_group_id; + group_services(frontend_t *const frontend) + : mp_frontend(frontend), m_group(0), m_min_segment_size(0){} + + virtual std::pair create_new_segment(size_type alloc_size) + { (void)alloc_size; + /* + //We should allocate an extra byte so that the + //[base_addr + alloc_size] byte belongs to this segment + alloc_size += 1; + + //If requested size is less than minimum, update that + alloc_size = (m_min_segment_size > alloc_size) ? + m_min_segment_size : alloc_size; + if(mp_frontend->priv_new_segment(create_open_func::DoCreate, + alloc_size, 0, permissions())){ + typename shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin(); + return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1); + }*/ + return result_type(static_cast(0), 0); + } + + virtual bool update_segments () + { return true; } + + virtual ~group_services(){} + + void set_group(segment_group_id group) + { m_group = group; } + + segment_group_id get_group() const + { return m_group; } + + void set_min_segment_size(size_type min_segment_size) + { m_min_segment_size = min_segment_size; } + + size_type get_min_segment_size() const + { return m_min_segment_size; } + + private: + + frontend_t * const mp_frontend; + segment_group_id m_group; + size_type m_min_segment_size; + }; + + //!Functor to execute atomically when opening or creating a shared memory + //!segment. + struct create_open_func + { + enum type_t { DoCreate, DoOpen, DoOpenOrCreate }; + typedef typename + basic_managed_multi_shared_memory::void_pointer void_pointer; + + create_open_func(self_t * const frontend, + type_t type, size_type segment_number) + : mp_frontend(frontend), m_type(type), m_segment_number(segment_number){} + + bool operator()(void *addr, size_type size, bool created) const + { + if(((m_type == DoOpen) && created) || + ((m_type == DoCreate) && !created)) + return false; + segment_group_id group = mp_frontend->m_group_services.get_group(); + bool mapped = false; + bool impl_done = false; + + //Associate this newly created segment as the + //segment id = 0 of this group + void_pointer::insert_mapping + ( group + , static_cast(addr) - managed_impl::ManagedOpenOrCreateUserOffset + , size + managed_impl::ManagedOpenOrCreateUserOffset); + //Check if this is the master segment + if(!m_segment_number){ + //Create or open the Interprocess machinery + if((impl_done = created ? + mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){ + return true; + } + } + else{ + return true; + } + + //This is the cleanup part + //--------------- + if(impl_done){ + mp_frontend->close_impl(); + } + if(mapped){ + bool ret = void_pointer::erase_last_mapping(group); + BOOST_ASSERT(ret);(void)ret; + } + return false; + } + self_t * const mp_frontend; + type_t m_type; + size_type m_segment_number; + }; + + //!Functor to execute atomically when closing a shared memory segment. + struct close_func + { + typedef typename + basic_managed_multi_shared_memory::void_pointer void_pointer; + + close_func(self_t * const frontend) + : mp_frontend(frontend){} + + void operator()(const mapped_region ®ion, bool last) const + { + if(last) mp_frontend->destroy_impl(); + else mp_frontend->close_impl(); + } + self_t * const mp_frontend; + }; + + //Friend declarations + friend struct basic_managed_multi_shared_memory::create_open_func; + friend struct basic_managed_multi_shared_memory::close_func; + friend class basic_managed_multi_shared_memory::group_services; + + typedef list shmem_list_t; + + basic_managed_multi_shared_memory *get_this_pointer() + { return this; } + + public: + + basic_managed_multi_shared_memory(create_only_t, + const char *name, + size_type size, + const permissions &perm = permissions()) + : m_group_services(get_this_pointer()) + { + priv_open_or_create(create_open_func::DoCreate,name, size, perm); + } + + basic_managed_multi_shared_memory(open_or_create_t, + const char *name, + size_type size, + const permissions &perm = permissions()) + : m_group_services(get_this_pointer()) + { + priv_open_or_create(create_open_func::DoOpenOrCreate, name, size, perm); + } + + basic_managed_multi_shared_memory(open_only_t, const char *name) + : m_group_services(get_this_pointer()) + { + priv_open_or_create(create_open_func::DoOpen, name, 0, permissions()); + } + + ~basic_managed_multi_shared_memory() + { this->priv_close(); } + + private: + bool priv_open_or_create(typename create_open_func::type_t type, + const char *name, + size_type size, + const permissions &perm) + { + if(!m_shmem_list.empty()) + return false; + typename void_pointer::segment_group_id group = 0; + BOOST_TRY{ + m_root_name = name; + //Insert multi segment services and get a group identifier + group = void_pointer::new_segment_group(&m_group_services); + size = void_pointer::round_size(size); + m_group_services.set_group(group); + m_group_services.set_min_segment_size(size); + + if(group){ + if(this->priv_new_segment(type, size, 0, perm)){ + return true; + } + } + } + BOOST_CATCH(const std::bad_alloc&){ + } + BOOST_CATCH_END + if(group){ + void_pointer::delete_group(group); + } + return false; + } + + bool priv_new_segment(typename create_open_func::type_t type, + size_type size, + const void *addr, + const permissions &perm) + { + BOOST_TRY{ + //Get the number of groups of this multi_segment group + size_type segment_id = m_shmem_list.size(); + //Format the name of the shared memory: append segment number. + boost::interprocess::basic_ovectorstream formatter; + //Pre-reserve string size + size_type str_size = m_root_name.length()+10; + if(formatter.vector().size() < str_size){ + //This can throw. + formatter.reserve(str_size); + } + //Format segment's name + formatter << m_root_name + << static_cast(segment_id) << std::ends; + //This functor will be executed when constructing + create_open_func func(this, type, segment_id); + const char *name = formatter.vector().c_str(); + //This can throw. + managed_impl mshm; + + switch(type){ + case create_open_func::DoCreate: + { + managed_impl shm(create_only, name, size, read_write, addr, func, perm); + mshm = boost::move(shm); + } + break; + + case create_open_func::DoOpen: + { + managed_impl shm(open_only, name,read_write, addr, func); + mshm = boost::move(shm); + } + break; + + case create_open_func::DoOpenOrCreate: + { + managed_impl shm(open_or_create, name, size, read_write, addr, func, perm); + mshm = boost::move(shm); + } + break; + + default: + return false; + break; + } + + //This can throw. + m_shmem_list.push_back(boost::move(mshm)); + return true; + } + BOOST_CATCH(const std::bad_alloc&){ + } + BOOST_CATCH_END + return false; + } + + //!Frees resources. Never throws. + void priv_close() + { + if(!m_shmem_list.empty()){ + bool ret; + //Obtain group identifier + segment_group_id group = m_group_services.get_group(); + //Erase main segment and its resources + //typename shmem_list_t::iterator itbeg = m_shmem_list.begin(), + // itend = m_shmem_list.end(), + // it = itbeg; + //(*itbeg)->close_with_func(close_func(this)); + //Delete group. All mappings are erased too. + ret = void_pointer::delete_group(group); + (void)ret; + BOOST_ASSERT(ret); + m_shmem_list.clear(); + } + } + + private: + shmem_list_t m_shmem_list; + group_services m_group_services; + std::string m_root_name; +}; + +typedef basic_managed_multi_shared_memory + < char + , rbtree_best_fit > + , iset_index> + managed_multi_shared_memory; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP + diff --git a/boost/interprocess/detail/managed_open_or_create_impl.hpp b/boost/interprocess/detail/managed_open_or_create_impl.hpp new file mode 100644 index 0000000000..4d6997f330 --- /dev/null +++ b/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -0,0 +1,483 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL +#define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { + +/// @cond +namespace ipcdetail{ class interprocess_tester; } + + +template +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 +{ + typedef xsi_key type; +}; + +#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + +/// @endcond + +namespace ipcdetail { + + +template +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 managed_open_or_create_impl_device_holder +{ + public: + DeviceAbstraction &get_device() + { return dev; } + + const DeviceAbstraction &get_device() const + { return dev; } + + private: + DeviceAbstraction dev; +}; + +template +class managed_open_or_create_impl + : public managed_open_or_create_impl_device_holder +{ + //Non-copyable + BOOST_MOVABLE_BUT_NOT_COPYABLE(managed_open_or_create_impl) + + typedef typename managed_open_or_create_impl_device_id_t::type device_id_t; + typedef managed_open_or_create_impl_device_holder DevHolder; + enum + { + UninitializedSegment, + InitializingSegment, + InitializedSegment, + CorruptedSegment + }; + + public: + static const std::size_t + ManagedOpenOrCreateUserOffset = + ct_rounded_size + < sizeof(boost::uint32_t) + , MemAlignment ? (MemAlignment) : + (::boost::alignment_of< ::boost::detail::max_align >::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 + 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 + 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 + 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(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 + static void truncate_device(DeviceAbstraction &, offset_t, false_) + {} //Empty + + template + static void truncate_device(DeviceAbstraction &dev, offset_t size, true_) + { dev.truncate(size); } + + + template + static bool check_offset_t_size(std::size_t , false_) + { return true; } //Empty + + template + 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 + 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 + 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 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_ file_like_t; + (void)mode; + error_info err; + bool created = false; + bool ronly = false; + bool cow = false; + DeviceAbstraction dev; + + if(type != DoOpen && 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(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(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; + while(!completed){ + try{ + create_device(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 &ex){ + if(ex.get_error_code() != not_found_error){ + throw; + } + } + catch(...){ + throw; + } + } + } + catch(...){ + throw; + } + thread_yield(); + } + } + + if(created){ + try{ + //If this throws, we are lost + truncate_device(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(region.get_address()); + boost::uint32_t previous = atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment); + + if(previous == UninitializedSegment){ + try{ + construct_func(static_cast(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(dev, 1u, file_like_t()); + } + catch(...){ + } + throw; + } + } + else{ + if(FileBased){ + offset_t filesize = 0; + while(filesize == 0){ + if(!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){ + throw interprocess_exception(error_info(system_error_code())); + } + thread_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(region.get_address()); + boost::uint32_t value = atomic_read32(patomic_word); + + while(value == InitializingSegment || value == UninitializedSegment){ + thread_yield(); + value = atomic_read32(patomic_word); + } + + if(value != InitializedSegment) + throw interprocess_exception(error_info(corrupted_error)); + + construct_func( static_cast(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); + } + } + + private: + friend class interprocess_tester; + void dont_close_on_destruction() + { interprocess_tester::dont_close_on_destruction(m_mapped_region); } + + mapped_region m_mapped_region; +}; + +template +inline void swap(managed_open_or_create_impl &x + ,managed_open_or_create_impl &y) +{ x.swap(y); } + +} //namespace ipcdetail { + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL diff --git a/boost/interprocess/detail/math_functions.hpp b/boost/interprocess/detail/math_functions.hpp new file mode 100644 index 0000000000..08274160db --- /dev/null +++ b/boost/interprocess/detail/math_functions.hpp @@ -0,0 +1,110 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Stephen Cleary 2000. +// (C) Copyright Ion Gaztanaga 2007-2011. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +// This file is a slightly modified file from Boost.Pool +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP + +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +// Greatest common divisor and least common multiple + +// +// gcd is an algorithm that calculates the greatest common divisor of two +// integers, using Euclid's algorithm. +// +// Pre: A > 0 && B > 0 +// Recommended: A > B +template +inline Integer gcd(Integer A, Integer B) +{ + do + { + const Integer tmp(B); + B = A % B; + A = tmp; + } while (B != 0); + + return A; +} + +// +// lcm is an algorithm that calculates the least common multiple of two +// integers. +// +// Pre: A > 0 && B > 0 +// Recommended: A > B +template +inline Integer lcm(const Integer & A, const Integer & B) +{ + Integer ret = A; + ret /= gcd(A, B); + ret *= B; + return ret; +} + +template +inline Integer log2_ceil(const Integer & A) +{ + Integer i = 0; + Integer power_of_2 = 1; + + while(power_of_2 < A){ + power_of_2 <<= 1; + ++i; + } + return i; +} + +template +inline Integer upper_power_of_2(const Integer & A) +{ + Integer power_of_2 = 1; + + while(power_of_2 < A){ + power_of_2 <<= 1; + } + return power_of_2; +} + +//This function uses binary search to discover the +//highest set bit of the integer +inline std::size_t floor_log2 (std::size_t x) +{ + const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT; + const bool Size_t_Bits_Power_2= !(Bits & (Bits-1)); + BOOST_STATIC_ASSERT(((Size_t_Bits_Power_2)== true)); + + std::size_t n = x; + std::size_t log2 = 0; + + for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ + std::size_t tmp = n >> shift; + if (tmp) + log2 += shift, n = tmp; + } + + return log2; +} + +} // namespace ipcdetail +} // namespace interprocess +} // namespace boost + +#endif diff --git a/boost/interprocess/detail/min_max.hpp b/boost/interprocess/detail/min_max.hpp new file mode 100644 index 0000000000..75aa00f87b --- /dev/null +++ b/boost/interprocess/detail/min_max.hpp @@ -0,0 +1,40 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP +#define BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +template +const T &max_value(const T &a, const T &b) +{ return a > b ? a : b; } + +template +const T &min_value(const T &a, const T &b) +{ return a < b ? a : b; } + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP + diff --git a/boost/interprocess/detail/move.hpp b/boost/interprocess/detail/move.hpp new file mode 100644 index 0000000000..1ec43b211b --- /dev/null +++ b/boost/interprocess/detail/move.hpp @@ -0,0 +1,28 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2010-2011. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//! \file + +#ifndef BOOST_INTERPROCESS_DETAIL_MOVE_HPP +#define BOOST_INTERPROCESS_DETAIL_MOVE_HPP + +#include + +namespace boost { +namespace interprocess { + +using ::boost::move; +using ::boost::forward; + +} //namespace interprocess { +} //namespace boost { + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MOVE_HPP diff --git a/boost/interprocess/detail/mpl.hpp b/boost/interprocess/detail/mpl.hpp new file mode 100644 index 0000000000..c5b6f90ef1 --- /dev/null +++ b/boost/interprocess/detail/mpl.hpp @@ -0,0 +1,152 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MPL_HPP +#define BOOST_INTERPROCESS_DETAIL_MPL_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +struct integral_constant +{ + static const T value = val; + typedef integral_constant type; +}; + +template< bool C_ > +struct bool_ : integral_constant +{ + static const bool value = C_; +}; + +typedef bool_ true_; +typedef bool_ false_; + +typedef true_ true_type; +typedef false_ false_type; + +typedef char yes_type; +struct no_type +{ + char padding[8]; +}; + +template +struct enable_if_c { + typedef T type; +}; + +template +struct enable_if_c {}; + +template +struct enable_if : public enable_if_c {}; + +template +struct disable_if : public enable_if_c {}; + +template +class is_convertible +{ + typedef char true_t; + class false_t { char dummy[2]; }; + static true_t dispatch(U); + static false_t dispatch(...); + static T trigger(); + public: + static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t); +}; + +template< + bool C + , typename T1 + , typename T2 + > +struct if_c +{ + typedef T1 type; +}; + +template< + typename T1 + , typename T2 + > +struct if_c +{ + typedef T2 type; +}; + +template< + typename T1 + , typename T2 + , typename T3 + > +struct if_ +{ + typedef typename if_c<0 != T1::value, T2, T3>::type type; +}; + + +template +struct select1st +// : public std::unary_function +{ + template + const typename Pair::first_type& operator()(const OtherPair& x) const + { return x.first; } + + const typename Pair::first_type& operator()(const typename Pair::first_type& x) const + { return x; } +}; + +// identity is an extension: it is not part of the standard. +template +struct identity +// : public std::unary_function +{ + typedef T type; + const T& operator()(const T& x) const + { return x; } +}; + +template +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 + diff --git a/boost/interprocess/detail/multi_segment_services.hpp b/boost/interprocess/detail/multi_segment_services.hpp new file mode 100644 index 0000000000..4b6cafc742 --- /dev/null +++ b/boost/interprocess/detail/multi_segment_services.hpp @@ -0,0 +1,46 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP +#define BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + + +/*!\file + Describes a named shared memory allocation user class. +*/ + +namespace boost { + +namespace interprocess { + +class multi_segment_services +{ + public: + virtual std::pair create_new_segment(std::size_t mem) = 0; + virtual bool update_segments () = 0; + virtual ~multi_segment_services() = 0; +}; + +inline multi_segment_services::~multi_segment_services() +{} + + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifdef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP diff --git a/boost/interprocess/detail/named_proxy.hpp b/boost/interprocess/detail/named_proxy.hpp new file mode 100644 index 0000000000..604d7881ea --- /dev/null +++ b/boost/interprocess/detail/named_proxy.hpp @@ -0,0 +1,349 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP +#define BOOST_INTERPROCESS_NAMED_PROXY_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include + +#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING +#include +#else +#include +#include +#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +//!\file +//!Describes a proxy class that implements named allocation syntax. + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +template +struct CtorNArg : public placement_destroy +{ + typedef bool_ IsIterator; + typedef CtorNArg self_t; + typedef typename build_number_seq::type index_tuple_t; + + self_t& operator++() + { + this->do_increment(IsIterator(), index_tuple_t()); + return *this; + } + + self_t operator++(int) { return ++*this; *this; } + + CtorNArg(Args && ...args) + : args_(args...) + {} + + virtual void construct_n(void *mem + , std::size_t num + , std::size_t &constructed) + { + T* memory = static_cast(mem); + for(constructed = 0; constructed < num; ++constructed){ + this->construct(memory++, IsIterator(), index_tuple_t()); + this->do_increment(IsIterator(), index_tuple_t()); + } + } + + private: + template + void construct(void *mem, true_, const index_tuple&) + { new((void*)mem)T(*boost::forward(get(args_))...); } + + template + void construct(void *mem, false_, const index_tuple&) + { new((void*)mem)T(boost::forward(get(args_))...); } + + template + void do_increment(true_, const index_tuple&) + { + this->expansion_helper(++get(args_)...); + } + + template + void expansion_helper(ExpansionArgs &&...) + {} + + template + void do_increment(false_, const index_tuple&) + {} + + tuple args_; +}; + +//!Describes a proxy class that implements named +//!allocation syntax. +template + < class SegmentManager //segment manager to construct the object + , class T //type of object to build + , bool is_iterator //passing parameters are normal object or iterators? + > +class named_proxy +{ + typedef typename SegmentManager::char_type char_type; + const char_type * mp_name; + SegmentManager * mp_mngr; + mutable std::size_t m_num; + const bool m_find; + const bool m_dothrow; + + public: + named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow) + : mp_name(name), mp_mngr(mngr), m_num(1) + , m_find(find), m_dothrow(dothrow) + {} + + template + T *operator()(Args &&...args) const + { + CtorNArg &&ctor_obj = CtorNArg + (boost::forward(args)...); + return mp_mngr->template + generic_construct(mp_name, m_num, m_find, m_dothrow, ctor_obj); + } + + //This operator allows --> named_new("Name")[3]; <-- syntax + const named_proxy &operator[](std::size_t num) const + { m_num *= num; return *this; } +}; + +#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +//!Function object that makes placement new +//!without arguments +template +struct Ctor0Arg : public placement_destroy +{ + typedef Ctor0Arg self_t; + + Ctor0Arg(){} + + self_t& operator++() { return *this; } + self_t operator++(int) { return *this; } + + void construct(void *mem) + { new((void*)mem)T; } + + virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) + { + T* memory = static_cast(mem); + for(constructed = 0; constructed < num; ++constructed) + new((void*)memory++)T; + } +}; + +//////////////////////////////////////////////////////////////// +// What the macro should generate (n == 2): +// +// template +// struct Ctor2Arg +// : public placement_destroy +// { +// typedef bool_ IsIterator; +// typedef Ctor2Arg self_t; +// +// void do_increment(false_) +// { ++m_p1; ++m_p2; } +// +// void do_increment(true_){} +// +// self_t& operator++() +// { +// this->do_increment(IsIterator()); +// return *this; +// } +// +// self_t operator++(int) { return ++*this; *this; } +// +// Ctor2Arg(const P1 &p1, const P2 &p2) +// : p1((P1 &)p_1), p2((P2 &)p_2) {} +// +// void construct(void *mem) +// { new((void*)object)T(m_p1, m_p2); } +// +// virtual void construct_n(void *mem +// , std::size_t num +// , std::size_t &constructed) +// { +// T* memory = static_cast(mem); +// for(constructed = 0; constructed < num; ++constructed){ +// this->construct(memory++, IsIterator()); +// this->do_increment(IsIterator()); +// } +// } +// +// private: +// void construct(void *mem, true_) +// { new((void*)mem)T(*m_p1, *m_p2); } +// +// void construct(void *mem, false_) +// { new((void*)mem)T(m_p1, m_p2); } +// +// P1 &m_p1; P2 &m_p2; +// }; +//////////////////////////////////////////////////////////////// + +//Note: +//We define template parameters as const references to +//be able to bind temporaries. After that we will un-const them. +//This cast is ugly but it is necessary until "perfect forwarding" +//is achieved in C++0x. Meanwhile, if we want to be able to +//bind lvalues with non-const references, we have to be ugly +#define BOOST_PP_LOCAL_MACRO(n) \ + template \ + struct BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ + : public placement_destroy \ + { \ + typedef bool_ IsIterator; \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) self_t; \ + \ + void do_increment(true_) \ + { BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_INC, _); } \ + \ + void do_increment(false_){} \ + \ + self_t& operator++() \ + { \ + this->do_increment(IsIterator()); \ + return *this; \ + } \ + \ + self_t operator++(int) { return ++*this; *this; } \ + \ + BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ + ( BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _) ) \ + : BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_INIT, _) {} \ + \ + virtual void construct_n(void *mem \ + , std::size_t num \ + , std::size_t &constructed) \ + { \ + T* memory = static_cast(mem); \ + for(constructed = 0; constructed < num; ++constructed){ \ + this->construct(memory++, IsIterator()); \ + this->do_increment(IsIterator()); \ + } \ + } \ + \ + private: \ + void construct(void *mem, true_) \ + { \ + new((void*)mem) T \ + (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD, _)); \ + } \ + \ + void construct(void *mem, false_) \ + { \ + new((void*)mem) T \ + (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ + } \ + \ + BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_PP_PARAM_DEFINE, _) \ + }; \ +//! +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) +#include BOOST_PP_LOCAL_ITERATE() + +//!Describes a proxy class that implements named +//!allocation syntax. +template + < class SegmentManager //segment manager to construct the object + , class T //type of object to build + , bool is_iterator //passing parameters are normal object or iterators? + > +class named_proxy +{ + typedef typename SegmentManager::char_type char_type; + const char_type * mp_name; + SegmentManager * mp_mngr; + mutable std::size_t m_num; + const bool m_find; + const bool m_dothrow; + + public: + named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow) + : mp_name(name), mp_mngr(mngr), m_num(1) + , m_find(find), m_dothrow(dothrow) + {} + + //!makes a named allocation and calls the + //!default constructor + T *operator()() const + { + Ctor0Arg ctor_obj; + return mp_mngr->template + generic_construct(mp_name, m_num, m_find, m_dothrow, ctor_obj); + } + //! + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + T *operator()(BOOST_PP_ENUM (n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) const\ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ + \ + ctor_obj_t; \ + ctor_obj_t ctor_obj \ + (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + return mp_mngr->template generic_construct \ + (mp_name, m_num, m_find, m_dothrow, ctor_obj); \ + } \ + //! + + #define BOOST_PP_LOCAL_LIMITS ( 1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS ) + #include BOOST_PP_LOCAL_ITERATE() + + //////////////////////////////////////////////////////////////////////// + // What the macro should generate (n == 2) + //////////////////////////////////////////////////////////////////////// + // + // template + // T *operator()(P1 &p1, P2 &p2) const + // { + // typedef Ctor2Arg + // + // ctor_obj_t; + // ctor_obj_t ctor_obj(p1, p2); + // + // return mp_mngr->template generic_construct + // (mp_name, m_num, m_find, m_dothrow, ctor_obj); + // } + // + ////////////////////////////////////////////////////////////////////////// + + //This operator allows --> named_new("Name")[3]; <-- syntax + const named_proxy &operator[](std::size_t num) const + { m_num *= num; return *this; } +}; + +#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +}}} //namespace boost { namespace interprocess { namespace ipcdetail { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP diff --git a/boost/interprocess/detail/os_file_functions.hpp b/boost/interprocess/detail/os_file_functions.hpp new file mode 100644 index 0000000000..b680c57132 --- /dev/null +++ b/boost/interprocess/detail/os_file_functions.hpp @@ -0,0 +1,696 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP + +#include +#include +#include +#include + +#include +#include +#include + +#if (defined BOOST_INTERPROCESS_WINDOWS) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include +# include +# include +# include +# include +# include +# include +# if 0 +# include +# endif +# else +# error Unknown platform +# endif +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +#if (defined BOOST_INTERPROCESS_WINDOWS) + +typedef void * file_handle_t; +typedef long long 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; + +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 const char *get_temporary_path() +{ return std::getenv("TMP"); } + + +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; + + const offset_t max_filesize = (std::numeric_limits::max)(); + //Avoid unused variable warnings in 32 bit systems + (void)max_filesize; + if( sizeof(std::size_t) >= sizeof(offset_t) && size > std::size_t(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 = 0xffffffff; +// 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 = 0xffffffff; + 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 = 0xffffffff; + winapi::interprocess_overlapped overlapped; + std::memset(&overlapped, 0, sizeof(overlapped)); + return winapi::unlock_file_ex(hnd, 0, len, len, &overlapped); +} + +inline bool acquire_file_lock_sharable(file_handle_t hnd) +{ + const unsigned long len = 0xffffffff; + winapi::interprocess_overlapped overlapped; + std::memset(&overlapped, 0, sizeof(overlapped)); + return winapi::lock_file_ex(hnd, 0, 0, len, len, &overlapped); +} + +inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) +{ + const unsigned long len = 0xffffffff; + 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_t 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)) + 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::delete_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 +inline bool for_each_file_in_dir(const char *dir, Function f) +{ + void * hFile; // Handle to directory + winapi::win32_find_data_t 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; + +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 const char *get_temporary_path() +{ + const char *names[] = {"/tmp", "TMPDIR", "TMP", "TEMP" }; + const int names_size = sizeof(names)/sizeof(names[0]); + struct stat data; + for(int i = 0; i != names_size; ++i){ + if(::stat(names[i], &data) == 0){ + return names[i]; + } + } + return "/tmp"; +} + +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; + } + } + } + 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) +{ + if(sizeof(off_t) == sizeof(std::size_t)){ + if(size > ((~std::size_t(0)) >> 1)){ + 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 +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; +} + + +} //namespace ipcdetail{ +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP diff --git a/boost/interprocess/detail/os_thread_functions.hpp b/boost/interprocess/detail/os_thread_functions.hpp new file mode 100644 index 0000000000..e49e82c8e0 --- /dev/null +++ b/boost/interprocess/detail/os_thread_functions.hpp @@ -0,0 +1,211 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP + +#include +#include +#include +#include + +#if (defined BOOST_INTERPROCESS_WINDOWS) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include +# include +# include +# include +# else +# error Unknown platform +# 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; +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; } + +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; + + 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; +} + + +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) + +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(); } + +inline void thread_sleep(unsigned int ms) +{ + const struct timespec rqt = { ms/1000u, (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; } + +#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()); } + +} //namespace ipcdetail{ +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP diff --git a/boost/interprocess/detail/pointer_type.hpp b/boost/interprocess/detail/pointer_type.hpp new file mode 100644 index 0000000000..7c45be085e --- /dev/null +++ b/boost/interprocess/detail/pointer_type.hpp @@ -0,0 +1,74 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP +#define BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +struct two {char _[2];}; + +namespace pointer_type_imp { + +template static two test(...); +template static char test(typename U::pointer* = 0); + +} //namespace pointer_type_imp { + +template +struct has_pointer_type +{ + static const bool value = sizeof(pointer_type_imp::test(0)) == 1; +}; + +namespace pointer_type_imp { + +template ::value> +struct pointer_type +{ + typedef typename D::pointer type; +}; + +template +struct pointer_type +{ + typedef T* type; +}; + +} //namespace pointer_type_imp { + +template +struct pointer_type +{ + typedef typename pointer_type_imp::pointer_type::type>::type type; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP + diff --git a/boost/interprocess/detail/posix_time_types_wrk.hpp b/boost/interprocess/detail/posix_time_types_wrk.hpp new file mode 100644 index 0000000000..c1276f0f26 --- /dev/null +++ b/boost/interprocess/detail/posix_time_types_wrk.hpp @@ -0,0 +1,42 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP +#define BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP + +//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 +#include + +namespace boost { +namespace interprocess { + +typedef boost::date_time::microsec_clock 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 + diff --git a/boost/interprocess/detail/preprocessor.hpp b/boost/interprocess/detail/preprocessor.hpp new file mode 100644 index 0000000000..4af2686452 --- /dev/null +++ b/boost/interprocess/detail/preprocessor.hpp @@ -0,0 +1,137 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_PREPROCESSOR_HPP +#define BOOST_INTERPROCESS_DETAIL_PREPROCESSOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif + +#include +#include +#include +#include +#include + +#define BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS 10 + +//Note: +//We define template parameters as const references to +//be able to bind temporaries. After that we will un-const them. +//This cast is ugly but it is necessary until "perfect forwarding" +//is achieved in C++0x. Meanwhile, if we want to be able to +//bind rvalues with non-const references, we have to be ugly +#ifndef BOOST_NO_RVALUE_REFERENCES + #define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \ + //! +#else + #define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \ + const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \ + //! +#endif + +#ifndef BOOST_NO_RVALUE_REFERENCES + #define BOOST_INTERPROCESS_PP_PARAM(U, u) \ + U && u \ + //! +#else + #define BOOST_INTERPROCESS_PP_PARAM(U, u) \ + const U & u \ + //! +#endif + +#ifndef BOOST_NO_RVALUE_REFERENCES + +#ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES + +#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (BOOST_INTERPROCESS_MOVE_NAMESPACE::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) )) \ +//! + +#else + +#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \ +//! + +#endif + +#else +#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (const_cast(BOOST_PP_CAT(p, n))) \ +//! +#endif + +#define BOOST_INTERPROCESS_PP_PARAM_INC(z, n, data) \ + BOOST_PP_CAT(++m_p, n) \ +//! + +#ifndef BOOST_NO_RVALUE_REFERENCES + +#if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + +#define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data) \ + BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ +//! + +#else + +#define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data) \ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \ +//! + +#endif //defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + + +#else +#define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data) \ + BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ +//! +#endif + +#define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ +::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ +//! + +#if !defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + +#include + +#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ +::boost::container::container_detail::stored_ref< BOOST_PP_CAT(P, n) >::forward( BOOST_PP_CAT(m_p, n) ) \ +//! + +#else + +#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ +::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ +//! + +#endif //!defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + +#define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \ +BOOST_PP_CAT(*m_p, n) \ +//! + +#include + +#else +#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_PREPROCESSOR_HPP diff --git a/boost/interprocess/detail/ptime_wrk.hpp b/boost/interprocess/detail/ptime_wrk.hpp new file mode 100644 index 0000000000..4a4709e3a8 --- /dev/null +++ b/boost/interprocess/detail/ptime_wrk.hpp @@ -0,0 +1,33 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_PTIME_WRK_HPP +#define BOOST_INTERPROCESS_PTIME_WRK_HPP + +//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 + +#ifdef _WIN32 +#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#undef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN +#endif //#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN +#endif //#ifdef _WIN32 + +#endif //#ifndef BOOST_INTERPROCESS_PTIME_WRK_HPP + diff --git a/boost/interprocess/detail/robust_emulation.hpp b/boost/interprocess/detail/robust_emulation.hpp new file mode 100644 index 0000000000..b2097d0ad7 --- /dev/null +++ b/boost/interprocess/detail/robust_emulation.hpp @@ -0,0 +1,439 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2010-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_ROBUST_EMULATION_HPP +#define BOOST_INTERPROCESS_ROBUST_EMULATION_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +namespace robust_emulation_helpers { + +template +class mutex_traits +{ + public: + static void take_ownership(T &t) + { t.take_ownership(); } +}; + +inline void remove_if_can_lock_file(const char *file_path) +{ + file_handle_t fhnd = open_existing_file(file_path, read_write); + + if(fhnd != invalid_file()){ + bool acquired; + if(try_acquire_file_lock(fhnd, acquired) && acquired){ + delete_file(file_path); + } + close_file(fhnd); + } +} + +inline const char *robust_lock_subdir_path() +{ return "robust"; } + +inline const char *robust_lock_prefix() +{ return "lck"; } + +inline void robust_lock_path(std::string &s) +{ + tmp_folder(s); + s += "/"; + s += robust_lock_subdir_path(); +} + +inline void create_and_get_robust_lock_file_path(std::string &s, OS_process_id_t pid) +{ + file_locking_helpers::create_tmp_subdir_and_get_pid_based_filepath + (robust_lock_subdir_path(), robust_lock_prefix(), pid, s); +} + +//This class will be a intermodule_singleton. The constructor will create +//a lock file, the destructor will erase it. +// +//We should take in care that another process might be erasing unlocked +//files while creating this one, so there are some race conditions we must +//take in care to guarantee some robustness. +class robust_mutex_lock_file +{ + file_handle_t fd; + std::string fname; + public: + robust_mutex_lock_file() + { + permissions p; + p.set_unrestricted(); + //Remove old lock files of other processes + remove_old_robust_lock_files(); + //Create path and obtain lock file path for this process + create_and_get_robust_lock_file_path(fname, get_current_process_id()); + + //Now try to open or create the lock file + fd = create_or_open_file(fname.c_str(), read_write, p); + //If we can't open or create it, then something unrecoverable has happened + if(fd == invalid_file()){ + throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: could not open or create file"); + } + + //Now we must take in care a race condition with another process + //calling "remove_old_robust_lock_files()". No other threads from this + //process will be creating the lock file because intermodule_singleton + //guarantees this. So let's loop acquiring the lock and checking if we + //can't exclusively create the file (if the file is erased by another process + //then this exclusive open would fail). If the file can't be exclusively created + //then we have correctly open/create and lock the file. If the file can + //be exclusively created, then close previous locked file and try again. + while(1){ + bool acquired; + if(!try_acquire_file_lock(fd, acquired) || !acquired ){ + throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: try_acquire_file_lock"); + } + //Creating exclusively must fail with already_exists_error + //to make sure we've locked the file and no one has + //deleted it between creation and locking + file_handle_t fd2 = create_new_file(fname.c_str(), read_write, p); + if(fd2 != invalid_file()){ + close_file(fd); + fd = fd2; + continue; + } + //If exclusive creation fails with expected error go ahead + else if(error_info(system_error_code()).get_error_code() == already_exists_error){ //must already exist + //Leak descriptor to mantain the file locked until the process dies + break; + } + //If exclusive creation fails with unexpected error throw an unrecoverable error + else{ + close_file(fd); + throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: create_file filed with unexpected error"); + } + } + } + + ~robust_mutex_lock_file() + { + //The destructor is guaranteed by intermodule_singleton to be + //executed serialized between all threads from current process, + //so we just need to close and unlink the file. + close_file(fd); + //If some other process deletes the file before us after + //closing it there should not be any problem. + delete_file(fname.c_str()); + } + + private: + //This functor is execute for all files in the lock file directory + class other_process_lock_remover + { + public: + void operator()(const char *filepath, const char *filename) + { + std::string pid_str; + //If the lock file is not our own lock file, then try to do the cleanup + if(!file_locking_helpers::check_if_filename_complies_with_pid + (filename, robust_lock_prefix(), get_current_process_id(), pid_str)){ + remove_if_can_lock_file(filepath); + } + } + }; + + bool remove_old_robust_lock_files() + { + std::string refcstrRootDirectory; + robust_lock_path(refcstrRootDirectory); + return for_each_file_in_dir(refcstrRootDirectory.c_str(), other_process_lock_remover()); + } +}; + +} //namespace robust_emulation_helpers { + +//This is the mutex class. Mutex should follow mutex concept +//with an additonal "take_ownership()" function to take ownership of the +//mutex when robust_spin_mutex determines the previous owner was dead. +template +class robust_spin_mutex +{ + public: + static const boost::uint32_t correct_state = 0; + static const boost::uint32_t fixing_state = 1; + static const boost::uint32_t broken_state = 2; + + typedef robust_emulation_helpers::mutex_traits mutex_traits_t; + + robust_spin_mutex(); + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + void consistent(); + bool previous_owner_dead(); + + private: + static const unsigned int spin_threshold = 100u; + bool lock_own_unique_file(); + bool robust_check(); + bool check_if_owner_dead_and_take_ownership_atomically(); + bool is_owner_dead(boost::uint32_t owner); + void owner_to_filename(boost::uint32_t owner, std::string &s); + //The real mutex + Mutex mtx; + //The pid of the owner + volatile boost::uint32_t owner; + //The state of the mutex (correct, fixing, broken) + volatile boost::uint32_t state; +}; + +template +inline robust_spin_mutex::robust_spin_mutex() + : mtx(), owner(get_invalid_process_id()), state(correct_state) +{} + +template +inline void robust_spin_mutex::lock() +{ + //If the mutex is broken (recovery didn't call consistent()), + //then throw an exception + if(atomic_read32(&this->state) == broken_state){ + throw interprocess_exception(lock_error, "Broken id"); + } + + //This function provokes intermodule_singleton instantiation + if(!this->lock_own_unique_file()){ + throw interprocess_exception(lock_error, "Broken id"); + } + + //Now the logic. Try to lock, if successful mark the owner + //if it fails, start recovery logic + unsigned int spin_count = 0; + while(1){ + if (mtx.try_lock()){ + atomic_write32(&this->owner, get_current_process_id()); + break; + } + else{ + //Do the dead owner checking each spin_threshold lock tries + ipcdetail::thread_yield(); + ++spin_count; + if(spin_count > spin_threshold){ + //Check if owner dead and take ownership if possible + if(!this->robust_check()){ + spin_count = 0; + } + else{ + break; + } + } + } + } +} + +template +inline bool robust_spin_mutex::try_lock() +{ + //Same as lock() but without spinning + if(atomic_read32(&this->state) == broken_state){ + throw interprocess_exception(lock_error, "Broken id"); + } + + if(!this->lock_own_unique_file()){ + throw interprocess_exception(lock_error, "Broken id"); + } + + if (mtx.try_lock()){ + atomic_write32(&this->owner, get_current_process_id()); + return true; + } + else{ + if(!this->robust_check()){ + return false; + } + else{ + return true; + } + } +} + +template +inline bool robust_spin_mutex::timed_lock + (const boost::posix_time::ptime &abs_time) +{ + //Same as lock() but with an additional timeout + if(abs_time == boost::posix_time::pos_infin){ + this->lock(); + return true; + } + //Obtain current count and target time + boost::posix_time::ptime now = microsec_clock::universal_time(); + + if(now >= abs_time) + return this->try_lock(); + + do{ + if(this->try_lock()){ + break; + } + now = microsec_clock::universal_time(); + + if(now >= abs_time){ + return this->try_lock(); + } + // relinquish current time slice + ipcdetail::thread_yield(); + }while (true); + + return true; +} + +template +inline void robust_spin_mutex::owner_to_filename(boost::uint32_t owner, std::string &s) +{ + robust_emulation_helpers::create_and_get_robust_lock_file_path(s, owner); +} + +template +inline bool robust_spin_mutex::robust_check() +{ + //If the old owner was dead, and we've acquired ownership, mark + //the mutex as 'fixing'. This means that a "consistent()" is needed + //to avoid marking the mutex as "broken" when the mutex is unlocked. + if(!this->check_if_owner_dead_and_take_ownership_atomically()){ + return false; + } + atomic_write32(&this->state, fixing_state); + return true; +} + +template +inline bool robust_spin_mutex::check_if_owner_dead_and_take_ownership_atomically() +{ + boost::uint32_t cur_owner = get_current_process_id(); + boost::uint32_t old_owner = atomic_read32(&this->owner), old_owner2; + //The cas loop guarantees that only one thread from this or another process + //will succeed taking ownership + do{ + //Check if owner is dead + if(!this->is_owner_dead(old_owner)){ + return false; + } + //If it's dead, try to mark this process as the owner in the owner field + old_owner2 = old_owner; + old_owner = atomic_cas32(&this->owner, cur_owner, old_owner); + }while(old_owner2 != old_owner); + //If success, we fix mutex internals to assure our ownership + mutex_traits_t::take_ownership(mtx); + return true; +} + +template +inline bool robust_spin_mutex::is_owner_dead(boost::uint32_t owner) +{ + //If owner is an invalid id, then it's clear it's dead + if(owner == (boost::uint32_t)get_invalid_process_id()){ + return true; + } + + //Obtain the lock filename of the owner field + std::string file; + this->owner_to_filename(owner, file); + + //Now the logic is to open and lock it + file_handle_t fhnd = open_existing_file(file.c_str(), read_write); + + if(fhnd != invalid_file()){ + //If we can open the file, lock it. + bool acquired; + if(try_acquire_file_lock(fhnd, acquired) && acquired){ + //If locked, just delete the file + delete_file(file.c_str()); + close_file(fhnd); + return true; + } + //If not locked, the owner is suppossed to be still alive + close_file(fhnd); + } + else{ + //If the lock file does not exist then the owner is dead (a previous cleanup) + //function has deleted the file. If there is another reason, then this is + //an unrecoverable error + if(error_info(system_error_code()).get_error_code() == not_found_error){ + return true; + } + } + return false; +} + +template +inline void robust_spin_mutex::consistent() +{ + //This function supposes the previous state was "fixing" + //and the current process holds the mutex + if(atomic_read32(&this->state) != fixing_state && + atomic_read32(&this->owner) != (boost::uint32_t)get_current_process_id()){ + throw interprocess_exception(lock_error, "Broken id"); + } + //If that's the case, just update mutex state + atomic_write32(&this->state, correct_state); +} + +template +inline bool robust_spin_mutex::previous_owner_dead() +{ + //Notifies if a owner recovery has been performed in the last lock() + return atomic_read32(&this->state) == fixing_state; +}; + +template +inline void robust_spin_mutex::unlock() +{ + //If in "fixing" state, unlock and mark the mutex as unrecoverable + //so next locks will fail and all threads will be notified that the + //data protected by the mutex was not recoverable. + if(atomic_read32(&this->state) == fixing_state){ + atomic_write32(&this->state, broken_state); + } + //Write an invalid owner to minimize pid reuse possibility + atomic_write32(&this->owner, get_invalid_process_id()); + mtx.unlock(); +} + +template +inline bool robust_spin_mutex::lock_own_unique_file() +{ + //This function forces instantiation of the singleton + robust_emulation_helpers::robust_mutex_lock_file* dummy = + &ipcdetail::intermodule_singleton + ::get(); + return dummy != 0; +} + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif diff --git a/boost/interprocess/detail/segment_manager_helper.hpp b/boost/interprocess/detail/segment_manager_helper.hpp new file mode 100644 index 0000000000..ea820b3881 --- /dev/null +++ b/boost/interprocess/detail/segment_manager_helper.hpp @@ -0,0 +1,513 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP +#define BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include //std::size_t +#include //char_traits +#include //std::nothrow +#include //std::pair +#include //BOOST_ASSERT +#include //unary_function +#ifndef BOOST_NO_EXCEPTIONS +#include +#endif + +//!\file +//!Describes the object placed in a memory segment that provides +//!named object allocation capabilities. + +namespace boost{ +namespace interprocess{ + +template +class segment_manager_base; + +//!An integer that describes the type of the +//!instance constructed in memory +enum instance_type { anonymous_type, named_type, unique_type, max_allocation_type }; + +namespace ipcdetail{ + +template +class mem_algo_deallocator +{ + void * m_ptr; + MemoryAlgorithm & m_algo; + + public: + mem_algo_deallocator(void *ptr, MemoryAlgorithm &algo) + : m_ptr(ptr), m_algo(algo) + {} + + void release() + { m_ptr = 0; } + + ~mem_algo_deallocator() + { if(m_ptr) m_algo.deallocate(m_ptr); } +}; + +/// @cond +template +struct block_header +{ + size_type m_value_bytes; + unsigned short m_num_char; + unsigned char m_value_alignment; + unsigned char m_alloc_type_sizeof_char; + + block_header(size_type value_bytes + ,size_type value_alignment + ,unsigned char alloc_type + ,std::size_t sizeof_char + ,std::size_t num_char + ) + : m_value_bytes(value_bytes) + , m_num_char((unsigned short)num_char) + , m_value_alignment((unsigned char)value_alignment) + , m_alloc_type_sizeof_char + ( (alloc_type << 5u) | + ((unsigned char)sizeof_char & 0x1F) ) + {}; + + + template + block_header &operator= (const T& ) + { return *this; } + + size_type total_size() const + { + if(alloc_type() != anonymous_type){ + return name_offset() + (m_num_char+1)*sizeof_char(); + } + else{ + return this->value_offset() + m_value_bytes; + } + } + + size_type value_bytes() const + { return m_value_bytes; } + + template + size_type total_size_with_header() const + { + return get_rounded_size + ( size_type(sizeof(Header)) + , size_type(::boost::alignment_of >::value)) + + total_size(); + } + + unsigned char alloc_type() const + { return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; } + + unsigned char sizeof_char() const + { return m_alloc_type_sizeof_char & (unsigned char)0x1F; } + + template + CharType *name() const + { + return const_cast(reinterpret_cast + (reinterpret_cast(this) + name_offset())); + } + + unsigned short name_length() const + { return m_num_char; } + + size_type name_offset() const + { + return this->value_offset() + get_rounded_size(size_type(m_value_bytes), size_type(sizeof_char())); + } + + void *value() const + { + return const_cast((reinterpret_cast(this) + this->value_offset())); + } + + size_type value_offset() const + { + return get_rounded_size(size_type(sizeof(block_header)), size_type(m_value_alignment)); + } + + template + bool less_comp(const block_header &b) const + { + return m_num_char < b.m_num_char || + (m_num_char < b.m_num_char && + std::char_traits::compare + (name(), b.name(), m_num_char) < 0); + } + + template + bool equal_comp(const block_header &b) const + { + return m_num_char == b.m_num_char && + std::char_traits::compare + (name(), b.name(), m_num_char) == 0; + } + + template + static block_header *block_header_from_value(T *value) + { return block_header_from_value(value, sizeof(T), ::boost::alignment_of::value); } + + static block_header *block_header_from_value(const void *value, std::size_t sz, std::size_t algn) + { + block_header * hdr = + const_cast + (reinterpret_cast(reinterpret_cast(value) - + get_rounded_size(sizeof(block_header), algn))); + (void)sz; + //Some sanity checks + BOOST_ASSERT(hdr->m_value_alignment == algn); + BOOST_ASSERT(hdr->m_value_bytes % sz == 0); + return hdr; + } + + template + static block_header *from_first_header(Header *header) + { + block_header * hdr = + reinterpret_cast*>(reinterpret_cast(header) + + get_rounded_size(size_type(sizeof(Header)), size_type(::boost::alignment_of >::value))); + //Some sanity checks + return hdr; + } + + template + static Header *to_first_header(block_header *bheader) + { + Header * hdr = + reinterpret_cast(reinterpret_cast(bheader) - + get_rounded_size(size_type(sizeof(Header)), size_type(::boost::alignment_of >::value))); + //Some sanity checks + return hdr; + } +}; + +inline void array_construct(void *mem, std::size_t num, in_place_interface &table) +{ + //Try constructors + std::size_t constructed = 0; + BOOST_TRY{ + table.construct_n(mem, num, constructed); + } + //If there is an exception call destructors and erase index node + BOOST_CATCH(...){ + std::size_t destroyed = 0; + table.destroy_n(mem, constructed, destroyed); + BOOST_RETHROW + } + BOOST_CATCH_END +} + +template +struct intrusive_compare_key +{ + typedef CharT char_type; + + intrusive_compare_key(const CharT *str, std::size_t len) + : mp_str(str), m_len(len) + {} + + const CharT * mp_str; + std::size_t m_len; +}; + +//!This struct indicates an anonymous object creation +//!allocation +template +class instance_t +{ + instance_t(){} +}; + +template +struct char_if_void +{ + typedef T type; +}; + +template<> +struct char_if_void +{ + typedef char type; +}; + +typedef instance_t anonymous_instance_t; +typedef instance_t unique_instance_t; + + +template +struct intrusive_value_type_impl + : public Hook +{ + private: + //Non-copyable + intrusive_value_type_impl(const intrusive_value_type_impl &); + intrusive_value_type_impl& operator=(const intrusive_value_type_impl &); + + public: + typedef CharType char_type; + typedef SizeType size_type; + + intrusive_value_type_impl(){} + + enum { BlockHdrAlignment = ::boost::alignment_of >::value }; + + block_header *get_block_header() const + { + return const_cast*> + (reinterpret_cast *>(reinterpret_cast(this) + + get_rounded_size(size_type(sizeof(*this)), size_type(BlockHdrAlignment)))); + } + + bool operator <(const intrusive_value_type_impl & other) const + { return (this->get_block_header())->template less_comp(*other.get_block_header()); } + + bool operator ==(const intrusive_value_type_impl & other) const + { return (this->get_block_header())->template equal_comp(*other.get_block_header()); } + + static intrusive_value_type_impl *get_intrusive_value_type(block_header *hdr) + { + return reinterpret_cast(reinterpret_cast(hdr) - + get_rounded_size(size_type(sizeof(intrusive_value_type_impl)), size_type(BlockHdrAlignment))); + } + + CharType *name() const + { return get_block_header()->template name(); } + + unsigned short name_length() const + { return get_block_header()->name_length(); } + + void *value() const + { return get_block_header()->value(); } +}; + +template +class char_ptr_holder +{ + public: + char_ptr_holder(const CharType *name) + : m_name(name) + {} + + char_ptr_holder(const anonymous_instance_t *) + : m_name(static_cast(0)) + {} + + char_ptr_holder(const unique_instance_t *) + : m_name(reinterpret_cast(-1)) + {} + + operator const CharType *() + { return m_name; } + + private: + const CharType *m_name; +}; + +//!The key of the the named allocation information index. Stores an offset pointer +//!to a null terminated string and the length of the string to speed up sorting +template +struct index_key +{ + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_char_ptr_t; + typedef CharT char_type; + typedef typename boost::intrusive::pointer_traits::difference_type difference_type; + typedef typename boost::make_unsigned::type size_type; + + private: + //Offset pointer to the object's name + const_char_ptr_t mp_str; + //Length of the name buffer (null NOT included) + size_type m_len; + public: + + //!Constructor of the key + index_key (const char_type *name, size_type length) + : mp_str(name), m_len(length) {} + + //!Less than function for index ordering + bool operator < (const index_key & right) const + { + return (m_len < right.m_len) || + (m_len == right.m_len && + std::char_traits::compare + (to_raw_pointer(mp_str) + ,to_raw_pointer(right.mp_str), m_len) < 0); + } + + //!Equal to function for index ordering + bool operator == (const index_key & right) const + { + return m_len == right.m_len && + std::char_traits::compare + (to_raw_pointer(mp_str), + to_raw_pointer(right.mp_str), m_len) == 0; + } + + void name(const CharT *name) + { mp_str = name; } + + void name_length(size_type len) + { m_len = len; } + + const CharT *name() const + { return to_raw_pointer(mp_str); } + + size_type name_length() const + { return m_len; } +}; + +//!The index_data stores a pointer to a buffer and the element count needed +//!to know how many destructors must be called when calling destroy +template +struct index_data +{ + typedef VoidPointer void_pointer; + void_pointer m_ptr; + index_data(void *ptr) : m_ptr(ptr){} + + void *value() const + { return static_cast(to_raw_pointer(m_ptr)); } +}; + +template +struct segment_manager_base_type +{ typedef segment_manager_base type; }; + +template +struct index_config +{ + typedef typename MemoryAlgorithm::void_pointer void_pointer; + typedef CharT char_type; + typedef index_key key_type; + typedef index_data mapped_type; + typedef typename segment_manager_base_type + ::type segment_manager_base; + + template + struct intrusive_value_type + { typedef intrusive_value_type_impl type; }; + + typedef intrusive_compare_key intrusive_compare_key_type; +}; + +template +class segment_manager_iterator_value_adaptor +{ + typedef typename Iterator::value_type iterator_val_t; + typedef typename iterator_val_t::char_type char_type; + + public: + segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val) + : m_val(&val) + {} + + const char_type *name() const + { return m_val->name(); } + + unsigned short name_length() const + { return m_val->name_length(); } + + const void *value() const + { return m_val->value(); } + + const typename Iterator::value_type *m_val; +}; + + +template +class segment_manager_iterator_value_adaptor +{ + typedef typename Iterator::value_type iterator_val_t; + typedef typename iterator_val_t::first_type first_type; + typedef typename iterator_val_t::second_type second_type; + typedef typename first_type::char_type char_type; + typedef typename first_type::size_type size_type; + + public: + segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val) + : m_val(&val) + {} + + const char_type *name() const + { return m_val->first.name(); } + + size_type name_length() const + { return m_val->first.name_length(); } + + const void *value() const + { + return reinterpret_cast*> + (to_raw_pointer(m_val->second.m_ptr))->value(); + } + + const typename Iterator::value_type *m_val; +}; + +template +struct segment_manager_iterator_transform + : std::unary_function< typename Iterator::value_type + , segment_manager_iterator_value_adaptor > +{ + typedef segment_manager_iterator_value_adaptor result_type; + + result_type operator()(const typename Iterator::value_type &arg) const + { return result_type(arg); } +}; + +} //namespace ipcdetail { + +//These pointers are the ones the user will use to +//indicate previous allocation types +static const ipcdetail::anonymous_instance_t * anonymous_instance = 0; +static const ipcdetail::unique_instance_t * unique_instance = 0; + +namespace ipcdetail_really_deep_namespace { + +//Otherwise, gcc issues a warning of previously defined +//anonymous_instance and unique_instance +struct dummy +{ + dummy() + { + (void)anonymous_instance; + (void)unique_instance; + } +}; + +} //detail_really_deep_namespace + +}} //namespace boost { namespace interprocess + +#include + +#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP + diff --git a/boost/interprocess/detail/tmp_dir_helpers.hpp b/boost/interprocess/detail/tmp_dir_helpers.hpp new file mode 100644 index 0000000000..38aafb2beb --- /dev/null +++ b/boost/interprocess/detail/tmp_dir_helpers.hpp @@ -0,0 +1,174 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP +#define BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP + +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_WINDOWS) + //#define BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME + //#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME + //#include +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) + //#include + //#if defined(CTL_KERN) && defined (KERN_BOOTTIME) + //#define BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME + //#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME + //#endif +#endif + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +#if defined (BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME) +inline void get_bootstamp(std::string &s, bool add = false) +{ + std::string bootstamp; + winapi::get_last_bootup_time(bootstamp); + if(add){ + s += bootstamp; + } + else{ + s.swap(bootstamp); + } +} +#elif defined(BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME) +inline void get_bootstamp(std::string &s, bool add = false) +{ + // FreeBSD specific: sysctl "kern.boottime" + int request[2] = { CTL_KERN, KERN_BOOTTIME }; + struct ::timeval result; + std::size_t result_len = sizeof result; + + if (::sysctl (request, 2, &result, &result_len, NULL, 0) < 0) + return; + + char bootstamp_str[256]; + + const char Characters [] = + { '0', '1', '2', '3', '4', '5', '6', '7' + , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + std::size_t char_counter = 0; + //32 bit values to allow 32 and 64 bit process IPC + boost::uint32_t fields[2] = { boost::uint32_t(result.tv_sec), boost::uint32_t(result.tv_usec) }; + for(std::size_t field = 0; field != 2; ++field){ + for(std::size_t i = 0; i != sizeof(fields[0]); ++i){ + const char *ptr = (const char *)&fields[field]; + bootstamp_str[char_counter++] = Characters[(ptr[i]&0xF0)>>4]; + bootstamp_str[char_counter++] = Characters[(ptr[i]&0x0F)]; + } + } + bootstamp_str[char_counter] = 0; + if(add){ + s += bootstamp_str; + } + else{ + s = bootstamp_str; + } +} +#endif + +inline void get_tmp_base_dir(std::string &tmp_name) +{ + #if defined (BOOST_INTERPROCESS_WINDOWS) + winapi::get_shared_documents_folder(tmp_name); + if(tmp_name.empty() || !winapi::is_directory(tmp_name.c_str())){ + tmp_name = get_temporary_path(); + } + #else + tmp_name = get_temporary_path(); + #endif + if(tmp_name.empty()){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + //Remove final null. + tmp_name += "/boost_interprocess"; +} + +inline void tmp_folder(std::string &tmp_name) +{ + get_tmp_base_dir(tmp_name); + #ifdef BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME + tmp_name += "/"; + get_bootstamp(tmp_name, true); + #endif +} + +inline void tmp_filename(const char *filename, std::string &tmp_name) +{ + tmp_folder(tmp_name); + tmp_name += "/"; + tmp_name += filename; +} + +inline void create_tmp_and_clean_old(std::string &tmp_name) +{ + //First get the temp directory + std::string root_tmp_name; + get_tmp_base_dir(root_tmp_name); + + //If fails, check that it's because already exists + if(!create_directory(root_tmp_name.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } + } + + #ifdef BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME + tmp_folder(tmp_name); + + //If fails, check that it's because already exists + if(!create_directory(tmp_name.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } + } + //Now erase all old directories created in the previous boot sessions + std::string subdir = tmp_name; + subdir.erase(0, root_tmp_name.size()+1); + delete_subdirectories(root_tmp_name, subdir.c_str()); + #else + tmp_name = root_tmp_name; + #endif +} + +inline void create_tmp_and_clean_old_and_get_filename(const char *filename, std::string &tmp_name) +{ + create_tmp_and_clean_old(tmp_name); + tmp_name += "/"; + tmp_name += 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 + +#endif //ifndef BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP diff --git a/boost/interprocess/detail/transform_iterator.hpp b/boost/interprocess/detail/transform_iterator.hpp new file mode 100644 index 0000000000..ef646fbefe --- /dev/null +++ b/boost/interprocess/detail/transform_iterator.hpp @@ -0,0 +1,195 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP +#define BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +#include +#include + +namespace boost { +namespace interprocess { + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(const PseudoReference &px) + : m_value(px) + {} + + PseudoReference* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable PseudoReference m_value; +}; + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(T &px) + : m_value(px) + {} + + T* operator->() const { return const_cast(&m_value); } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + T &m_value; +}; + +template +class transform_iterator + : public UnaryFunction + , public std::iterator + < typename Iterator::iterator_category + , typename ipcdetail::remove_reference::type + , typename Iterator::difference_type + , operator_arrow_proxy + , typename UnaryFunction::result_type> +{ + public: + explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction()) + : UnaryFunction(f), m_it(it) + {} + + explicit transform_iterator() + : UnaryFunction(), m_it() + {} + + //Constructors + transform_iterator& operator++() + { increment(); return *this; } + + transform_iterator operator++(int) + { + transform_iterator result (*this); + increment(); + return result; + } + + transform_iterator& operator--() + { decrement(); return *this; } + + transform_iterator operator--(int) + { + transform_iterator result (*this); + decrement(); + return result; + } + + friend bool operator== (const transform_iterator& i, const transform_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const transform_iterator& i, const transform_iterator& i2) + { return !(i == i2); } + + friend bool operator< (const transform_iterator& i, const transform_iterator& i2) + { return i < i2; } + + friend bool operator> (const transform_iterator& i, const transform_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const transform_iterator& i, const transform_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const transform_iterator& i, const transform_iterator& i2) + { return !(i < i2); } + + friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + transform_iterator& operator+=(typename Iterator::difference_type off) + { this->advance(off); return *this; } + + transform_iterator operator+(typename Iterator::difference_type off) const + { + transform_iterator other(*this); + other.advance(off); + return other; + } + + friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right) + { return right + off; } + + transform_iterator& operator-=(typename Iterator::difference_type off) + { this->advance(-off); return *this; } + + transform_iterator operator-(typename Iterator::difference_type off) const + { return *this + (-off); } + + typename UnaryFunction::result_type operator*() const + { return dereference(); } + + typename UnaryFunction::result_type operator[](typename Iterator::difference_type off) const + { return UnaryFunction::operator()(m_it[off]); } + + operator_arrow_proxy + operator->() const + { return operator_arrow_proxy(dereference()); } + + Iterator & base() + { return m_it; } + + const Iterator & base() const + { return m_it; } + + private: + Iterator m_it; + + void increment() + { ++m_it; } + + void decrement() + { --m_it; } + + bool equal(const transform_iterator &other) const + { return m_it == other.m_it; } + + bool less(const transform_iterator &other) const + { return other.m_it < m_it; } + + typename UnaryFunction::result_type dereference() const + { return UnaryFunction::operator()(*m_it); } + + void advance(typename Iterator::difference_type n) + { std::advance(m_it, n); } + + typename Iterator::difference_type distance_to(const transform_iterator &other)const + { return std::distance(other.m_it, m_it); } +}; + +template +transform_iterator +make_transform_iterator(Iterator it, UnaryFunc fun) +{ + return transform_iterator(it, fun); +} + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + diff --git a/boost/interprocess/detail/type_traits.hpp b/boost/interprocess/detail/type_traits.hpp new file mode 100644 index 0000000000..2cfa0be291 --- /dev/null +++ b/boost/interprocess/detail/type_traits.hpp @@ -0,0 +1,145 @@ +////////////////////////////////////////////////////////////////////////////// +// (C) Copyright John Maddock 2000. +// (C) Copyright Ion Gaztanaga 2005-2011. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP +#define BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +struct nat{}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct is_reference +{ + static const bool value = false; +}; + +template +struct is_reference +{ + static const bool value = true; +}; + +template +struct is_pointer +{ + static const bool value = false; +}; + +template +struct is_pointer +{ + static const bool value = true; +}; + +template +struct add_reference +{ + typedef T& type; +}; + +template +struct add_reference +{ + typedef T& type; +}; + +template<> +struct add_reference +{ + typedef nat &type; +}; + +template<> +struct add_reference +{ + typedef const nat &type; +}; + +template +struct add_const_reference +{ typedef const T &type; }; + +template +struct add_const_reference +{ typedef T& type; }; + +template +struct remove_const +{ + typedef T type; +}; + +template +struct remove_const +{ + typedef T type; +}; + +template +struct remove_volatile +{ + typedef T type; +}; + +template +struct remove_volatile +{ + typedef T type; +}; + +template +struct is_same +{ + typedef char yes_type; + struct no_type + { + char padding[8]; + }; + + template + 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)); +}; + +} // namespace ipcdetail +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP diff --git a/boost/interprocess/detail/utilities.hpp b/boost/interprocess/detail/utilities.hpp new file mode 100644 index 0000000000..625a9159d3 --- /dev/null +++ b/boost/interprocess/detail/utilities.hpp @@ -0,0 +1,160 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. +// (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 + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +inline T* to_raw_pointer(T* p) +{ return p; } + +template +inline typename boost::intrusive::pointer_traits::element_type* +to_raw_pointer(const Pointer &p) +{ return boost::interprocess::ipcdetail::to_raw_pointer(p.operator->()); } + +//!To avoid ADL problems with swap +template +inline void do_swap(T& x, T& y) +{ + using std::swap; + swap(x, y); +} + +//Rounds "orig_size" by excess to round_to bytes +template +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 +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 +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 +inline SizeType get_truncated_size_po2(SizeType orig_size, SizeType multiple) +{ + return (orig_size & (~(multiple-1))); +} + +template +struct ct_rounded_size +{ + static const std::size_t value = ((OrigSize-1)/RoundTo+1)*RoundTo; +}; + +// Gennaro Prota wrote this. Thanks! +template +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 +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 +struct is_intrusive_index +{ + static const bool value = false; +}; + +template T* +addressof(T& v) +{ + return reinterpret_cast( + &const_cast(reinterpret_cast(v))); +} + +//Anti-exception node eraser +template +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); } + + void release() { m_erase = false; } + + private: + Cont &m_cont; + typename Cont::iterator m_index_it; + bool m_erase; +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP + diff --git a/boost/interprocess/detail/variadic_templates_tools.hpp b/boost/interprocess/detail/variadic_templates_tools.hpp new file mode 100644 index 0000000000..1e6c4216e3 --- /dev/null +++ b/boost/interprocess/detail/variadic_templates_tools.hpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP +#define BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include //std::size_t + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +class tuple; + +template<> class tuple<> +{}; + +template +class tuple + : private tuple +{ + typedef tuple inherited; + + public: + tuple() { } + + // implicit copy-constructor is okay + // Construct tuple from separate arguments. + tuple(typename add_const_reference::type v, + typename add_const_reference::type... vtail) + : inherited(vtail...), m_head(v) + {} + + // Construct tuple from another tuple. + template + tuple(const tuple& other) + : m_head(other.head()), inherited(other.tail()) + {} + + template + tuple& operator=(const tuple& other) + { + m_head = other.head(); + tail() = other.tail(); + return this; + } + + typename add_reference::type head() { return m_head; } + typename add_reference::type head() const { return m_head; } + + inherited& tail() { return *this; } + const inherited& tail() const { return *this; } + + protected: + Head m_head; +}; + + +template +tuple tie_forward(Values&&... values) +{ return tuple(values...); } + +template +struct tuple_element; + +template +struct tuple_element > +{ + typedef typename tuple_element >::type type; +}; + +template +struct tuple_element<0, tuple > +{ + typedef Head type; +}; + +template +class get_impl; + +template +class get_impl > +{ + typedef typename tuple_element >::type Element; + typedef get_impl > Next; + + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return Next::get(t.tail()); } + static const_type get(const tuple& t) { return Next::get(t.tail()); } +}; + +template +class get_impl<0, tuple > +{ + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return t.head(); } + static const_type get(const tuple& t){ return t.head(); } +}; + +template +typename get_impl >::type get(tuple& t) +{ return get_impl >::get(t); } + +template +typename get_impl >::const_type get(const tuple& t) +{ return get_impl >::get(t); } + +//////////////////////////////////////////////////// +// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will +// be used to "unpack" into comma-separated values +// in a function call. +//////////////////////////////////////////////////// + +template +struct index_tuple{}; + +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + + +}}} //namespace boost { namespace interprocess { namespace ipcdetail { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP diff --git a/boost/interprocess/detail/win32_api.hpp b/boost/interprocess/detail/win32_api.hpp new file mode 100644 index 0000000000..b420c3d67b --- /dev/null +++ b/boost/interprocess/detail/win32_api.hpp @@ -0,0 +1,1766 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_WIN32_PRIMITIVES_HPP +#define BOOST_INTERPROCESS_WIN32_PRIMITIVES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +# pragma comment( lib, "advapi32.lib" ) +# pragma comment( lib, "oleaut32.lib" ) +# pragma comment( lib, "Ole32.lib" ) +# pragma comment( lib, "Psapi.lib" ) +#endif + +#if (defined BOOST_INTERPROCESS_WINDOWS) +# include +# include +#else +# error "This file can only be included in Windows OS" +#endif + + +//The structures used in Interprocess with the +//same binary interface as windows ones +namespace boost { +namespace interprocess { +namespace winapi { + +//Some used constants +static const unsigned long infinite_time = 0xFFFFFFFF; +static const unsigned long error_already_exists = 183L; +static const unsigned long error_sharing_violation = 32L; +static const unsigned long error_file_not_found = 2u; +static const unsigned long error_no_more_files = 18u; +//Retries in CreateFile, see http://support.microsoft.com/kb/316609 +static const unsigned int error_sharing_violation_tries = 3u; +static const unsigned int error_sharing_violation_sleep_ms = 250u; +static const unsigned int error_file_too_large = 223u; + +static const unsigned long semaphore_all_access = (0x000F0000L)|(0x00100000L)|0x3; +static const unsigned long mutex_all_access = (0x000F0000L)|(0x00100000L)|0x0001; + +static const unsigned long page_readonly = 0x02; +static const unsigned long page_readwrite = 0x04; +static const unsigned long page_writecopy = 0x08; + +static const unsigned long standard_rights_required = 0x000F0000L; +static const unsigned long section_query = 0x0001; +static const unsigned long section_map_write = 0x0002; +static const unsigned long section_map_read = 0x0004; +static const unsigned long section_map_execute = 0x0008; +static const unsigned long section_extend_size = 0x0010; +static const unsigned long section_all_access = standard_rights_required | + section_query | + section_map_write | + section_map_read | + section_map_execute | + section_extend_size; + +static const unsigned long file_map_copy = section_query; +static const unsigned long file_map_write = section_map_write; +static const unsigned long file_map_read = section_map_read; +static const unsigned long file_map_all_access = section_all_access; +static const unsigned long delete_access = 0x00010000L; +static const unsigned long file_flag_backup_semantics = 0x02000000; +static const long file_flag_delete_on_close = 0x04000000; + +//Native API constants +static const unsigned long file_open_for_backup_intent = 0x00004000; +static const int file_share_valid_flags = 0x00000007; +static const long file_delete_on_close = 0x00001000L; +static const long obj_case_insensitive = 0x00000040L; + +static const unsigned long movefile_copy_allowed = 0x02; +static const unsigned long movefile_delay_until_reboot = 0x04; +static const unsigned long movefile_replace_existing = 0x01; +static const unsigned long movefile_write_through = 0x08; +static const unsigned long movefile_create_hardlink = 0x10; +static const unsigned long movefile_fail_if_not_trackable = 0x20; + +static const unsigned long file_share_read = 0x00000001; +static const unsigned long file_share_write = 0x00000002; +static const unsigned long file_share_delete = 0x00000004; + +static const unsigned long file_attribute_readonly = 0x00000001; +static const unsigned long file_attribute_hidden = 0x00000002; +static const unsigned long file_attribute_system = 0x00000004; +static const unsigned long file_attribute_directory = 0x00000010; +static const unsigned long file_attribute_archive = 0x00000020; +static const unsigned long file_attribute_device = 0x00000040; +static const unsigned long file_attribute_normal = 0x00000080; +static const unsigned long file_attribute_temporary = 0x00000100; + +static const unsigned long generic_read = 0x80000000L; +static const unsigned long generic_write = 0x40000000L; + +static const unsigned long wait_object_0 = 0; +static const unsigned long wait_abandoned = 0x00000080L; +static const unsigned long wait_timeout = 258L; +static const unsigned long wait_failed = (unsigned long)0xFFFFFFFF; + +static const unsigned long duplicate_close_source = (unsigned long)0x00000001; +static const unsigned long duplicate_same_access = (unsigned long)0x00000002; + +static const unsigned long format_message_allocate_buffer + = (unsigned long)0x00000100; +static const unsigned long format_message_ignore_inserts + = (unsigned long)0x00000200; +static const unsigned long format_message_from_string + = (unsigned long)0x00000400; +static const unsigned long format_message_from_hmodule + = (unsigned long)0x00000800; +static const unsigned long format_message_from_system + = (unsigned long)0x00001000; +static const unsigned long format_message_argument_array + = (unsigned long)0x00002000; +static const unsigned long format_message_max_width_mask + = (unsigned long)0x000000FF; +static const unsigned long lang_neutral = (unsigned long)0x00; +static const unsigned long sublang_default = (unsigned long)0x01; +static const unsigned long invalid_file_size = (unsigned long)0xFFFFFFFF; +static const unsigned long invalid_file_attributes = ((unsigned long)-1); +static void * const invalid_handle_value = (void*)(long)(-1); +static const unsigned long create_new = 1; +static const unsigned long create_always = 2; +static const unsigned long open_existing = 3; +static const unsigned long open_always = 4; +static const unsigned long truncate_existing = 5; + +static const unsigned long file_begin = 0; +static const unsigned long file_current = 1; +static const unsigned long file_end = 2; + +static const unsigned long lockfile_fail_immediately = 1; +static const unsigned long lockfile_exclusive_lock = 2; +static const unsigned long error_lock_violation = 33; +static const unsigned long security_descriptor_revision = 1; + +//Own defines +static const long SystemTimeOfDayInfoLength = 48; +static const long BootAndSystemstampLength = 16; +static const long BootstampLength = 8; +static const unsigned long MaxPath = 260; + + +//Keys +static void * const hkey_local_machine = (void*)(unsigned long*)(long)(0x80000002); +static unsigned long key_query_value = 0x0001; + +//COM API +const unsigned long RPC_C_AUTHN_LEVEL_PKT_BIPC = 4; +const unsigned long RPC_C_AUTHN_DEFAULT_BIPC = 0xffffffffL; +const unsigned long RPC_C_AUTHZ_DEFAULT_BIPC = 0xffffffffL; +const unsigned long RPC_C_IMP_LEVEL_IMPERSONATE_BIPC = 3; +const signed long EOAC_NONE_BIPC = 0; +const signed long CLSCTX_INPROC_SERVER_BIPC = 0x1; +const signed long CLSCTX_LOCAL_SERVER_BIPC = 0x4; +const signed long WBEM_FLAG_RETURN_IMMEDIATELY_BIPC = 0x10; +const signed long WBEM_FLAG_RETURN_WHEN_COMPLETE_BIPC = 0x0; +const signed long WBEM_FLAG_FORWARD_ONLY_BIPC = 0x20; +const signed long WBEM_INFINITE_BIPC = 0xffffffffL; +const signed long RPC_E_TOO_LATE_BIPC = 0x80010119L; +const signed long S_OK_BIPC = 0L; +const signed long S_FALSE_BIPC = 1; + +} //namespace winapi { +} //namespace interprocess { +} //namespace boost { + + +namespace boost { +namespace interprocess { +namespace winapi { + +struct GUID_BIPC +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +}; + +const GUID_BIPC CLSID_WbemAdministrativeLocator = + { 0xcb8555cc, 0x9128, 0x11d1, {0xad, 0x9b, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff}}; + +const GUID_BIPC IID_IUnknown = { 0x00000000, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; + +struct wchar_variant +{ + unsigned long long dummy; + union value_t{ + wchar_t *pbstrVal; + unsigned long long dummy; + } value; +}; + + struct IUnknown_BIPC + { + public: + virtual long __stdcall QueryInterface( + /* [in] */ const GUID_BIPC &riid, + /* [iid_is][out] */ void **ppvObject) = 0; + + virtual unsigned long __stdcall AddRef( void) = 0; + + virtual unsigned long __stdcall Release( void) = 0; + }; + +struct IWbemClassObject_BIPC : public IUnknown_BIPC +{ + public: + virtual long __stdcall GetQualifierSet( + /* [out] */ void **ppQualSet) = 0; + + virtual long __stdcall Get( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags, + /* [unique][in][out] */ wchar_variant *pVal, + /* [unique][in][out] */ long *pType, + /* [unique][in][out] */ long *plFlavor) = 0; + + virtual long __stdcall Put( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags, + /* [in] */ wchar_variant *pVal, + /* [in] */ long Type) = 0; + + virtual long __stdcall Delete( + /* [string][in] */ const wchar_t * wszName) = 0; + + virtual long __stdcall GetNames( + /* [string][in] */ const wchar_t * wszQualifierName, + /* [in] */ long lFlags, + /* [in] */ wchar_variant *pQualifierVal, + /* [out] */ void * *pNames) = 0; + + virtual long __stdcall BeginEnumeration( + /* [in] */ long lEnumFlags) = 0; + + virtual long __stdcall Next( + /* [in] */ long lFlags, + /* [unique][in][out] */ wchar_t * *strName, + /* [unique][in][out] */ wchar_variant *pVal, + /* [unique][in][out] */ long *pType, + /* [unique][in][out] */ long *plFlavor) = 0; + + virtual long __stdcall EndEnumeration( void) = 0; + + virtual long __stdcall GetPropertyQualifierSet( + /* [string][in] */ const wchar_t * wszProperty, + /* [out] */ void **ppQualSet) = 0; + + virtual long __stdcall Clone( + /* [out] */ IWbemClassObject_BIPC **ppCopy) = 0; + + virtual long __stdcall GetObjectText( + /* [in] */ long lFlags, + /* [out] */ wchar_t * *pstrObjectText) = 0; + + virtual long __stdcall SpawnDerivedClass( + /* [in] */ long lFlags, + /* [out] */ IWbemClassObject_BIPC **ppNewClass) = 0; + + virtual long __stdcall SpawnInstance( + /* [in] */ long lFlags, + /* [out] */ IWbemClassObject_BIPC **ppNewInstance) = 0; + + virtual long __stdcall CompareTo( + /* [in] */ long lFlags, + /* [in] */ IWbemClassObject_BIPC *pCompareTo) = 0; + + virtual long __stdcall GetPropertyOrigin( + /* [string][in] */ const wchar_t * wszName, + /* [out] */ wchar_t * *pstrClassName) = 0; + + virtual long __stdcall InheritsFrom( + /* [in] */ const wchar_t * strAncestor) = 0; + + virtual long __stdcall GetMethod( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags, + /* [out] */ IWbemClassObject_BIPC **ppInSignature, + /* [out] */ IWbemClassObject_BIPC **ppOutSignature) = 0; + + virtual long __stdcall PutMethod( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags, + /* [in] */ IWbemClassObject_BIPC *pInSignature, + /* [in] */ IWbemClassObject_BIPC *pOutSignature) = 0; + + virtual long __stdcall DeleteMethod( + /* [string][in] */ const wchar_t * wszName) = 0; + + virtual long __stdcall BeginMethodEnumeration( + /* [in] */ long lEnumFlags) = 0; + + virtual long __stdcall NextMethod( + /* [in] */ long lFlags, + /* [unique][in][out] */ wchar_t * *pstrName, + /* [unique][in][out] */ IWbemClassObject_BIPC **ppInSignature, + /* [unique][in][out] */ IWbemClassObject_BIPC **ppOutSignature) = 0; + + virtual long __stdcall EndMethodEnumeration( void) = 0; + + virtual long __stdcall GetMethodQualifierSet( + /* [string][in] */ const wchar_t * wszMethod, + /* [out] */ void **ppQualSet) = 0; + + virtual long __stdcall GetMethodOrigin( + /* [string][in] */ const wchar_t * wszMethodName, + /* [out] */ wchar_t * *pstrClassName) = 0; + +}; + + +struct IWbemContext_BIPC : public IUnknown_BIPC +{ +public: + virtual long __stdcall Clone( + /* [out] */ IWbemContext_BIPC **ppNewCopy) = 0; + + virtual long __stdcall GetNames( + /* [in] */ long lFlags, + /* [out] */ void * *pNames) = 0; + + virtual long __stdcall BeginEnumeration( + /* [in] */ long lFlags) = 0; + + virtual long __stdcall Next( + /* [in] */ long lFlags, + /* [out] */ wchar_t * *pstrName, + /* [out] */ wchar_variant *pValue) = 0; + + virtual long __stdcall EndEnumeration( void) = 0; + + virtual long __stdcall SetValue( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags, + /* [in] */ wchar_variant *pValue) = 0; + + virtual long __stdcall GetValue( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags, + /* [out] */ wchar_variant *pValue) = 0; + + virtual long __stdcall DeleteValue( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags) = 0; + + virtual long __stdcall DeleteAll( void) = 0; + +}; + + +struct IEnumWbemClassObject_BIPC : public IUnknown_BIPC +{ +public: + virtual long __stdcall Reset( void) = 0; + + virtual long __stdcall Next( + /* [in] */ long lTimeout, + /* [in] */ unsigned long uCount, + /* [length_is][size_is][out] */ IWbemClassObject_BIPC **apObjects, + /* [out] */ unsigned long *puReturned) = 0; + + virtual long __stdcall NextAsync( + /* [in] */ unsigned long uCount, + /* [in] */ void *pSink) = 0; + + virtual long __stdcall Clone( + /* [out] */ void **ppEnum) = 0; + + virtual long __stdcall Skip( + /* [in] */ long lTimeout, + /* [in] */ unsigned long nCount) = 0; + +}; + +struct IWbemServices_BIPC : public IUnknown_BIPC +{ +public: + virtual long __stdcall OpenNamespace( + /* [in] */ const wchar_t * strNamespace, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppWorkingNamespace, + /* [unique][in][out] */ void **ppResult) = 0; + + virtual long __stdcall CancelAsyncCall( + /* [in] */ void *pSink) = 0; + + virtual long __stdcall QueryObjectSink( + /* [in] */ long lFlags, + /* [out] */ void **ppResponseHandler) = 0; + + virtual long __stdcall GetObject( + /* [in] */ const wchar_t * strObjectPath, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppObject, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall GetObjectAsync( + /* [in] */ const wchar_t * strObjectPath, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall PutClass( + /* [in] */ IWbemClassObject_BIPC *pObject, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall PutClassAsync( + /* [in] */ IWbemClassObject_BIPC *pObject, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall DeleteClass( + /* [in] */ const wchar_t * strClass, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall DeleteClassAsync( + /* [in] */ const wchar_t * strClass, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall CreateClassEnum( + /* [in] */ const wchar_t * strSuperclass, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [out] */ void **ppEnum) = 0; + + virtual long __stdcall CreateClassEnumAsync( + /* [in] */ const wchar_t * strSuperclass, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall PutInstance( + /* [in] */ void *pInst, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall PutInstanceAsync( + /* [in] */ void *pInst, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall DeleteInstance( + /* [in] */ const wchar_t * strObjectPath, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall DeleteInstanceAsync( + /* [in] */ const wchar_t * strObjectPath, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall CreateInstanceEnum( + /* [in] */ const wchar_t * strFilter, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [out] */ void **ppEnum) = 0; + + virtual long __stdcall CreateInstanceEnumAsync( + /* [in] */ const wchar_t * strFilter, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall ExecQuery( + /* [in] */ const wchar_t * strQueryLanguage, + /* [in] */ const wchar_t * strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [out] */ IEnumWbemClassObject_BIPC **ppEnum) = 0; + + virtual long __stdcall ExecQueryAsync( + /* [in] */ const wchar_t * strQueryLanguage, + /* [in] */ const wchar_t * strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall ExecNotificationQuery( + /* [in] */ const wchar_t * strQueryLanguage, + /* [in] */ const wchar_t * strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [out] */ void **ppEnum) = 0; + + virtual long __stdcall ExecNotificationQueryAsync( + /* [in] */ const wchar_t * strQueryLanguage, + /* [in] */ const wchar_t * strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall ExecMethod( + /* [in] */ const wchar_t * strObjectPath, + /* [in] */ const wchar_t * strMethodName, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [in] */ IWbemClassObject_BIPC *pInParams, + /* [unique][in][out] */ IWbemClassObject_BIPC **ppOutParams, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall ExecMethodAsync( + /* [in] */ const wchar_t * strObjectPath, + /* [in] */ const wchar_t * strMethodName, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [in] */ IWbemClassObject_BIPC *pInParams, + /* [in] */ void *pResponseHandler) = 0; + +}; + +struct IWbemLocator_BIPC : public IUnknown_BIPC +{ +public: + virtual long __stdcall ConnectServer( + /* [in] */ const wchar_t * strNetworkResource, + /* [in] */ const wchar_t * strUser, + /* [in] */ const wchar_t * strPassword, + /* [in] */ const wchar_t * strLocale, + /* [in] */ long lSecurityFlags, + /* [in] */ const wchar_t * strAuthority, + /* [in] */ void *pCtx, + /* [out] */ IWbemServices_BIPC **ppNamespace) = 0; + +}; + + + +struct interprocess_overlapped +{ + unsigned long *internal; + unsigned long *internal_high; + union { + struct { + unsigned long offset; + unsigned long offset_high; + }dummy; + void *pointer; + }; + + void *h_event; +}; + +struct interprocess_filetime +{ + unsigned long dwLowDateTime; + unsigned long dwHighDateTime; +}; + +struct win32_find_data_t +{ + unsigned long dwFileAttributes; + interprocess_filetime ftCreationTime; + interprocess_filetime ftLastAccessTime; + interprocess_filetime ftLastWriteTime; + unsigned long nFileSizeHigh; + unsigned long nFileSizeLow; + unsigned long dwReserved0; + unsigned long dwReserved1; + char cFileName[MaxPath]; + char cAlternateFileName[14]; +}; + +struct interprocess_security_attributes +{ + unsigned long nLength; + void *lpSecurityDescriptor; + int bInheritHandle; +}; + +struct system_info { + union { + unsigned long dwOemId; // Obsolete field...do not use + struct { + unsigned short wProcessorArchitecture; + unsigned short wReserved; + } dummy; + }; + unsigned long dwPageSize; + void * lpMinimumApplicationAddress; + void * lpMaximumApplicationAddress; + unsigned long * dwActiveProcessorMask; + unsigned long dwNumberOfProcessors; + unsigned long dwProcessorType; + unsigned long dwAllocationGranularity; + unsigned short wProcessorLevel; + unsigned short wProcessorRevision; +}; + +struct interprocess_memory_basic_information +{ + void * BaseAddress; + void * AllocationBase; + unsigned long AllocationProtect; + unsigned long RegionSize; + unsigned long State; + unsigned long Protect; + unsigned long Type; +}; + +typedef struct _interprocess_acl +{ + unsigned char AclRevision; + unsigned char Sbz1; + unsigned short AclSize; + unsigned short AceCount; + unsigned short Sbz2; +} interprocess_acl; + +typedef struct _interprocess_security_descriptor +{ + unsigned char Revision; + unsigned char Sbz1; + unsigned short Control; + void *Owner; + void *Group; + interprocess_acl *Sacl; + interprocess_acl *Dacl; +} interprocess_security_descriptor; + +enum file_information_class_t { + file_directory_information = 1, + file_full_directory_information, + file_both_directory_information, + file_basic_information, + file_standard_information, + file_internal_information, + file_ea_information, + file_access_information, + file_name_information, + file_rename_information, + file_link_information, + file_names_information, + file_disposition_information, + file_position_information, + file_full_ea_information, + file_mode_information, + file_alignment_information, + file_all_information, + file_allocation_information, + file_end_of_file_information, + file_alternate_name_information, + file_stream_information, + file_pipe_information, + file_pipe_local_information, + file_pipe_remote_information, + file_mailslot_query_information, + file_mailslot_set_information, + file_compression_information, + file_copy_on_write_information, + file_completion_information, + file_move_cluster_information, + file_quota_information, + file_reparse_point_information, + file_network_open_information, + file_object_id_information, + file_tracking_information, + file_ole_directory_information, + file_content_index_information, + file_inherit_content_index_information, + file_ole_information, + file_maximum_information +}; + +struct file_name_information_t { + unsigned long FileNameLength; + wchar_t FileName[1]; +}; + +struct file_rename_information_t { + int Replace; + void *RootDir; + unsigned long FileNameLength; + wchar_t FileName[1]; +}; + +struct unicode_string_t { + unsigned short Length; + unsigned short MaximumLength; + wchar_t *Buffer; +}; + +struct object_attributes_t { + unsigned long Length; + void * RootDirectory; + unicode_string_t *ObjectName; + unsigned long Attributes; + void *SecurityDescriptor; + void *SecurityQualityOfService; +}; + +struct io_status_block_t { + union { + long Status; + void *Pointer; + }; + + unsigned long *Information; +}; + +union system_timeofday_information +{ + struct data_t + { + __int64 liKeBootTime; + __int64 liKeSystemTime; + __int64 liExpTimeZoneBias; + unsigned long uCurrentTimeZoneId; + unsigned long dwReserved; + } data; + unsigned char Reserved1[SystemTimeOfDayInfoLength]; +}; + +struct interprocess_by_handle_file_information +{ + unsigned long dwFileAttributes; + interprocess_filetime ftCreationTime; + interprocess_filetime ftLastAccessTime; + interprocess_filetime ftLastWriteTime; + unsigned long dwVolumeSerialNumber; + unsigned long nFileSizeHigh; + unsigned long nFileSizeLow; + unsigned long nNumberOfLinks; + unsigned long nFileIndexHigh; + unsigned long nFileIndexLow; +}; + +enum system_information_class { + system_basic_information = 0, + system_performance_information = 2, + system_time_of_day_information = 3, + system_process_information = 5, + system_processor_performance_information = 8, + system_interrupt_information = 23, + system_exception_information = 33, + system_registry_quota_information = 37, + system_lookaside_information = 45 +}; + +enum object_information_class +{ + object_basic_information, + object_name_information, + object_type_information, + object_all_information, + object_data_information +}; + +struct object_name_information_t +{ + unicode_string_t Name; + wchar_t NameBuffer[1]; +}; + +//Some windows API declarations +extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(); +extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(); +extern "C" __declspec(dllimport) int __stdcall GetProcessTimes + ( void *hProcess, interprocess_filetime* lpCreationTime + , interprocess_filetime *lpExitTime,interprocess_filetime *lpKernelTime + , interprocess_filetime *lpUserTime ); +extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long); +extern "C" __declspec(dllimport) int __stdcall SwitchToThread(); +extern "C" __declspec(dllimport) unsigned long __stdcall GetLastError(); +extern "C" __declspec(dllimport) void __stdcall SetLastError(unsigned long); +extern "C" __declspec(dllimport) void * __stdcall GetCurrentProcess(); +extern "C" __declspec(dllimport) int __stdcall CloseHandle(void*); +extern "C" __declspec(dllimport) int __stdcall DuplicateHandle + ( void *hSourceProcessHandle, void *hSourceHandle + , void *hTargetProcessHandle, void **lpTargetHandle + , unsigned long dwDesiredAccess, int bInheritHandle + , unsigned long dwOptions); +extern "C" __declspec(dllimport) void *__stdcall FindFirstFileA(const char *lpFileName, win32_find_data_t *lpFindFileData); +extern "C" __declspec(dllimport) int __stdcall FindNextFileA(void *hFindFile, win32_find_data_t *lpFindFileData); +extern "C" __declspec(dllimport) int __stdcall FindClose(void *hFindFile); +//extern "C" __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(interprocess_filetime*); +//extern "C" __declspec(dllimport) int __stdcall FileTimeToLocalFileTime(const interprocess_filetime *in, const interprocess_filetime *out); +extern "C" __declspec(dllimport) void * __stdcall CreateMutexA(interprocess_security_attributes*, int, const char *); +extern "C" __declspec(dllimport) void * __stdcall OpenMutexA(unsigned long, int, const char *); +extern "C" __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void *, unsigned long); +extern "C" __declspec(dllimport) int __stdcall ReleaseMutex(void *); +extern "C" __declspec(dllimport) int __stdcall UnmapViewOfFile(void *); +extern "C" __declspec(dllimport) void * __stdcall CreateSemaphoreA(interprocess_security_attributes*, long, long, const char *); +extern "C" __declspec(dllimport) int __stdcall ReleaseSemaphore(void *, long, long *); +extern "C" __declspec(dllimport) void * __stdcall OpenSemaphoreA(unsigned long, int, const char *); +extern "C" __declspec(dllimport) void * __stdcall CreateFileMappingA (void *, interprocess_security_attributes*, unsigned long, unsigned long, unsigned long, const char *); +extern "C" __declspec(dllimport) void * __stdcall MapViewOfFileEx (void *, unsigned long, unsigned long, unsigned long, std::size_t, void*); +extern "C" __declspec(dllimport) void * __stdcall OpenFileMappingA (unsigned long, int, const char *); +extern "C" __declspec(dllimport) void * __stdcall CreateFileA (const char *, unsigned long, unsigned long, struct interprocess_security_attributes*, unsigned long, unsigned long, void *); +extern "C" __declspec(dllimport) int __stdcall DeleteFileA (const char *); +extern "C" __declspec(dllimport) int __stdcall MoveFileExA (const char *, const char *, unsigned long); +extern "C" __declspec(dllimport) void __stdcall GetSystemInfo (struct system_info *); +extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile (void *, std::size_t); +extern "C" __declspec(dllimport) int __stdcall FlushFileBuffers (void *); +extern "C" __declspec(dllimport) int __stdcall GetFileSizeEx (void *, __int64 *size); +extern "C" __declspec(dllimport) unsigned long __stdcall FormatMessageA + (unsigned long dwFlags, const void *lpSource, unsigned long dwMessageId, + unsigned long dwLanguageId, char *lpBuffer, unsigned long nSize, + std::va_list *Arguments); +extern "C" __declspec(dllimport) void *__stdcall LocalFree (void *); +extern "C" __declspec(dllimport) unsigned long __stdcall GetFileAttributesA(const char *); +extern "C" __declspec(dllimport) int __stdcall CreateDirectoryA(const char *, interprocess_security_attributes*); +extern "C" __declspec(dllimport) int __stdcall RemoveDirectoryA(const char *lpPathName); +extern "C" __declspec(dllimport) int __stdcall GetTempPathA(unsigned long length, char *buffer); +extern "C" __declspec(dllimport) int __stdcall CreateDirectory(const char *, interprocess_security_attributes*); +extern "C" __declspec(dllimport) int __stdcall SetFileValidData(void *, __int64 size); +extern "C" __declspec(dllimport) int __stdcall SetEndOfFile(void *); +extern "C" __declspec(dllimport) int __stdcall SetFilePointerEx(void *, __int64 distance, __int64 *new_file_pointer, unsigned long move_method); +extern "C" __declspec(dllimport) int __stdcall LockFile (void *hnd, unsigned long offset_low, unsigned long offset_high, unsigned long size_low, unsigned long size_high); +extern "C" __declspec(dllimport) int __stdcall UnlockFile(void *hnd, unsigned long offset_low, unsigned long offset_high, unsigned long size_low, unsigned long size_high); +extern "C" __declspec(dllimport) int __stdcall LockFileEx(void *hnd, unsigned long flags, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped* overlapped); +extern "C" __declspec(dllimport) int __stdcall UnlockFileEx(void *hnd, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped* overlapped); +extern "C" __declspec(dllimport) int __stdcall WriteFile(void *hnd, const void *buffer, unsigned long bytes_to_write, unsigned long *bytes_written, interprocess_overlapped* overlapped); +extern "C" __declspec(dllimport) int __stdcall InitializeSecurityDescriptor(interprocess_security_descriptor *pSecurityDescriptor, unsigned long dwRevision); +extern "C" __declspec(dllimport) int __stdcall SetSecurityDescriptorDacl(interprocess_security_descriptor *pSecurityDescriptor, int bDaclPresent, interprocess_acl *pDacl, int bDaclDefaulted); +extern "C" __declspec(dllimport) void *__stdcall LoadLibraryA(const char *); +extern "C" __declspec(dllimport) int __stdcall FreeLibrary(void *); +extern "C" __declspec(dllimport) void *__stdcall GetProcAddress(void *, const char*); +extern "C" __declspec(dllimport) void *__stdcall GetModuleHandleA(const char*); +extern "C" __declspec(dllimport) void *__stdcall GetFileInformationByHandle(void *, interprocess_by_handle_file_information*); +extern "C" __declspec(dllimport) unsigned long __stdcall GetMappedFileNameW(void *, void *, wchar_t *, unsigned long); +extern "C" __declspec(dllimport) long __stdcall RegOpenKeyExA(void *, const char *, unsigned long, unsigned long, void **); +extern "C" __declspec(dllimport) long __stdcall RegQueryValueExA(void *, const char *, unsigned long*, unsigned long*, unsigned char *, unsigned long*); +extern "C" __declspec(dllimport) long __stdcall RegCloseKey(void *); +extern "C" __declspec(dllimport) int __stdcall QueryPerformanceCounter(__int64 *lpPerformanceCount); + +//COM API +extern "C" __declspec(dllimport) long __stdcall CoInitialize(void *pvReserved); +extern "C" __declspec(dllimport) long __stdcall CoInitializeSecurity( + void* pSecDesc, + long cAuthSvc, + void *asAuthSvc, + void *pReserved1, + unsigned long dwAuthnLevel, + unsigned long dwImpLevel, + void *pAuthList, + unsigned long dwCapabilities, + void *pReserved3 ); + + extern "C" __declspec(dllimport) long __stdcall CoSetProxyBlanket( + IUnknown_BIPC *pProxy, + unsigned long dwAuthnSvc, + unsigned long dwAuthzSvc, + wchar_t *pServerPrincName, + unsigned long dwAuthnLevel, + unsigned long dwImpLevel, + void *pAuthInfo, + unsigned long dwCapabilities); + +extern "C" __declspec(dllimport) long __stdcall VariantClear(wchar_variant * pvarg); +extern "C" __declspec(dllimport) long __stdcall CoCreateInstance(const GUID_BIPC & rclsid, IUnknown_BIPC *pUnkOuter, + unsigned long dwClsContext, const GUID_BIPC & riid, void** ppv); +extern "C" __declspec(dllimport) void __stdcall CoUninitialize(void); + + + +//API function typedefs +//Pointer to functions +typedef long (__stdcall *NtDeleteFile_t)(object_attributes_t *ObjectAttributes); +typedef long (__stdcall *NtSetInformationFile_t)(void *FileHandle, io_status_block_t *IoStatusBlock, void *FileInformation, unsigned long Length, int FileInformationClass ); +typedef long (__stdcall * NtQuerySystemInformation_t)(int, void*, unsigned long, unsigned long *); +typedef long (__stdcall * NtQueryObject_t)(void*, object_information_class, void *, unsigned long, unsigned long *); +typedef long (__stdcall *NtQueryInformationFile_t)(void *,io_status_block_t *,void *, long, int); +typedef long (__stdcall *NtOpenFile_t)(void*,unsigned long ,object_attributes_t*,io_status_block_t*,unsigned long,unsigned long); +typedef long (__stdcall *NtClose_t) (void*); +typedef long (__stdcall *RtlCreateUnicodeStringFromAsciiz_t)(unicode_string_t *, const char *); +typedef void (__stdcall *RtlFreeUnicodeString_t)(unicode_string_t *); +typedef void (__stdcall *RtlInitUnicodeString_t)( unicode_string_t *, const wchar_t * ); +typedef long (__stdcall *RtlAppendUnicodeToString_t)(unicode_string_t *Destination, const wchar_t *Source); +typedef unsigned long (__stdcall * GetMappedFileName_t)(void *, void *, wchar_t *, unsigned long); +typedef long (__stdcall * RegOpenKeyEx_t)(void *, const char *, unsigned long, unsigned long, void **); +typedef long (__stdcall * RegQueryValueEx_t)(void *, const char *, unsigned long*, unsigned long*, unsigned char *, unsigned long*); +typedef long (__stdcall * RegCloseKey_t)(void *); + +} //namespace winapi { +} //namespace interprocess { +} //namespace boost { + +namespace boost { +namespace interprocess { +namespace winapi { + +inline unsigned long get_last_error() +{ return GetLastError(); } + +inline void set_last_error(unsigned long err) +{ return SetLastError(err); } + +inline unsigned long format_message + (unsigned long dwFlags, const void *lpSource, + unsigned long dwMessageId, unsigned long dwLanguageId, + char *lpBuffer, unsigned long nSize, std::va_list *Arguments) +{ + return FormatMessageA + (dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); +} + +//And now, wrapper functions +inline void * local_free(void *hmem) +{ return LocalFree(hmem); } + +inline unsigned long make_lang_id(unsigned long p, unsigned long s) +{ return ((((unsigned short)(s)) << 10) | (unsigned short)(p)); } + +inline void sched_yield() +{ + if(!SwitchToThread()){ + Sleep(1); + } +} + +inline void sleep(unsigned long ms) +{ Sleep(ms); } + +inline unsigned long get_current_thread_id() +{ return GetCurrentThreadId(); } + +inline bool get_process_times + ( void *hProcess, interprocess_filetime* lpCreationTime + , interprocess_filetime *lpExitTime, interprocess_filetime *lpKernelTime + , interprocess_filetime *lpUserTime ) +{ return 0 != GetProcessTimes(hProcess, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime); } + +inline unsigned long get_current_process_id() +{ return GetCurrentProcessId(); } + +inline unsigned int close_handle(void* handle) +{ return CloseHandle(handle); } + +inline void * find_first_file(const char *lpFileName, win32_find_data_t *lpFindFileData) +{ return FindFirstFileA(lpFileName, lpFindFileData); } + +inline bool find_next_file(void *hFindFile, win32_find_data_t *lpFindFileData) +{ return FindNextFileA(hFindFile, lpFindFileData) != 0; } + +inline bool find_close(void *handle) +{ return FindClose(handle) != 0; } + +inline bool duplicate_current_process_handle + (void *hSourceHandle, void **lpTargetHandle) +{ + return 0 != DuplicateHandle + ( GetCurrentProcess(), hSourceHandle, GetCurrentProcess() + , lpTargetHandle, 0, 0 + , duplicate_same_access); +} +/* +inline void get_system_time_as_file_time(interprocess_filetime *filetime) +{ GetSystemTimeAsFileTime(filetime); } + +inline bool file_time_to_local_file_time + (const interprocess_filetime *in, const interprocess_filetime *out) +{ return 0 != FileTimeToLocalFileTime(in, out); } +*/ +inline void *open_or_create_mutex(const char *name, bool initial_owner, interprocess_security_attributes *attr) +{ return CreateMutexA(attr, (int)initial_owner, name); } + +inline unsigned long wait_for_single_object(void *handle, unsigned long time) +{ return WaitForSingleObject(handle, time); } + +inline int release_mutex(void *handle) +{ return ReleaseMutex(handle); } + +inline int unmap_view_of_file(void *address) +{ return UnmapViewOfFile(address); } + +inline void *open_or_create_semaphore(const char *name, long initial_count, long maximum_count, interprocess_security_attributes *attr) +{ return CreateSemaphoreA(attr, initial_count, maximum_count, name); } + +inline int release_semaphore(void *handle, long release_count, long *prev_count) +{ return ReleaseSemaphore(handle, release_count, prev_count); } + +class interprocess_all_access_security +{ + interprocess_security_attributes sa; + interprocess_security_descriptor sd; + bool initialized; + + public: + interprocess_all_access_security() + : initialized(false) + { + if(!InitializeSecurityDescriptor(&sd, security_descriptor_revision)) + return; + if(!SetSecurityDescriptorDacl(&sd, true, 0, false)) + return; + sa.lpSecurityDescriptor = &sd; + sa.nLength = sizeof(interprocess_security_attributes); + sa.bInheritHandle = false; + initialized = false; + } + + interprocess_security_attributes *get_attributes() + { return &sa; } +}; + +inline void * create_file_mapping (void * handle, unsigned long access, unsigned long high_size, unsigned long low_size, const char * name, interprocess_security_attributes *psec) +{ + return CreateFileMappingA (handle, psec, access, high_size, low_size, name); +} + +inline void * open_file_mapping (unsigned long access, const char *name) +{ return OpenFileMappingA (access, 0, name); } + +inline void *map_view_of_file_ex(void *handle, unsigned long file_access, unsigned long highoffset, unsigned long lowoffset, std::size_t numbytes, void *base_addr) +{ return MapViewOfFileEx(handle, file_access, highoffset, lowoffset, numbytes, base_addr); } + +inline void *create_file(const char *name, unsigned long access, unsigned long creation_flags, unsigned long attributes, interprocess_security_attributes *psec) +{ + for (unsigned int attempt(0); attempt < error_sharing_violation_tries; ++attempt){ + void * const handle = CreateFileA(name, access, + file_share_read | file_share_write | file_share_delete, + psec, creation_flags, attributes, 0); + bool const invalid(invalid_handle_value == handle); + if (!invalid){ + return handle; + } + if (error_sharing_violation != get_last_error()){ + return handle; + } + Sleep(error_sharing_violation_sleep_ms); + } + return invalid_handle_value; +} + +inline bool delete_file(const char *name) +{ return 0 != DeleteFileA(name); } + +inline bool move_file_ex(const char *source_filename, const char *destination_filename, unsigned long flags) +{ return 0 != MoveFileExA(source_filename, destination_filename, flags); } + +inline void get_system_info(system_info *info) +{ GetSystemInfo(info); } + +inline bool flush_view_of_file(void *base_addr, std::size_t numbytes) +{ return 0 != FlushViewOfFile(base_addr, numbytes); } + +inline bool flush_file_buffers(void *handle) +{ return 0 != FlushFileBuffers(handle); } + +inline bool get_file_size(void *handle, __int64 &size) +{ return 0 != GetFileSizeEx(handle, &size); } + +inline bool create_directory(const char *name) +{ + interprocess_all_access_security sec; + return 0 != CreateDirectoryA(name, sec.get_attributes()); +} + +inline bool remove_directory(const char *lpPathName) +{ return 0 != RemoveDirectoryA(lpPathName); } + +inline unsigned long get_temp_path(unsigned long length, char *buffer) +{ return GetTempPathA(length, buffer); } + +inline int set_end_of_file(void *handle) +{ return 0 != SetEndOfFile(handle); } + +inline bool set_file_pointer_ex(void *handle, __int64 distance, __int64 *new_file_pointer, unsigned long move_method) +{ return 0 != SetFilePointerEx(handle, distance, new_file_pointer, move_method); } + +inline bool lock_file_ex(void *hnd, unsigned long flags, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped *overlapped) +{ return 0 != LockFileEx(hnd, flags, reserved, size_low, size_high, overlapped); } + +inline bool unlock_file_ex(void *hnd, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped *overlapped) +{ return 0 != UnlockFileEx(hnd, reserved, size_low, size_high, overlapped); } + +inline bool write_file(void *hnd, const void *buffer, unsigned long bytes_to_write, unsigned long *bytes_written, interprocess_overlapped* overlapped) +{ return 0 != WriteFile(hnd, buffer, bytes_to_write, bytes_written, overlapped); } + +inline bool get_file_information_by_handle(void *hnd, interprocess_by_handle_file_information *info) +{ return 0 != GetFileInformationByHandle(hnd, info); } + +inline long interlocked_increment(long volatile *addr) +{ return BOOST_INTERLOCKED_INCREMENT(addr); } + +inline long interlocked_decrement(long volatile *addr) +{ return BOOST_INTERLOCKED_DECREMENT(addr); } + +inline long interlocked_compare_exchange(long volatile *addr, long val1, long val2) +{ return BOOST_INTERLOCKED_COMPARE_EXCHANGE(addr, val1, val2); } + +inline long interlocked_exchange_add(long volatile* addend, long value) +{ return BOOST_INTERLOCKED_EXCHANGE_ADD(const_cast(addend), value); } + +inline long interlocked_exchange(long volatile* addend, long value) +{ return BOOST_INTERLOCKED_EXCHANGE(const_cast(addend), value); } + +//Forward functions +inline void *load_library(const char *name) +{ return LoadLibraryA(name); } + +inline bool free_library(void *module) +{ return 0 != FreeLibrary(module); } + +inline void *get_proc_address(void *module, const char *name) +{ return GetProcAddress(module, name); } + +inline void *get_current_process() +{ return GetCurrentProcess(); } + +inline void *get_module_handle(const char *name) +{ return GetModuleHandleA(name); } + +inline unsigned long get_mapped_file_name(void *process, void *lpv, wchar_t *lpfilename, unsigned long nSize) +{ return GetMappedFileNameW(process, lpv, lpfilename, nSize); } + +inline long reg_open_key_ex(void *hKey, const char *lpSubKey, unsigned long ulOptions, unsigned long samDesired, void **phkResult) +{ return RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult); } + +inline long reg_query_value_ex(void *hKey, const char *lpValueName, unsigned long*lpReserved, unsigned long*lpType, unsigned char *lpData, unsigned long*lpcbData) +{ return RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } + +inline long reg_close_key(void *hKey) +{ return RegCloseKey(hKey); } + +inline bool query_performance_counter(__int64 *lpPerformanceCount) +{ + return 0 != QueryPerformanceCounter(lpPerformanceCount); +} + +inline void initialize_object_attributes +( object_attributes_t *pobject_attr, unicode_string_t *name + , unsigned long attr, void *rootdir, void *security_descr) + +{ + pobject_attr->Length = sizeof(object_attributes_t); + pobject_attr->RootDirectory = rootdir; + pobject_attr->Attributes = attr; + pobject_attr->ObjectName = name; + pobject_attr->SecurityDescriptor = security_descr; + pobject_attr->SecurityQualityOfService = 0; +} + +inline void rtl_init_empty_unicode_string(unicode_string_t *ucStr, wchar_t *buf, unsigned short bufSize) +{ + ucStr->Buffer = buf; + ucStr->Length = 0; + ucStr->MaximumLength = bufSize; +} + +//A class that locates and caches loaded DLL function addresses. +template +struct function_address_holder +{ + enum { NtSetInformationFile, NtQuerySystemInformation, NtQueryObject, NumFunction }; + enum { NtDll_dll, NumModule }; + + private: + static void *FunctionAddresses[NumFunction]; + static volatile long FunctionStates[NumFunction]; + static void *ModuleAddresses[NumModule]; + static volatile long ModuleStates[NumModule]; + + static void *get_module_from_id(unsigned int id) + { + assert(id < (unsigned int)NumModule); + const char *module[] = { "ntdll.dll" }; + bool compile_check[sizeof(module)/sizeof(module[0]) == NumModule]; + (void)compile_check; + return get_module_handle(module[id]); + } + + static void *get_module(const unsigned int id) + { + assert(id < (unsigned int)NumModule); + while(ModuleStates[id] < 2){ + if(interlocked_compare_exchange(&ModuleStates[id], 1, 0) == 0){ + ModuleAddresses[id] = get_module_from_id(id); + interlocked_increment(&ModuleStates[id]); + break; + } + else{ + sched_yield(); + } + } + return ModuleAddresses[id]; + } + + static void *get_address_from_dll(const unsigned int id) + { + assert(id < (unsigned int)NumFunction); + const char *function[] = { "NtSetInformationFile", "NtQuerySystemInformation", "NtQueryObject" }; + bool compile_check[sizeof(function)/sizeof(function[0]) == NumFunction]; + (void)compile_check; + return get_proc_address(get_module(NtDll_dll), function[id]); + } + + public: + static void *get(const unsigned int id) + { + assert(id < (unsigned int)NumFunction); + while(FunctionStates[id] < 2){ + if(interlocked_compare_exchange(&FunctionStates[id], 1, 0) == 0){ + FunctionAddresses[id] = get_address_from_dll(id); + interlocked_increment(&FunctionStates[id]); + break; + } + else{ + sched_yield(); + } + } + return FunctionAddresses[id]; + } +}; + +template +void *function_address_holder::FunctionAddresses[function_address_holder::NumFunction]; + +template +volatile long function_address_holder::FunctionStates[function_address_holder::NumFunction]; + +template +void *function_address_holder::ModuleAddresses[function_address_holder::NumModule]; + +template +volatile long function_address_holder::ModuleStates[function_address_holder::NumModule]; + + +struct dll_func + : public function_address_holder<0> +{}; + +//Complex winapi based functions... +struct library_unloader +{ + void *lib_; + library_unloader(void *module) : lib_(module){} + ~library_unloader(){ free_library(lib_); } +}; + +//pszFilename must have room for at least MaxPath+1 characters +inline bool get_file_name_from_handle_function + (void * hFile, wchar_t *pszFilename, std::size_t length, std::size_t &out_length) +{ + if(length <= MaxPath){ + return false; + } + +// void *hiPSAPI = load_library("PSAPI.DLL"); +// if (0 == hiPSAPI) +// return 0; +// library_unloader unloader(hiPSAPI); + +// Pointer to function getMappedFileName() in PSAPI.DLL +// GetMappedFileName_t pfGMFN = +// (GetMappedFileName_t)get_proc_address(hiPSAPI, "GetMappedFileNameW"); +// if (! pfGMFN){ +// return 0; // Failed: unexpected error +// } + + bool bSuccess = false; + + // Create a file mapping object. + void * hFileMap = create_file_mapping(hFile, page_readonly, 0, 1, 0, 0); + if(hFileMap){ + // Create a file mapping to get the file name. + void* pMem = map_view_of_file_ex(hFileMap, file_map_read, 0, 0, 1, 0); + + if (pMem){ + //out_length = pfGMFN(get_current_process(), pMem, pszFilename, MaxPath); + out_length = get_mapped_file_name(get_current_process(), pMem, pszFilename, MaxPath); + if(out_length){ + bSuccess = true; + } + unmap_view_of_file(pMem); + } + close_handle(hFileMap); + } + + return(bSuccess); +} + +inline bool get_system_time_of_day_information(system_timeofday_information &info) +{ + NtQuerySystemInformation_t pNtQuerySystemInformation = (NtQuerySystemInformation_t) + //get_proc_address(get_module_handle("ntdll.dll"), "NtQuerySystemInformation"); + dll_func::get(dll_func::NtQuerySystemInformation); + unsigned long res; + long status = pNtQuerySystemInformation(system_time_of_day_information, &info, sizeof(info), &res); + if(status){ + return false; + } + return true; +} + +inline bool get_boot_time(unsigned char (&bootstamp) [BootstampLength]) +{ + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + std::memcpy(&bootstamp[0], &info.Reserved1, sizeof(bootstamp)); + return true; +} + +inline bool get_boot_and_system_time(unsigned char (&bootsystemstamp) [BootAndSystemstampLength]) +{ + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + std::memcpy(&bootsystemstamp[0], &info.Reserved1, sizeof(bootsystemstamp)); + return true; +} + +inline bool get_boot_time_str(char *bootstamp_str, std::size_t &s) //will write BootstampLength chars +{ + if(s < (BootstampLength*2)) + return false; + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + 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; + for(std::size_t i = 0; i != static_cast(BootstampLength); ++i){ + bootstamp_str[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4]; + bootstamp_str[char_counter++] = Characters[(info.Reserved1[i]&0x0F)]; + } + s = BootstampLength*2; + return true; +} + +inline bool get_boot_and_system_time_wstr(wchar_t *bootsystemstamp, std::size_t &s) //will write BootAndSystemstampLength chars +{ + if(s < (BootAndSystemstampLength*2)) + return false; + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + const wchar_t Characters [] = + { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7' + , L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F' }; + std::size_t char_counter = 0; + for(std::size_t i = 0; i != static_cast(BootAndSystemstampLength); ++i){ + bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4]; + bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0x0F)]; + } + s = BootAndSystemstampLength*2; + return true; +} + +class handle_closer +{ + void *handle_; + public: + handle_closer(void *handle) : handle_(handle){} + ~handle_closer(){ close_handle(handle_); } +}; + +union ntquery_mem_t +{ + object_name_information_t name; + struct ren_t + { + file_rename_information_t info; + wchar_t buf[32767]; + } ren; +}; + +inline bool unlink_file(const char *filename) +{ + if(!delete_file(filename)){ + try{ + NtSetInformationFile_t pNtSetInformationFile = + //(NtSetInformationFile_t)get_proc_address(get_module_handle("ntdll.dll"), "NtSetInformationFile"); + (NtSetInformationFile_t)dll_func::get(dll_func::NtSetInformationFile); + if(!pNtSetInformationFile){ + return false; + } + + NtQueryObject_t pNtQueryObject = + //(NtQueryObject_t)get_proc_address(get_module_handle("ntdll.dll"), "NtQueryObject"); + (NtQueryObject_t)dll_func::get(dll_func::NtQueryObject); + + //First step: Obtain a handle to the file using Win32 rules. This resolves relative paths + void *fh = create_file(filename, generic_read | delete_access, open_existing, + file_flag_backup_semantics | file_flag_delete_on_close, 0); + if(fh == invalid_handle_value){ + return false; + } + + handle_closer h_closer(fh); + + std::auto_ptr pmem(new ntquery_mem_t); + file_rename_information_t *pfri = &pmem->ren.info; + const std::size_t RenMaxNumChars = + ((char*)pmem.get() - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t); + + //Obtain file name + unsigned long size; + if(pNtQueryObject(fh, object_name_information, pmem.get(), sizeof(ntquery_mem_t), &size)){ + return false; + } + + //Copy filename to the rename member + std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length); + std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t); + + //Second step: obtain the complete native-nt filename + //if(!get_file_name_from_handle_function(fh, pfri->FileName, RenMaxNumChars, filename_string_length)){ + //return 0; + //} + + //Add trailing mark + if((RenMaxNumChars-filename_string_length) < (SystemTimeOfDayInfoLength*2)){ + return false; + } + + //Search '\\' character to replace it + for(std::size_t i = filename_string_length; i != 0; --filename_string_length){ + if(pmem->ren.info.FileName[--i] == L'\\') + break; + } + + //Add random number + std::size_t s = RenMaxNumChars - filename_string_length; + if(!get_boot_and_system_time_wstr(&pfri->FileName[filename_string_length], s)){ + return false; + } + filename_string_length += s; + + //Fill rename information (FileNameLength is in bytes) + pfri->FileNameLength = static_cast(sizeof(wchar_t)*(filename_string_length)); + pfri->Replace = 1; + pfri->RootDir = 0; + + //Final step: change the name of the in-use file: + io_status_block_t io; + if(0 != pNtSetInformationFile(fh, &io, pfri, sizeof(ntquery_mem_t::ren_t), file_rename_information)){ + return false; + } + return true; + } + catch(...){ + return false; + } + } + return true; +} + +struct reg_closer +{ + //reg_closer(RegCloseKey_t func, void *key) : func_(func), key_(key){} + //~reg_closer(){ (*func_)(key_); } + //RegCloseKey_t func_; + void *key_; + reg_closer(void *key) : key_(key){} + ~reg_closer(){ reg_close_key(key_); } +}; + +inline void get_shared_documents_folder(std::string &s) +{ + s.clear(); + //void *hAdvapi = load_library("Advapi32.dll"); + //if (hAdvapi){ + //library_unloader unloader(hAdvapi); + // Pointer to function RegOpenKeyA + //RegOpenKeyEx_t pRegOpenKey = + //(RegOpenKeyEx_t)get_proc_address(hAdvapi, "RegOpenKeyExA"); + //if (pRegOpenKey){ + // Pointer to function RegCloseKey + //RegCloseKey_t pRegCloseKey = + //(RegCloseKey_t)get_proc_address(hAdvapi, "RegCloseKey"); + //if (pRegCloseKey){ + // Pointer to function RegQueryValueA + //RegQueryValueEx_t pRegQueryValue = + //(RegQueryValueEx_t)get_proc_address(hAdvapi, "RegQueryValueExA"); + //if (pRegQueryValue){ + //Open the key + void *key; + //if ((*pRegOpenKey)( hkey_local_machine + //, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" + //, 0 + //, key_query_value + //, &key) == 0){ + //reg_closer key_closer(pRegCloseKey, key); + if (reg_open_key_ex( hkey_local_machine + , "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" + , 0 + , key_query_value + , &key) == 0){ + reg_closer key_closer(key); + + //Obtain the value + unsigned long size; + unsigned long type; + const char *const reg_value = "Common AppData"; + //long err = (*pRegQueryValue)( key, reg_value, 0, &type, 0, &size); + long err = reg_query_value_ex( key, reg_value, 0, &type, 0, &size); + if(!err){ + //Size includes terminating NULL + s.resize(size); + //err = (*pRegQueryValue)( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + err = reg_query_value_ex( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + if(!err) + s.erase(s.end()-1); + (void)err; + } + } + //} + //} + //} + //} +} + + +inline void get_registry_value(const char *folder, const char *value_key, std::vector &s) +{ + s.clear(); + //void *hAdvapi = load_library("Advapi32.dll"); + //if (hAdvapi){ + //library_unloader unloader(hAdvapi); + // Pointer to function RegOpenKeyA + //RegOpenKeyEx_t pRegOpenKey = + //(RegOpenKeyEx_t)get_proc_address(hAdvapi, "RegOpenKeyExA"); + //if (pRegOpenKey){ + // Pointer to function RegCloseKey + //RegCloseKey_t pRegCloseKey = + //(RegCloseKey_t)get_proc_address(hAdvapi, "RegCloseKey"); + //if (pRegCloseKey){ + // Pointer to function RegQueryValueA + //RegQueryValueEx_t pRegQueryValue = + //(RegQueryValueEx_t)get_proc_address(hAdvapi, "RegQueryValueExA"); + //if (pRegQueryValue){ + //Open the key + void *key; + //if ((*pRegOpenKey)( hkey_local_machine + //, folder + //, 0 + //, key_query_value + //, &key) == 0){ + //reg_closer key_closer(pRegCloseKey, key); + if (reg_open_key_ex( hkey_local_machine + , folder + , 0 + , key_query_value + , &key) == 0){ + reg_closer key_closer(key); + + //Obtain the value + unsigned long size; + unsigned long type; + const char *const reg_value = value_key; + //long err = (*pRegQueryValue)( key, reg_value, 0, &type, 0, &size); + long err = reg_query_value_ex( key, reg_value, 0, &type, 0, &size); + if(!err){ + //Size includes terminating NULL + s.resize(size); + //err = (*pRegQueryValue)( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + err = reg_query_value_ex( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + if(!err) + s.erase(s.end()-1); + (void)err; + } + } + //} + //} + //} + //} +} + +struct co_uninitializer +{ ~co_uninitializer() { CoUninitialize(); } }; + +template +struct com_releaser +{ + Object *&object_; + com_releaser(Object *&object) : object_(object) {} + ~com_releaser() { object_->Release(); object_ = 0; } +}; + +inline bool get_wmi_class_attribute( std::wstring& strValue, const wchar_t *wmi_class, const wchar_t *wmi_class_var) +{ + //See example http://msdn.microsoft.com/en-us/library/aa390423%28v=VS.85%29.aspx + long co_init_ret = CoInitialize(0); + if(co_init_ret != S_OK_BIPC && co_init_ret != S_FALSE_BIPC) + return false; + co_uninitializer co_initialize_end; + (void)co_initialize_end; + + bool bRet = false; + long sec_init_ret = CoInitializeSecurity + ( 0 //pVoid + ,-1 //cAuthSvc + , 0 //asAuthSvc + , 0 //pReserved1 + , RPC_C_AUTHN_LEVEL_PKT_BIPC //dwAuthnLevel + , RPC_C_IMP_LEVEL_IMPERSONATE_BIPC //dwImpLevel + , 0 //pAuthList + , EOAC_NONE_BIPC //dwCapabilities + , 0 //pReserved3 + ); + if( 0 == sec_init_ret || RPC_E_TOO_LATE_BIPC == sec_init_ret) + { + IWbemLocator_BIPC * pIWbemLocator = 0; + const wchar_t * bstrNamespace = L"root\\cimv2"; + + if( 0 != CoCreateInstance( + CLSID_WbemAdministrativeLocator, + 0, + CLSCTX_INPROC_SERVER_BIPC | CLSCTX_LOCAL_SERVER_BIPC, + IID_IUnknown, (void **)&pIWbemLocator)){ + return false; + } + + com_releaser IWbemLocator_releaser(pIWbemLocator); + + IWbemServices_BIPC *pWbemServices = 0; + + if( 0 != pIWbemLocator->ConnectServer( + bstrNamespace, // Namespace + 0, // Userid + 0, // PW + 0, // Locale + 0, // flags + 0, // Authority + 0, // Context + &pWbemServices + ) + ){ + return false; + } + + if( S_OK_BIPC != CoSetProxyBlanket( + pWbemServices, + RPC_C_AUTHN_DEFAULT_BIPC, + RPC_C_AUTHZ_DEFAULT_BIPC, + 0, + RPC_C_AUTHN_LEVEL_PKT_BIPC, + RPC_C_IMP_LEVEL_IMPERSONATE_BIPC, + 0, + EOAC_NONE_BIPC + ) + ){ + return false; + } + + com_releaser IWbemServices_releaser(pWbemServices); + + strValue.clear(); + strValue += L"Select "; + strValue += wmi_class_var; + strValue += L" from "; + strValue += wmi_class; + + IEnumWbemClassObject_BIPC * pEnumObject = 0; + + if ( 0 != pWbemServices->ExecQuery( + L"WQL", + strValue.c_str(), + //WBEM_FLAG_RETURN_IMMEDIATELY_BIPC, + WBEM_FLAG_RETURN_WHEN_COMPLETE_BIPC | WBEM_FLAG_FORWARD_ONLY_BIPC, + 0, + &pEnumObject + ) + ){ + return false; + } + + com_releaser IEnumWbemClassObject_releaser(pEnumObject); + + //WBEM_FLAG_FORWARD_ONLY_BIPC incompatible with Reset + //if ( 0 != pEnumObject->Reset() ){ + //return false; + //} + + wchar_variant vwchar; + unsigned long uCount = 1, uReturned; + IWbemClassObject_BIPC * pClassObject = 0; + while( 0 == pEnumObject->Next( WBEM_INFINITE_BIPC, uCount, &pClassObject, &uReturned ) ) + { + com_releaser IWbemClassObject_releaser(pClassObject); + if ( 0 == pClassObject->Get( L"LastBootUpTime", 0, &vwchar, 0, 0 ) ){ + bRet = true; + strValue = vwchar.value.pbstrVal; + VariantClear(&vwchar ); + break; + } + } + } + return bRet; +} + +inline bool get_last_bootup_time( std::wstring& strValue ) +{ + bool ret = get_wmi_class_attribute(strValue, L"Win32_OperatingSystem", L"LastBootUpTime"); + std::size_t timezone = strValue.find(L'+'); + if(timezone != std::wstring::npos){ + strValue.erase(timezone); + } + timezone = strValue.find(L'-'); + if(timezone != std::wstring::npos){ + strValue.erase(timezone); + } + return ret; +} + +inline bool get_last_bootup_time( std::string& str ) +{ + std::wstring wstr; + bool ret = get_last_bootup_time(wstr); + str.resize(wstr.size()); + for(std::size_t i = 0, max = str.size(); i != max; ++i){ + str[i] = '0' + (wstr[i]-L'0'); + } + return ret; +} + +inline bool is_directory(const char *path) +{ + unsigned long attrib = GetFileAttributesA(path); + + return (attrib != invalid_file_attributes && + (attrib & file_attribute_directory)); +} + +} //namespace winapi +} //namespace interprocess +} //namespace boost + +#include + +#endif //#ifdef BOOST_INTERPROCESS_WIN32_PRIMITIVES_HPP diff --git a/boost/interprocess/detail/workaround.hpp b/boost/interprocess/detail/workaround.hpp new file mode 100644 index 0000000000..896a2208a2 --- /dev/null +++ b/boost/interprocess/detail/workaround.hpp @@ -0,0 +1,148 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP +#define BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP + +#include + +#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) + +#define BOOST_INTERPROCESS_WINDOWS + +/* +#if !defined(_MSC_EXTENSIONS) +#error "Turn on Microsoft language extensions (_MSC_EXTENSIONS) to be able to call Windows API functions" +#endif +*/ + +#endif + +#if !defined(BOOST_INTERPROCESS_WINDOWS) + + #include + + #if ((_POSIX_THREAD_PROCESS_SHARED - 0) > 0) + //Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it. + //Mac Os X >= Leopard defines _POSIX_THREAD_PROCESS_SHARED but does not seems to work. + # if !defined(__CYGWIN__) && !defined(__APPLE__) + # define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED + # endif + #endif + + #if ((_POSIX_BARRIERS - 0) > 0) + # define BOOST_INTERPROCESS_POSIX_BARRIERS + # endif + + #if ((_POSIX_SEMAPHORES - 0) > 0) + # define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + # if defined(__CYGWIN__) + #define BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK + # endif + //Some platforms have a limited (name length) named semaphore support + #elif (defined(__FreeBSD__) && (__FreeBSD__ >= 4)) || defined(__APPLE__) + # define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + #endif + + #if ((defined _V6_ILP32_OFFBIG) &&(_V6_ILP32_OFFBIG - 0 > 0)) ||\ + ((defined _V6_LP64_OFF64) &&(_V6_LP64_OFF64 - 0 > 0)) ||\ + ((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 + #else + #endif + + //Check for XSI shared memory objects. They are available in nearly all UNIX platforms + #if !defined(__QNXNTO__) + # define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + #endif + + #if ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0) + # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + #else + //VMS and MACOS don't define it but the have shm_open/close interface + # if defined(__vms) + # if __CRTL_VER >= 70200000 + # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + # endif + //Mac OS has some non-conformant features like names limited to SHM_NAME_MAX + # elif defined (__APPLE__) +// # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS +// # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS_NO_GROW + # endif + #endif + + //Now check if we have only XSI shared memory + #if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) &&\ + !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) + //# define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS_ONLY + #endif + + #if ((_POSIX_TIMEOUTS - 0) > 0) + # define BOOST_INTERPROCESS_POSIX_TIMEOUTS + #endif + + + #ifdef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + //Some systems have filesystem-based resources, so the + //portable "/shmname" format does not work due to permission issues + //For those systems we need to form a path to a temporary directory: + // hp-ux tru64 vms freebsd + #if defined(__hpux) || defined(__osf__) || defined(__vms) || (defined(__FreeBSD__) && (__FreeBSD__ < 7)) + #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY + #elif defined(__FreeBSD__) + #define BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY + #endif + #endif + + #ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + #if defined(__osf__) || defined(__vms) + #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES + #endif + #endif + + #if ((_POSIX_VERSION + 0)>= 200112L || (_XOPEN_VERSION + 0)>= 500) + #define BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES + #endif + +#endif + +#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)\ + && !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL) +#define BOOST_INTERPROCESS_PERFECT_FORWARDING +#endif + +//Now declare some Boost.Interprocess features depending on the implementation + +#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) + +#define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES + +#endif + +#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) + +#define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES +#define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES + +#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 + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP diff --git a/boost/interprocess/detail/xsi_shared_memory_device.hpp b/boost/interprocess/detail/xsi_shared_memory_device.hpp new file mode 100644 index 0000000000..d2e2bf2ce6 --- /dev/null +++ b/boost/interprocess/detail/xsi_shared_memory_device.hpp @@ -0,0 +1,392 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_DEVICE_HPP +#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_DEVICE_HPP + +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_WINDOWS) +#error "This header can't be used in Windows operating systems" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes a class representing a native xsi shared memory. + +namespace boost { +namespace interprocess { + +class xsi_shared_memory_device +{ + /// @cond + BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper) + /// @endcond + + public: + + xsi_shared_memory_device(); + + xsi_shared_memory_device(create_only_t, const char *name, mode_t mode, std::size_t size) + { this->priv_open_or_create_name_only(ipcdetail::DoCreate, name, mode, size); } + + xsi_shared_memory_device(open_or_create_t, const char *name, mode_t mode, std::size_t size) + { this->priv_open_or_create_name_only(ipcdetail::DoOpenOrCreate, name, mode, size); } + + xsi_shared_memory_device(open_only_t, const char *name, mode_t mode) + { this->priv_open_or_create_name_only(ipcdetail::DoOpen, name, mode, 0); } + + xsi_shared_memory_device(create_only_t, const char *filepath, boost::uint8_t id, mode_t mode, std::size_t size) + { this->priv_open_or_create_name_id(ipcdetail::DoCreate, name, id, mode, size); } + + xsi_shared_memory_device(open_or_create_t, const char *filepath, boost::uint8_t id, mode_t mode, std::size_t size) + { this->priv_open_or_create_name_id(ipcdetail::DoOpenOrCreate, id, name, mode, size); } + + xsi_shared_memory_device(open_only_t, const char *filepath, boost::uint8_t id, mode_t mode) + { this->priv_open_or_create_name_id(ipcdetail::DoOpen, name, id, mode, 0); } + + xsi_shared_memory_device(BOOST_RV_REF(xsi_shared_memory_device) moved) + { this->swap(moved); } + + xsi_shared_memory_device &operator=(BOOST_RV_REF(xsi_shared_memory_device) moved) + { + xsi_shared_memory_device tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps two xsi_shared_memory_device. Does not throw + void swap(xsi_shared_memory_device &other); + + //!Destroys *this. The shared memory won't be destroyed, just + //!this connection to it. Use remove() to destroy the shared memory. + ~xsi_shared_memory_device(); + + //!Returns the name of the + //!shared memory. + const char *get_name() const; + + //!Returns the shared memory ID that + //!identifies the shared memory + int get_shmid() const; + + //!Returns access + //!permissions + mode_t get_mode() const; + + //!Returns the mapping handle. + //!Never throws + mapping_handle_t get_mapping_handle() const; + + //!Erases a XSI shared memory object identified by shmname + //!from the system. + //!Returns false on error. Never throws + static bool remove(const char *shmname); + + //!Erases the XSI shared memory object identified by shmid + //!from the system. + //!Returns false on error. Never throws + static bool remove(int shmid); + + /// @cond + private: + template + struct info_constants_t + { + static const std::size_t MaxName = 32; + static const std::size_t FirstID = 2; + static const std::size_t LastID = 256; + static const std::size_t NumID = LastID - FirstID; + }; + + struct info_t + { + struct names_t + { + char buf[info_constants_t<0>::MaxName]; + } names[info_constants_t<0>::NumID]; + }; + + static void priv_obtain_index(mapped_region &m, xsi_named_mutex &m, std::string &path); + static bool priv_remove_dead_memory(info_t *info, const char *path); + + bool priv_open_or_create_name_only( ipcdetail::create_enum_t type + , const char *shmname + , mode_t mode + , std::size_t size); + bool priv_open_or_create_name_id( ipcdetail::create_enum_t type + , const char *shmname + , boost::uint8_t id + , mode_t mode + , std::size_t size); + xsi_shared_memory m_shm; + mode_t m_mode; + std::string m_name; + /// @endcond +}; + +template +const std::size_t xsi_shared_memory_device::info_constants_t::MaxName; + +template +const std::size_t xsi_shared_memory_device::info_constants_t::FirstID; + +template +const std::size_t xsi_shared_memory_device::info_constants_t::LastID; + +template +const std::size_t xsi_shared_memory_device::info_constants_t::NumID; + +/// @cond + +inline xsi_shared_memory_device::xsi_shared_memory_device() + : m_shm(), m_mode(invalid_mode), m_name() +{} + +inline xsi_shared_memory_device::~xsi_shared_memory_device() +{} + +inline const char *xsi_shared_memory_device::get_name() const +{ return m_name.c_str(); } + +inline void xsi_shared_memory_device::swap(xsi_shared_memory_device &other) +{ + m_shm.swap(other.m_shm); + std::swap(m_mode, other.m_mode); + m_name.swap(other.m_name); +} + +inline mapping_handle_t xsi_shared_memory_device::get_mapping_handle() const +{ return m_shm.get_mapping_handle(); } + +inline mode_t xsi_shared_memory_device::get_mode() const +{ return m_mode; } + +inline int xsi_shared_memory::get_shmid() const +{ return m_shm.get_shmid(); } + +inline void xsi_shared_memory_device::priv_obtain_index + (mapped_region ®, xsi_named_mutex &mut, std::string &path) +{ + const char *const filename = "xsi_shm_emulation_file"; + permissions p; + p.set_unrestricted(); + std::string xsi_shm_emulation_file_path; + ipcdetail::create_tmp_and_clean_old_and_get_filename(filename, xsi_shm_emulation_file_path); + ipcdetail::create_or_open_file(xsi_shm_emulation_file_path.c_str(), read_write, p); + const std::size_t MemSize = sizeof(info_t); + + xsi_shared_memory index_shm(open_or_create, xsi_shm_emulation_file_path.c_str(), 1, MemSize, 0666); + mapped_region r(index_shm, read_write, 0, MemSize, 0); + xsi_named_mutex m(open_or_create, xsi_shm_emulation_file_path.c_str(), 2, 0666); + reg = boost::move(r); + mut = boost::move(m); + path.swap(xsi_shm_emulation_file_path); +} + +inline bool xsi_shared_memory_device::priv_remove_dead_memory + (xsi_shared_memory_device::info_t *info, const char *path) +{ + bool removed = false; + for(std::size_t i = 0; i != info_constants_t<0>::NumID; ++i){ + if(info->names[i].buf[0]){ + try{ + xsi_shared_memory temp( open_only, path, i+info_constants_t<0>::FirstID, 0600); + } + catch(interprocess_exception &e){ + if(e.get_error_code() == not_found_error){ + std::memset(info->names[i].buf, 0, info_constants_t<0>::MaxName); + removed = true; + } + } + } + } + return removed; +} + +inline bool xsi_shared_memory_device::priv_open_or_create_name_id + (ipcdetail::create_enum_t type, const char *filepath, mode_t mode, std::size_t size) +{ + //Set accesses + if (mode != read_write && mode != read_only){ + error_info err = other_error; + throw interprocess_exception(err); + } + + int perm = (mode == read_only) ? (0444) : (0666); + + if(type == ipcdetail::DoOpen){ + if(!found){ + error_info err = not_found_error; + throw interprocess_exception(err); + } + xsi_shared_memory temp(open_only, filepath, id, perm); + m_shm = boost::move(temp); + } + else if(type == ipcdetail::DoCreate){ + //Try to reuse slot + xsi_shared_memory temp(create_only, filepath, id, size, perm); + std::strcpy(info->names[target_entry].buf, shmname); + m_shm = boost::move(temp); + } + else{ // if(type == ipcdetail::DoOpenOrCreate){ + xsi_shared_memory temp(open_or_create, filepath, id, size, perm); + m_shm = boost::move(temp); + } + + m_mode = mode; + m_name.clear(); + return true; +} + +inline bool xsi_shared_memory_device::priv_open_or_create_name_only + (ipcdetail::create_enum_t type, const char *shmname, mode_t mode, std::size_t size) +{ + //Set accesses + if (mode != read_write && mode != read_only){ + error_info err = other_error; + throw interprocess_exception(err); + } + + if (std::strlen(shmname) >= (info_constants_t<0>::MaxName)){ + error_info err = other_error; + throw interprocess_exception(err); + } + + { + //Obtain index and index lock + mapped_region region; + xsi_named_mutex mut; + std::string xsi_shm_emulation_file_path; + priv_obtain_index(region, mut, xsi_shm_emulation_file_path); + info_t *info = static_cast(region.get_address()); + scoped_lock lock(mut); + + //Find the correct entry or the first empty index + bool found = false; + int target_entry = -1; + int tries = 2; + while(tries--){ + for(std::size_t i = 0; i != info_constants_t<0>::NumID; ++i){ + if(target_entry < 0 && !info->names[i].buf[0]){ + target_entry = static_cast(i); + } + else if(0 == std::strcmp(info->names[i].buf, shmname)){ + found = true; + target_entry = static_cast(i); + break; + } + } + if(target_entry < 0){ + if(!tries || !priv_remove_dead_memory(info, xsi_shm_emulation_file_path.c_str())){ + error_info err = out_of_resource_error; + throw interprocess_exception(err); + } + } + } + //Now handle the result + int perm = (mode == read_only) ? (0444) : (0666); + if(type == ipcdetail::DoOpen){ + if(!found){ + error_info err = not_found_error; + throw interprocess_exception(err); + } + xsi_shared_memory temp( open_only, xsi_shm_emulation_file_path.c_str() + , target_entry+info_constants_t<0>::FirstID, perm); + m_shm = boost::move(temp); + } + else{ + + if(type == ipcdetail::DoCreate){ + //Try to reuse slot + xsi_shared_memory temp( create_only, xsi_shm_emulation_file_path.c_str() + , target_entry+info_constants_t<0>::FirstID, size, perm); + std::strcpy(info->names[target_entry].buf, shmname); + m_shm = boost::move(temp); + } + else{ // if(type == ipcdetail::DoOpenOrCreate){ + xsi_shared_memory temp( open_or_create, xsi_shm_emulation_file_path.c_str() + , target_entry+info_constants_t<0>::FirstID, size, perm); + if(!found){ + std::memset(info->names[target_entry].buf, 0, info_constants_t<0>::MaxName); + std::strcpy(info->names[target_entry].buf, shmname); + } + m_shm = boost::move(temp); + } + } + } + + m_mode = mode; + m_name = shmname; + return true; +} + +inline bool xsi_shared_memory_device::remove(const char *shmname) +{ + try{ + //Obtain index and index lockss + mapped_region region; + xsi_named_mutex mut; + std::string xsi_shm_emulation_file_path; + priv_obtain_index(region, mut, xsi_shm_emulation_file_path); + scoped_lock lock(mut); + info_t *info = static_cast(region.get_address()); + + //Now check and remove + bool removed = false; + + for(std::size_t i = 0; i != info_constants_t<0>::NumID; ++i){ + if(0 == std::strcmp(info->names[i].buf, name)){ + xsi_shared_memory temp( open_only, xsi_shm_emulation_file_path.c_str() + , i+info_constants_t<0>::FirstID); + if(!xsi_shared_memory::remove(temp.get_shmid()) && (system_error_code() != invalid_argument)){ + return false; + } + std::memset(info->names[i].buf, 0, info_constants_t<0>::MaxName); + removed = true; + break; + } + } + return removed; + } + catch(...){ + return false; + } +} + +inline bool xsi_shared_memory_device::remove(int shmid) +{ return xsi_shared_memory::remove(shmid); } + +///@endcond + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_DEVICE_HPP diff --git a/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp b/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp new file mode 100644 index 0000000000..d74d9664a5 --- /dev/null +++ b/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp @@ -0,0 +1,80 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2011. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP +#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP + +#include +#include +#include + +#if !defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) +#error "This header can't be used in operating systems without XSI (System V) shared memory support" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +//!\file +//!Describes a class representing a pseudo-file implemented on top of xsi shared memory. + +namespace boost { +namespace interprocess { + +class xsi_shared_memory_file_wrapper + : public xsi_shared_memory +{ + /// @cond + BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper) + /// @endcond + public: + + xsi_shared_memory_file_wrapper() : xsi_shared_memory() {} + + xsi_shared_memory_file_wrapper(create_only_t, const xsi_key &key, mode_t mode, std::size_t size, const permissions& perm = permissions()) + : xsi_shared_memory(create_only_t(), key, size, perm.get_permissions()) + {} + + xsi_shared_memory_file_wrapper(open_or_create_t, const xsi_key &key, mode_t mode, std::size_t size, const permissions& perm = permissions()) + : xsi_shared_memory(open_or_create_t(), key, size, perm.get_permissions()) + {} + + xsi_shared_memory_file_wrapper(open_only_t, const xsi_key &key, mode_t mode, const permissions& perm = permissions()) + : xsi_shared_memory(open_only_t(), key) + {} + + xsi_shared_memory_file_wrapper(BOOST_RV_REF(xsi_shared_memory_file_wrapper) moved) + { this->swap(moved); } + + xsi_shared_memory_file_wrapper &operator=(BOOST_RV_REF(xsi_shared_memory_file_wrapper) moved) + { + xsi_shared_memory_file_wrapper tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps two xsi_shared_memory_file_wrapper. Does not throw + void swap(xsi_shared_memory_file_wrapper &other) + { this->xsi_shared_memory::swap(other); } +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP -- cgit v1.2.3