From 493ab93e227e1141f07f7fe39bd9b1961b89d642 Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Wed, 20 Sep 2017 22:47:22 -0700 Subject: [PATCH 1/5] Added shared memory output. --- vfe/win/console/winconsole.cpp | 151 ++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) diff --git a/vfe/win/console/winconsole.cpp b/vfe/win/console/winconsole.cpp index 824af69c6..61df148cd 100644 --- a/vfe/win/console/winconsole.cpp +++ b/vfe/win/console/winconsole.cpp @@ -86,6 +86,127 @@ void ErrorExit(vfeSession *session) exit (1); } +const char* gSharedMemoryName = "leocad-povray"; + +struct lcSharedMemoryHeader +{ + uint32_t Version; + uint32_t Width; + uint32_t Height; + uint32_t PixelsWritten; + uint32_t PixelsRead; +}; + +class WinSharedMemoryDisplay : public vfeDisplay +{ +public: + WinSharedMemoryDisplay(unsigned int width, unsigned int height, GammaCurvePtr gamma, vfeSession *session, bool visible = false) + : vfeDisplay( width, height, gamma, session, visible ) + { + mBuffer = NULL; + mMapFile = INVALID_HANDLE_VALUE; + } + + virtual ~WinSharedMemoryDisplay() + { + Close(); + } + + virtual void Initialise() + { + if (mMapFile != INVALID_HANDLE_VALUE) + return; + + int BufferSize = sizeof(lcSharedMemoryHeader) + GetWidth() * GetHeight() * sizeof(RGBA8); + + mMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BufferSize, gSharedMemoryName); + + if (!mMapFile) + return; + + mBuffer = MapViewOfFile(mMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BufferSize); + + if (!mBuffer) + { + CloseHandle(mMapFile); + mMapFile = INVALID_HANDLE_VALUE; + return; + } + + lcSharedMemoryHeader* Header = (lcSharedMemoryHeader*)mBuffer; + Header->Version = 1; + Header->Width = GetWidth(); + Header->Height = GetHeight(); + Header->PixelsWritten = 0; + Header->PixelsRead = 0; + } + + virtual void Close() + { + if (mBuffer) + { + lcSharedMemoryHeader* Header = (lcSharedMemoryHeader*)mBuffer; + if (Header->PixelsWritten != Header->PixelsRead) + Sleep(5000); + + UnmapViewOfFile(mBuffer); + mBuffer = NULL; + } + + if (mMapFile != INVALID_HANDLE_VALUE) + { + CloseHandle(mMapFile); + mMapFile = INVALID_HANDLE_VALUE; + } + } + + virtual void DrawPixel(unsigned int x, unsigned int y, const RGBA8& colour) + { + lcSharedMemoryHeader* Header = (lcSharedMemoryHeader*)mBuffer; + RGBA8* Pixels = (RGBA8*)(Header + 1); + Pixels[y * GetWidth() + x] = colour; + Header->PixelsWritten++; + } + + virtual void DrawRectangleFrame(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, const RGBA8& colour) + { + for (unsigned int x = x1; x <= x2; x++) + DrawPixel(x, y1, colour); + for (unsigned int x = x1; x <= x2; x++) + DrawPixel(x, y2, colour); + for (unsigned int y = y1; y <= y2; y++) + { + DrawPixel(x1, y, colour); + DrawPixel(x2, y, colour); + } + } + + virtual void DrawFilledRectangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, const RGBA8& colour) + { + for (unsigned int y = y1; y <= y2; y++) + for (unsigned int x = x1; x <= x2; x++) + DrawPixel(x, y, colour); + } + + virtual void DrawPixelBlock(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, const RGBA8 *colour) + { + for (int y = y1; y <= y2; y++) + for (int x = x1; x <= x2; x++) + DrawPixel(x, y, *colour++); + } + +protected: + HANDLE mMapFile; + void* mBuffer; +}; + +vfeDisplay *SharedMemoryDisplayCreator(unsigned int width, unsigned int height, GammaCurvePtr gamma, vfeSession *session, bool visible) +{ + return new WinSharedMemoryDisplay(width, height, gamma, session, visible); +} + +int pause = 0; + // this is an example of a minimal console version of POV-Ray using the VFE // (virtual front-end) library. it is NOT INTENDED TO BE A FULLY-FEATURED // CONSOLE IMPLEMENTATION OF POV-RAY and is not officially supported. see @@ -97,6 +218,8 @@ int main (int argc, char **argv) vfeStatusFlags flags; vfeRenderOptions opts; + session->SetDisplayCreator(SharedMemoryDisplayCreator); + fprintf(stderr, "This is an example of a minimal console build of POV-Ray under Windows.\n\n" "Persistence of Vision(tm) Ray Tracer Version " POV_RAY_VERSION_INFO ".\n" @@ -112,8 +235,32 @@ int main (int argc, char **argv) if ((s = getenv ("POVINC")) != NULL) opts.AddLibraryPath (s); - while (*++argv) - opts.AddCommand (*argv); + argv++; + while (*argv) + { + if (!strcmp(*argv, "-pause")) + { + pause = 1; + argv++; + } + else if (!strcmp(*argv, "-shared-memory")) + { + argv++; + if (*argv) + { + gSharedMemoryName = *argv; + argv++; + } + } + else + { + opts.AddCommand(*argv); + argv++; + } + } + + if (pause) + MessageBox(0, "", "", MB_OK); if (session->SetOptions(opts) != vfeNoError) ErrorExit(session); From 93971373d48f964496d138b5b320940045e3765c Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Sun, 14 Jan 2018 11:14:14 -0800 Subject: [PATCH 2/5] Added boost::interprocess library. --- .../interprocess/allocators/adaptive_pool.hpp | 469 ++++ .../interprocess/allocators/allocator.hpp | 307 +++ .../allocators/cached_adaptive_pool.hpp | 357 +++ .../allocators/cached_node_allocator.hpp | 328 +++ .../allocators/detail/adaptive_node_pool.hpp | 118 + .../allocators/detail/allocator_common.hpp | 858 ++++++ .../allocators/detail/node_pool.hpp | 111 + .../allocators/detail/node_tools.hpp | 54 + .../allocators/node_allocator.hpp | 453 ++++ .../allocators/private_adaptive_pool.hpp | 469 ++++ .../allocators/private_node_allocator.hpp | 446 ++++ .../interprocess/anonymous_shared_memory.hpp | 125 + .../containers/allocation_type.hpp | 44 + .../containers/containers_fwd.hpp | 44 + .../boost/interprocess/containers/deque.hpp | 37 + .../interprocess/containers/flat_map.hpp | 37 + .../interprocess/containers/flat_set.hpp | 37 + .../boost/interprocess/containers/list.hpp | 37 + .../boost/interprocess/containers/map.hpp | 37 + .../boost/interprocess/containers/pair.hpp | 37 + .../boost/interprocess/containers/set.hpp | 37 + .../boost/interprocess/containers/slist.hpp | 36 + .../interprocess/containers/stable_vector.hpp | 36 + .../boost/interprocess/containers/string.hpp | 37 + .../boost/interprocess/containers/vector.hpp | 37 + .../interprocess/containers/version_type.hpp | 37 + .../boost/interprocess/creation_tags.hpp | 85 + .../boost/interprocess/detail/atomic.hpp | 601 +++++ .../boost/interprocess/detail/cast_tags.hpp | 31 + .../interprocess/detail/config_begin.hpp | 50 + .../boost/interprocess/detail/config_end.hpp | 16 + .../detail/config_external_begin.hpp | 18 + .../detail/config_external_end.hpp | 12 + .../detail/file_locking_helpers.hpp | 302 +++ .../interprocess/detail/file_wrapper.hpp | 212 ++ .../detail/in_place_interface.hpp | 77 + .../detail/intermodule_singleton.hpp | 53 + .../detail/intermodule_singleton_common.hpp | 504 ++++ .../detail/interprocess_tester.hpp | 39 + .../interprocess/detail/intersegment_ptr.hpp | 1044 ++++++++ .../detail/managed_global_memory.hpp | 119 + .../detail/managed_memory_impl.hpp | 775 ++++++ .../detail/managed_multi_shared_memory.hpp | 429 +++ .../detail/managed_open_or_create_impl.hpp | 501 ++++ .../interprocess/detail/math_functions.hpp | 118 + .../boost/interprocess/detail/min_max.hpp | 44 + .../boost/boost/interprocess/detail/move.hpp | 36 + .../boost/boost/interprocess/detail/mpl.hpp | 122 + .../boost/interprocess/detail/named_proxy.hpp | 316 +++ .../boost/interprocess/detail/nothrow.hpp | 41 + .../interprocess/detail/os_file_functions.hpp | 739 ++++++ .../detail/os_thread_functions.hpp | 617 +++++ .../interprocess/detail/pointer_type.hpp | 78 + .../detail/portable_intermodule_singleton.hpp | 361 +++ .../detail/posix_time_types_wrk.hpp | 51 + .../boost/interprocess/detail/ptime_wrk.hpp | 41 + .../interprocess/detail/robust_emulation.hpp | 385 +++ .../detail/segment_manager_helper.hpp | 518 ++++ .../detail/shared_dir_helpers.hpp | 199 ++ .../boost/interprocess/detail/simple_swap.hpp | 29 + .../boost/interprocess/detail/std_fwd.hpp | 57 + .../detail/transform_iterator.hpp | 200 ++ .../boost/interprocess/detail/type_traits.hpp | 162 ++ .../boost/interprocess/detail/utilities.hpp | 213 ++ .../detail/variadic_templates_tools.hpp | 35 + .../boost/interprocess/detail/win32_api.hpp | 2349 +++++++++++++++++ .../detail/windows_intermodule_singleton.hpp | 314 +++ .../boost/interprocess/detail/workaround.hpp | 205 ++ .../detail/xsi_shared_memory_file_wrapper.hpp | 88 + libraries/boost/boost/interprocess/errors.hpp | 241 ++ .../boost/boost/interprocess/exceptions.hpp | 110 + .../boost/boost/interprocess/file_mapping.hpp | 199 ++ .../interprocess/indexes/flat_map_index.hpp | 93 + .../boost/interprocess/indexes/iset_index.hpp | 158 ++ .../indexes/iunordered_set_index.hpp | 376 +++ .../boost/interprocess/indexes/map_index.hpp | 109 + .../boost/interprocess/indexes/null_index.hpp | 76 + .../indexes/unordered_map_index.hpp | 124 + .../boost/interprocess/interprocess_fwd.hpp | 516 ++++ .../boost/interprocess/ipc/message_queue.hpp | 996 +++++++ .../interprocess/managed_external_buffer.hpp | 137 + .../interprocess/managed_heap_memory.hpp | 171 ++ .../interprocess/managed_mapped_file.hpp | 250 ++ .../interprocess/managed_shared_memory.hpp | 262 ++ .../managed_windows_shared_memory.hpp | 224 ++ .../managed_xsi_shared_memory.hpp | 229 ++ .../boost/interprocess/mapped_region.hpp | 920 +++++++ .../mem_algo/detail/mem_algo_common.hpp | 596 +++++ .../mem_algo/detail/simple_seq_fit_impl.hpp | 1105 ++++++++ .../interprocess/mem_algo/rbtree_best_fit.hpp | 1400 ++++++++++ .../interprocess/mem_algo/simple_seq_fit.hpp | 62 + .../boost/boost/interprocess/offset_ptr.hpp | 751 ++++++ .../boost/boost/interprocess/permissions.hpp | 132 + .../boost/interprocess/segment_manager.hpp | 1343 ++++++++++ .../interprocess/shared_memory_object.hpp | 436 +++ .../boost/interprocess/smart_ptr/deleter.hpp | 68 + .../smart_ptr/detail/bad_weak_ptr.hpp | 48 + .../smart_ptr/detail/shared_count.hpp | 343 +++ .../smart_ptr/detail/sp_counted_base.hpp | 26 + .../detail/sp_counted_base_atomic.hpp | 94 + .../smart_ptr/detail/sp_counted_impl.hpp | 159 ++ .../smart_ptr/enable_shared_from_this.hpp | 87 + .../interprocess/smart_ptr/intrusive_ptr.hpp | 305 +++ .../interprocess/smart_ptr/scoped_ptr.hpp | 176 ++ .../interprocess/smart_ptr/shared_ptr.hpp | 428 +++ .../interprocess/smart_ptr/unique_ptr.hpp | 63 + .../boost/interprocess/smart_ptr/weak_ptr.hpp | 269 ++ .../interprocess/streams/bufferstream.hpp | 491 ++++ .../interprocess/streams/vectorstream.hpp | 622 +++++ .../sync/detail/common_algorithms.hpp | 81 + .../sync/detail/condition_algorithm_8a.hpp | 395 +++ .../sync/detail/condition_any_algorithm.hpp | 224 ++ .../boost/interprocess/sync/detail/locks.hpp | 101 + .../boost/interprocess/sync/file_lock.hpp | 237 ++ .../sync/interprocess_condition.hpp | 164 ++ .../sync/interprocess_condition_any.hpp | 137 + .../interprocess/sync/interprocess_mutex.hpp | 188 ++ .../sync/interprocess_recursive_mutex.hpp | 181 ++ .../sync/interprocess_semaphore.hpp | 149 ++ .../sync/interprocess_sharable_mutex.hpp | 349 +++ .../sync/interprocess_upgradable_mutex.hpp | 677 +++++ .../boost/interprocess/sync/lock_options.hpp | 63 + .../boost/interprocess/sync/mutex_family.hpp | 60 + .../interprocess/sync/named_condition.hpp | 201 ++ .../interprocess/sync/named_condition_any.hpp | 155 ++ .../boost/interprocess/sync/named_mutex.hpp | 175 ++ .../sync/named_recursive_mutex.hpp | 162 ++ .../interprocess/sync/named_semaphore.hpp | 173 ++ .../sync/named_sharable_mutex.hpp | 234 ++ .../sync/named_upgradable_mutex.hpp | 363 +++ .../boost/interprocess/sync/null_mutex.hpp | 155 ++ .../interprocess/sync/posix/condition.hpp | 196 ++ .../boost/interprocess/sync/posix/mutex.hpp | 143 + .../interprocess/sync/posix/named_mutex.hpp | 114 + .../sync/posix/named_semaphore.hpp | 88 + .../sync/posix/pthread_helpers.hpp | 172 ++ .../sync/posix/ptime_to_timespec.hpp | 48 + .../sync/posix/recursive_mutex.hpp | 137 + .../interprocess/sync/posix/semaphore.hpp | 67 + .../sync/posix/semaphore_wrapper.hpp | 253 ++ .../boost/interprocess/sync/scoped_lock.hpp | 377 +++ .../boost/interprocess/sync/sharable_lock.hpp | 310 +++ .../interprocess/sync/shm/named_condition.hpp | 239 ++ .../sync/shm/named_condition_any.hpp | 195 ++ .../sync/shm/named_creation_functor.hpp | 81 + .../interprocess/sync/shm/named_mutex.hpp | 181 ++ .../sync/shm/named_recursive_mutex.hpp | 171 ++ .../interprocess/sync/shm/named_semaphore.hpp | 138 + .../sync/shm/named_upgradable_mutex.hpp | 357 +++ .../interprocess/sync/spin/condition.hpp | 304 +++ .../sync/spin/interprocess_barrier.hpp | 54 + .../boost/interprocess/sync/spin/mutex.hpp | 87 + .../sync/spin/recursive_mutex.hpp | 176 ++ .../interprocess/sync/spin/semaphore.hpp | 94 + .../boost/interprocess/sync/spin/wait.hpp | 185 ++ .../interprocess/sync/upgradable_lock.hpp | 313 +++ .../interprocess/sync/windows/condition.hpp | 129 + .../boost/interprocess/sync/windows/mutex.hpp | 118 + .../sync/windows/named_condition.hpp | 38 + .../sync/windows/named_condition_any.hpp | 244 ++ .../interprocess/sync/windows/named_mutex.hpp | 179 ++ .../sync/windows/named_recursive_mutex.hpp | 62 + .../sync/windows/named_semaphore.hpp | 182 ++ .../interprocess/sync/windows/named_sync.hpp | 219 ++ .../sync/windows/recursive_mutex.hpp | 47 + .../interprocess/sync/windows/semaphore.hpp | 117 + .../interprocess/sync/windows/sync_utils.hpp | 240 ++ .../sync/windows/winapi_mutex_wrapper.hpp | 134 + .../sync/windows/winapi_semaphore_wrapper.hpp | 168 ++ .../sync/windows/winapi_wrapper_common.hpp | 97 + .../interprocess/windows_shared_memory.hpp | 252 ++ .../boost/boost/interprocess/xsi_key.hpp | 95 + .../boost/interprocess/xsi_shared_memory.hpp | 215 ++ 173 files changed, 42646 insertions(+) create mode 100644 libraries/boost/boost/interprocess/allocators/adaptive_pool.hpp create mode 100644 libraries/boost/boost/interprocess/allocators/allocator.hpp create mode 100644 libraries/boost/boost/interprocess/allocators/cached_adaptive_pool.hpp create mode 100644 libraries/boost/boost/interprocess/allocators/cached_node_allocator.hpp create mode 100644 libraries/boost/boost/interprocess/allocators/detail/adaptive_node_pool.hpp create mode 100644 libraries/boost/boost/interprocess/allocators/detail/allocator_common.hpp create mode 100644 libraries/boost/boost/interprocess/allocators/detail/node_pool.hpp create mode 100644 libraries/boost/boost/interprocess/allocators/detail/node_tools.hpp create mode 100644 libraries/boost/boost/interprocess/allocators/node_allocator.hpp create mode 100644 libraries/boost/boost/interprocess/allocators/private_adaptive_pool.hpp create mode 100644 libraries/boost/boost/interprocess/allocators/private_node_allocator.hpp create mode 100644 libraries/boost/boost/interprocess/anonymous_shared_memory.hpp create mode 100644 libraries/boost/boost/interprocess/containers/allocation_type.hpp create mode 100644 libraries/boost/boost/interprocess/containers/containers_fwd.hpp create mode 100644 libraries/boost/boost/interprocess/containers/deque.hpp create mode 100644 libraries/boost/boost/interprocess/containers/flat_map.hpp create mode 100644 libraries/boost/boost/interprocess/containers/flat_set.hpp create mode 100644 libraries/boost/boost/interprocess/containers/list.hpp create mode 100644 libraries/boost/boost/interprocess/containers/map.hpp create mode 100644 libraries/boost/boost/interprocess/containers/pair.hpp create mode 100644 libraries/boost/boost/interprocess/containers/set.hpp create mode 100644 libraries/boost/boost/interprocess/containers/slist.hpp create mode 100644 libraries/boost/boost/interprocess/containers/stable_vector.hpp create mode 100644 libraries/boost/boost/interprocess/containers/string.hpp create mode 100644 libraries/boost/boost/interprocess/containers/vector.hpp create mode 100644 libraries/boost/boost/interprocess/containers/version_type.hpp create mode 100644 libraries/boost/boost/interprocess/creation_tags.hpp create mode 100644 libraries/boost/boost/interprocess/detail/atomic.hpp create mode 100644 libraries/boost/boost/interprocess/detail/cast_tags.hpp create mode 100644 libraries/boost/boost/interprocess/detail/config_begin.hpp create mode 100644 libraries/boost/boost/interprocess/detail/config_end.hpp create mode 100644 libraries/boost/boost/interprocess/detail/config_external_begin.hpp create mode 100644 libraries/boost/boost/interprocess/detail/config_external_end.hpp create mode 100644 libraries/boost/boost/interprocess/detail/file_locking_helpers.hpp create mode 100644 libraries/boost/boost/interprocess/detail/file_wrapper.hpp create mode 100644 libraries/boost/boost/interprocess/detail/in_place_interface.hpp create mode 100644 libraries/boost/boost/interprocess/detail/intermodule_singleton.hpp create mode 100644 libraries/boost/boost/interprocess/detail/intermodule_singleton_common.hpp create mode 100644 libraries/boost/boost/interprocess/detail/interprocess_tester.hpp create mode 100644 libraries/boost/boost/interprocess/detail/intersegment_ptr.hpp create mode 100644 libraries/boost/boost/interprocess/detail/managed_global_memory.hpp create mode 100644 libraries/boost/boost/interprocess/detail/managed_memory_impl.hpp create mode 100644 libraries/boost/boost/interprocess/detail/managed_multi_shared_memory.hpp create mode 100644 libraries/boost/boost/interprocess/detail/managed_open_or_create_impl.hpp create mode 100644 libraries/boost/boost/interprocess/detail/math_functions.hpp create mode 100644 libraries/boost/boost/interprocess/detail/min_max.hpp create mode 100644 libraries/boost/boost/interprocess/detail/move.hpp create mode 100644 libraries/boost/boost/interprocess/detail/mpl.hpp create mode 100644 libraries/boost/boost/interprocess/detail/named_proxy.hpp create mode 100644 libraries/boost/boost/interprocess/detail/nothrow.hpp create mode 100644 libraries/boost/boost/interprocess/detail/os_file_functions.hpp create mode 100644 libraries/boost/boost/interprocess/detail/os_thread_functions.hpp create mode 100644 libraries/boost/boost/interprocess/detail/pointer_type.hpp create mode 100644 libraries/boost/boost/interprocess/detail/portable_intermodule_singleton.hpp create mode 100644 libraries/boost/boost/interprocess/detail/posix_time_types_wrk.hpp create mode 100644 libraries/boost/boost/interprocess/detail/ptime_wrk.hpp create mode 100644 libraries/boost/boost/interprocess/detail/robust_emulation.hpp create mode 100644 libraries/boost/boost/interprocess/detail/segment_manager_helper.hpp create mode 100644 libraries/boost/boost/interprocess/detail/shared_dir_helpers.hpp create mode 100644 libraries/boost/boost/interprocess/detail/simple_swap.hpp create mode 100644 libraries/boost/boost/interprocess/detail/std_fwd.hpp create mode 100644 libraries/boost/boost/interprocess/detail/transform_iterator.hpp create mode 100644 libraries/boost/boost/interprocess/detail/type_traits.hpp create mode 100644 libraries/boost/boost/interprocess/detail/utilities.hpp create mode 100644 libraries/boost/boost/interprocess/detail/variadic_templates_tools.hpp create mode 100644 libraries/boost/boost/interprocess/detail/win32_api.hpp create mode 100644 libraries/boost/boost/interprocess/detail/windows_intermodule_singleton.hpp create mode 100644 libraries/boost/boost/interprocess/detail/workaround.hpp create mode 100644 libraries/boost/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp create mode 100644 libraries/boost/boost/interprocess/errors.hpp create mode 100644 libraries/boost/boost/interprocess/exceptions.hpp create mode 100644 libraries/boost/boost/interprocess/file_mapping.hpp create mode 100644 libraries/boost/boost/interprocess/indexes/flat_map_index.hpp create mode 100644 libraries/boost/boost/interprocess/indexes/iset_index.hpp create mode 100644 libraries/boost/boost/interprocess/indexes/iunordered_set_index.hpp create mode 100644 libraries/boost/boost/interprocess/indexes/map_index.hpp create mode 100644 libraries/boost/boost/interprocess/indexes/null_index.hpp create mode 100644 libraries/boost/boost/interprocess/indexes/unordered_map_index.hpp create mode 100644 libraries/boost/boost/interprocess/interprocess_fwd.hpp create mode 100644 libraries/boost/boost/interprocess/ipc/message_queue.hpp create mode 100644 libraries/boost/boost/interprocess/managed_external_buffer.hpp create mode 100644 libraries/boost/boost/interprocess/managed_heap_memory.hpp create mode 100644 libraries/boost/boost/interprocess/managed_mapped_file.hpp create mode 100644 libraries/boost/boost/interprocess/managed_shared_memory.hpp create mode 100644 libraries/boost/boost/interprocess/managed_windows_shared_memory.hpp create mode 100644 libraries/boost/boost/interprocess/managed_xsi_shared_memory.hpp create mode 100644 libraries/boost/boost/interprocess/mapped_region.hpp create mode 100644 libraries/boost/boost/interprocess/mem_algo/detail/mem_algo_common.hpp create mode 100644 libraries/boost/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp create mode 100644 libraries/boost/boost/interprocess/mem_algo/rbtree_best_fit.hpp create mode 100644 libraries/boost/boost/interprocess/mem_algo/simple_seq_fit.hpp create mode 100644 libraries/boost/boost/interprocess/offset_ptr.hpp create mode 100644 libraries/boost/boost/interprocess/permissions.hpp create mode 100644 libraries/boost/boost/interprocess/segment_manager.hpp create mode 100644 libraries/boost/boost/interprocess/shared_memory_object.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/deleter.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/detail/shared_count.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/enable_shared_from_this.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/intrusive_ptr.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/scoped_ptr.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/shared_ptr.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/unique_ptr.hpp create mode 100644 libraries/boost/boost/interprocess/smart_ptr/weak_ptr.hpp create mode 100644 libraries/boost/boost/interprocess/streams/bufferstream.hpp create mode 100644 libraries/boost/boost/interprocess/streams/vectorstream.hpp create mode 100644 libraries/boost/boost/interprocess/sync/detail/common_algorithms.hpp create mode 100644 libraries/boost/boost/interprocess/sync/detail/condition_algorithm_8a.hpp create mode 100644 libraries/boost/boost/interprocess/sync/detail/condition_any_algorithm.hpp create mode 100644 libraries/boost/boost/interprocess/sync/detail/locks.hpp create mode 100644 libraries/boost/boost/interprocess/sync/file_lock.hpp create mode 100644 libraries/boost/boost/interprocess/sync/interprocess_condition.hpp create mode 100644 libraries/boost/boost/interprocess/sync/interprocess_condition_any.hpp create mode 100644 libraries/boost/boost/interprocess/sync/interprocess_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/interprocess_recursive_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/interprocess_semaphore.hpp create mode 100644 libraries/boost/boost/interprocess/sync/interprocess_sharable_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/interprocess_upgradable_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/lock_options.hpp create mode 100644 libraries/boost/boost/interprocess/sync/mutex_family.hpp create mode 100644 libraries/boost/boost/interprocess/sync/named_condition.hpp create mode 100644 libraries/boost/boost/interprocess/sync/named_condition_any.hpp create mode 100644 libraries/boost/boost/interprocess/sync/named_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/named_recursive_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/named_semaphore.hpp create mode 100644 libraries/boost/boost/interprocess/sync/named_sharable_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/named_upgradable_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/null_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/posix/condition.hpp create mode 100644 libraries/boost/boost/interprocess/sync/posix/mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/posix/named_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/posix/named_semaphore.hpp create mode 100644 libraries/boost/boost/interprocess/sync/posix/pthread_helpers.hpp create mode 100644 libraries/boost/boost/interprocess/sync/posix/ptime_to_timespec.hpp create mode 100644 libraries/boost/boost/interprocess/sync/posix/recursive_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/posix/semaphore.hpp create mode 100644 libraries/boost/boost/interprocess/sync/posix/semaphore_wrapper.hpp create mode 100644 libraries/boost/boost/interprocess/sync/scoped_lock.hpp create mode 100644 libraries/boost/boost/interprocess/sync/sharable_lock.hpp create mode 100644 libraries/boost/boost/interprocess/sync/shm/named_condition.hpp create mode 100644 libraries/boost/boost/interprocess/sync/shm/named_condition_any.hpp create mode 100644 libraries/boost/boost/interprocess/sync/shm/named_creation_functor.hpp create mode 100644 libraries/boost/boost/interprocess/sync/shm/named_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/shm/named_recursive_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/shm/named_semaphore.hpp create mode 100644 libraries/boost/boost/interprocess/sync/shm/named_upgradable_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/spin/condition.hpp create mode 100644 libraries/boost/boost/interprocess/sync/spin/interprocess_barrier.hpp create mode 100644 libraries/boost/boost/interprocess/sync/spin/mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/spin/recursive_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/spin/semaphore.hpp create mode 100644 libraries/boost/boost/interprocess/sync/spin/wait.hpp create mode 100644 libraries/boost/boost/interprocess/sync/upgradable_lock.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/condition.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/named_condition.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/named_condition_any.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/named_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/named_recursive_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/named_semaphore.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/named_sync.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/recursive_mutex.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/semaphore.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/sync_utils.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp create mode 100644 libraries/boost/boost/interprocess/sync/windows/winapi_wrapper_common.hpp create mode 100644 libraries/boost/boost/interprocess/windows_shared_memory.hpp create mode 100644 libraries/boost/boost/interprocess/xsi_key.hpp create mode 100644 libraries/boost/boost/interprocess/xsi_shared_memory.hpp diff --git a/libraries/boost/boost/interprocess/allocators/adaptive_pool.hpp b/libraries/boost/boost/interprocess/allocators/adaptive_pool.hpp new file mode 100644 index 000000000..3c0d50f5e --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/adaptive_pool.hpp @@ -0,0 +1,469 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP +#define BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes adaptive_pool pooled shared memory STL compatible allocator + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace ipcdetail{ + +template < unsigned int Version + , class T + , class SegmentManager + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , unsigned char OverheadPercent + > +class adaptive_pool_base + : public node_pool_allocation_impl + < adaptive_pool_base + < Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> + , Version + , T + , SegmentManager + > +{ + public: + typedef typename SegmentManager::void_pointer void_pointer; + typedef SegmentManager segment_manager; + typedef adaptive_pool_base + self_t; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + template + struct node_pool + { + typedef ipcdetail::shared_adaptive_node_pool + < SegmentManager, sizeof_value::value, NodesPerBlock, MaxFreeBlocks, OverheadPercent> type; + + static type *get(void *p) + { return static_cast(p); } + }; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + BOOST_STATIC_ASSERT((Version <=2)); + + public: + //------- + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + typedef boost::interprocess::version_type version; + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + + //!Obtains adaptive_pool_base from + //!adaptive_pool_base + template + struct rebind + { + typedef adaptive_pool_base other; + }; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + //!Not assignable from related adaptive_pool_base + template + adaptive_pool_base& operator= + (const adaptive_pool_base&); + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor from a segment manager. If not present, constructs a node + //!pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + adaptive_pool_base(segment_manager *segment_mngr) + : mp_node_pool(ipcdetail::get_or_create_node_pool::type>(segment_mngr)) { } + + //!Copy constructor from other adaptive_pool_base. Increments the reference + //!count of the associated node pool. Never throws + adaptive_pool_base(const adaptive_pool_base &other) + : mp_node_pool(other.get_node_pool()) + { + node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))->inc_ref_count(); + } + + //!Assignment from other adaptive_pool_base + adaptive_pool_base& operator=(const adaptive_pool_base &other) + { + adaptive_pool_base c(other); + boost::adl_move_swap(*this, c); + return *this; + } + + //!Copy constructor from related adaptive_pool_base. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + adaptive_pool_base + (const adaptive_pool_base &other) + : mp_node_pool(ipcdetail::get_or_create_node_pool::type>(other.get_segment_manager())) { } + + //!Destructor, removes node_pool_t from memory + //!if its reference count reaches to zero. Never throws + ~adaptive_pool_base() + { ipcdetail::destroy_node_pool_if_last_link(node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))); } + + //!Returns a pointer to the node pool. + //!Never throws + void* get_node_pool() const + { return ipcdetail::to_raw_pointer(mp_node_pool); } + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const + { return node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))->get_segment_manager(); } + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2) + { boost::adl_move_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + void_pointer mp_node_pool; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!Equality test for same type +//!of adaptive_pool_base +template inline +bool operator==(const adaptive_pool_base &alloc1, + const adaptive_pool_base &alloc2) + { return alloc1.get_node_pool() == alloc2.get_node_pool(); } + +//!Inequality test for same type +//!of adaptive_pool_base +template inline +bool operator!=(const adaptive_pool_base &alloc1, + const adaptive_pool_base &alloc2) + { return alloc1.get_node_pool() != alloc2.get_node_pool(); } + +template < class T + , class SegmentManager + , std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2 + , unsigned char OverheadPercent = 5 + > +class adaptive_pool_v1 + : public adaptive_pool_base + < 1 + , T + , SegmentManager + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > +{ + public: + typedef ipcdetail::adaptive_pool_base + < 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; + + template + struct rebind + { + typedef adaptive_pool_v1 other; + }; + + adaptive_pool_v1(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + adaptive_pool_v1 + (const adaptive_pool_v1 &other) + : base_t(other) + {} +}; + +} //namespace ipcdetail{ + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!An STL node allocator that uses a segment manager as memory +//!source. The internal pointer type will of the same type (raw, smart) as +//!"typename SegmentManager::void_pointer" type. This allows +//!placing the allocator in shared memory, memory mapped-files, etc... +//! +//!This node allocator shares a segregated storage between all instances +//!of adaptive_pool with equal sizeof(T) placed in the same segment +//!group. NodesPerBlock is the number of nodes allocated at once when the allocator +//!needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks +//!that the adaptive node pool will hold. The rest of the totally free blocks will be +//!deallocated with the segment manager. +//! +//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator: +//!(memory usable for nodes / total memory allocated from the segment manager) +template < class T + , class SegmentManager + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , unsigned char OverheadPercent + > +class adaptive_pool + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + : public ipcdetail::adaptive_pool_base + < 2 + , T + , SegmentManager + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef ipcdetail::adaptive_pool_base + < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; + public: + typedef boost::interprocess::version_type version; + + template + struct rebind + { + typedef adaptive_pool other; + }; + + adaptive_pool(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + adaptive_pool + (const adaptive_pool &other) + : base_t(other) + {} + + #else //BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + typedef implementation_defined::segment_manager segment_manager; + typedef segment_manager::void_pointer void_pointer; + typedef implementation_defined::pointer pointer; + typedef implementation_defined::const_pointer const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + //!Obtains adaptive_pool from + //!adaptive_pool + template + struct rebind + { + typedef adaptive_pool other; + }; + + private: + //!Not assignable from + //!related adaptive_pool + template + adaptive_pool& operator= + (const adaptive_pool&); + + //!Not assignable from + //!other adaptive_pool + //adaptive_pool& operator=(const adaptive_pool&); + + public: + //!Constructor from a segment manager. If not present, constructs a node + //!pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + adaptive_pool(segment_manager *segment_mngr); + + //!Copy constructor from other adaptive_pool. Increments the reference + //!count of the associated node pool. Never throws + adaptive_pool(const adaptive_pool &other); + + //!Copy constructor from related adaptive_pool. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + adaptive_pool + (const adaptive_pool &other); + + //!Destructor, removes node_pool_t from memory + //!if its reference count reaches to zero. Never throws + ~adaptive_pool(); + + //!Returns a pointer to the node pool. + //!Never throws + void* get_node_pool() const; + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const; + + //!Returns the number of elements that could be allocated. + //!Never throws + size_type max_size() const; + + //!Allocate memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_pointer hint = 0); + + //!Deallocate allocated memory. + //!Never throws + void deallocate(const pointer &ptr, size_type count); + + //!Deallocates all free blocks + //!of the pool + void deallocate_free_blocks(); + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2); + + //!Returns address of mutable object. + //!Never throws + pointer address(reference value) const; + + //!Returns address of non mutable object. + //!Never throws + const_pointer address(const_reference value) const; +/* + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); + + //!Destroys object. Throws if object's + //!destructor throws + void destroy(const pointer &ptr); +*/ + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. This size only works for memory allocated with + //!allocate, allocation_command and allocate_many. + size_type size(const pointer &p) const; + + pointer allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain); + + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous block + //!of memory. The elements must be deallocated + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain &chain); + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one(); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void allocate_individual(size_type num_elements, multiallocation_chain &chain); + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain); + #endif +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of adaptive_pool +template inline +bool operator==(const adaptive_pool &alloc1, + const adaptive_pool &alloc2); + +//!Inequality test for same type +//!of adaptive_pool +template inline +bool operator!=(const adaptive_pool &alloc1, + const adaptive_pool &alloc2); + +#endif + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP + diff --git a/libraries/boost/boost/interprocess/allocators/allocator.hpp b/libraries/boost/boost/interprocess/allocators/allocator.hpp new file mode 100644 index 000000000..759e3d260 --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/allocator.hpp @@ -0,0 +1,307 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_ALLOCATOR_HPP +#define BOOST_INTERPROCESS_ALLOCATOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//!\file +//!Describes an allocator that allocates portions of fixed size +//!memory buffer (shared memory, mapped file...) + +namespace boost { +namespace interprocess { + + +//!An STL compatible allocator that uses a segment manager as +//!memory source. The internal pointer type will of the same type (raw, smart) as +//!"typename SegmentManager::void_pointer" type. This allows +//!placing the allocator in shared memory, memory mapped-files, etc... +template +class allocator +{ + public: + //Segment manager + typedef SegmentManager segment_manager; + typedef typename SegmentManager::void_pointer void_pointer; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + + //Self type + typedef allocator self_t; + + //Pointer to void + typedef typename segment_manager::void_pointer aux_pointer_t; + + //Typedef to const void pointer + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type cvoid_ptr; + + //Pointer to the allocator + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type alloc_ptr_t; + + //Not assignable from related allocator + template + allocator& operator=(const allocator&); + + //Not assignable from other allocator + allocator& operator=(const allocator&); + + //Pointer to the allocator + alloc_ptr_t mp_mngr; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef T value_type; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_pointer; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + typedef boost::interprocess::version_type version; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Experimental. Don't use. + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Obtains an allocator that allocates + //!objects of type T2 + template + struct rebind + { + typedef allocator other; + }; + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const + { return ipcdetail::to_raw_pointer(mp_mngr); } + + //!Constructor from the segment manager. + //!Never throws + allocator(segment_manager *segment_mngr) + : mp_mngr(segment_mngr) { } + + //!Constructor from other allocator. + //!Never throws + allocator(const allocator &other) + : mp_mngr(other.get_segment_manager()){ } + + //!Constructor from related allocator. + //!Never throws + template + allocator(const allocator &other) + : mp_mngr(other.get_segment_manager()){} + + //!Allocates memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_ptr hint = 0) + { + (void)hint; + if(size_overflows(count)){ + throw bad_alloc(); + } + return pointer(static_cast(mp_mngr->allocate(count*sizeof(T)))); + } + + //!Deallocates memory previously allocated. + //!Never throws + void deallocate(const pointer &ptr, size_type) + { mp_mngr->deallocate((void*)ipcdetail::to_raw_pointer(ptr)); } + + //!Returns the number of elements that could be allocated. + //!Never throws + size_type max_size() const + { return mp_mngr->get_size()/sizeof(T); } + + //!Swap segment manager. Does not throw. If each allocator is placed in + //!different memory segments, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2) + { boost::adl_move_swap(alloc1.mp_mngr, alloc2.mp_mngr); } + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. This size only works for memory allocated with + //!allocate, allocation_command and allocate_many. + size_type size(const pointer &p) const + { + return (size_type)mp_mngr->size(ipcdetail::to_raw_pointer(p))/sizeof(T); + } + + pointer allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse) + { + value_type *reuse_raw = ipcdetail::to_raw_pointer(reuse); + pointer const p = mp_mngr->allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse_raw); + reuse = reuse_raw; + return p; + } + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain) + { + if(size_overflows(elem_size)){ + throw bad_alloc(); + } + mp_mngr->allocate_many(elem_size*sizeof(T), num_elements, chain); + } + + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous block + //!of memory. The elements must be deallocated + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) + { + mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T), chain); + } + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain &chain) + { mp_mngr->deallocate_many(chain); } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one() + { return this->allocate(1); } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void allocate_individual(size_type num_elements, multiallocation_chain &chain) + { this->allocate_many(1, num_elements, chain); } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p) + { return this->deallocate(p, 1); } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain) + { this->deallocate_many(chain); } + + //!Returns address of mutable object. + //!Never throws + pointer address(reference value) const + { return pointer(boost::addressof(value)); } + + //!Returns address of non mutable object. + //!Never throws + const_pointer address(const_reference value) const + { return const_pointer(boost::addressof(value)); } + + //!Constructs an object + //!Throws if T's constructor throws + //!For backwards compatibility with libraries using C++03 allocators + template + void construct(const pointer &ptr, BOOST_FWD_REF(P) p) + { ::new((void*)ipcdetail::to_raw_pointer(ptr), boost_container_new_t()) value_type(::boost::forward

(p)); } + + //!Destroys object. Throws if object's + //!destructor throws + void destroy(const pointer &ptr) + { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } + +}; + +//!Equality test for same type +//!of allocator +template inline +bool operator==(const allocator &alloc1, + const allocator &alloc2) + { return alloc1.get_segment_manager() == alloc2.get_segment_manager(); } + +//!Inequality test for same type +//!of allocator +template inline +bool operator!=(const allocator &alloc1, + const allocator &alloc2) + { return alloc1.get_segment_manager() != alloc2.get_segment_manager(); } + +} //namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +template +struct has_trivial_destructor; + +template +struct has_trivial_destructor + > +{ + static const bool value = true; +}; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP + diff --git a/libraries/boost/boost/interprocess/allocators/cached_adaptive_pool.hpp b/libraries/boost/boost/interprocess/allocators/cached_adaptive_pool.hpp new file mode 100644 index 000000000..0ccf1f363 --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -0,0 +1,357 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP +#define BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes cached_adaptive_pool pooled shared memory STL compatible allocator + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace ipcdetail { + +template < class T + , class SegmentManager + , std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2 + , unsigned char OverheadPercent = 5 + > +class cached_adaptive_pool_v1 + : public ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_adaptive_node_pool + < SegmentManager + , sizeof_value::value + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > + , 1> +{ + public: + typedef ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_adaptive_node_pool + < SegmentManager + , sizeof_value::value + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > + , 1> base_t; + + template + struct rebind + { + typedef cached_adaptive_pool_v1 + other; + }; + + typedef typename base_t::size_type size_type; + + cached_adaptive_pool_v1(SegmentManager *segment_mngr, + size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES) + : base_t(segment_mngr, max_cached_nodes) + {} + + template + cached_adaptive_pool_v1 + (const cached_adaptive_pool_v1 + &other) + : base_t(other) + {} +}; + +} //namespace ipcdetail{ + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!An STL node allocator that uses a segment manager as memory +//!source. The internal pointer type will of the same type (raw, smart) as +//!"typename SegmentManager::void_pointer" type. This allows +//!placing the allocator in shared memory, memory mapped-files, etc... +//! +//!This node allocator shares a segregated storage between all instances of +//!cached_adaptive_pool with equal sizeof(T) placed in the same +//!memory segment. But also caches some nodes privately to +//!avoid some synchronization overhead. +//! +//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when +//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks +//!that the adaptive node pool will hold. The rest of the totally free blocks will be +//!deallocated with the segment manager. +//! +//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator: +//!(memory usable for nodes / total memory allocated from the segment manager) +template < class T + , class SegmentManager + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , unsigned char OverheadPercent + > +class cached_adaptive_pool + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + : public ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_adaptive_node_pool + < SegmentManager + , sizeof_value::value + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > + , 2> + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + typedef ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_adaptive_node_pool + < SegmentManager + , sizeof_value::value + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > + , 2> base_t; + + public: + typedef boost::interprocess::version_type version; + + template + struct rebind + { + typedef cached_adaptive_pool + other; + }; + + cached_adaptive_pool(SegmentManager *segment_mngr, + std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES) + : base_t(segment_mngr, max_cached_nodes) + {} + + template + cached_adaptive_pool + (const cached_adaptive_pool &other) + : base_t(other) + {} + + #else + public: + typedef implementation_defined::segment_manager segment_manager; + typedef segment_manager::void_pointer void_pointer; + typedef implementation_defined::pointer pointer; + typedef implementation_defined::const_pointer const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + //!Obtains cached_adaptive_pool from + //!cached_adaptive_pool + template + struct rebind + { + typedef cached_adaptive_pool other; + }; + + private: + //!Not assignable from + //!related cached_adaptive_pool + template + cached_adaptive_pool& operator= + (const cached_adaptive_pool&); + + //!Not assignable from + //!other cached_adaptive_pool + cached_adaptive_pool& operator=(const cached_adaptive_pool&); + + public: + //!Constructor from a segment manager. If not present, constructs a node + //!pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + cached_adaptive_pool(segment_manager *segment_mngr); + + //!Copy constructor from other cached_adaptive_pool. Increments the reference + //!count of the associated node pool. Never throws + cached_adaptive_pool(const cached_adaptive_pool &other); + + //!Copy constructor from related cached_adaptive_pool. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + cached_adaptive_pool + (const cached_adaptive_pool &other); + + //!Destructor, removes node_pool_t from memory + //!if its reference count reaches to zero. Never throws + ~cached_adaptive_pool(); + + //!Returns a pointer to the node pool. + //!Never throws + node_pool_t* get_node_pool() const; + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const; + + //!Returns the number of elements that could be allocated. + //!Never throws + size_type max_size() const; + + //!Allocate memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_pointer hint = 0); + + //!Deallocate allocated memory. + //!Never throws + void deallocate(const pointer &ptr, size_type count); + + //!Deallocates all free blocks + //!of the pool + void deallocate_free_blocks(); + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2); + + //!Returns address of mutable object. + //!Never throws + pointer address(reference value) const; + + //!Returns address of non mutable object. + //!Never throws + const_pointer address(const_reference value) const; + + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); + + //!Destroys object. Throws if object's + //!destructor throws + void destroy(const pointer &ptr); + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. This size only works for memory allocated with + //!allocate, allocation_command and allocate_many. + size_type size(const pointer &p) const; + + pointer allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain); + + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous block + //!of memory. The elements must be deallocated + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain &chain); + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one(); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + multiallocation_chain allocate_individual(size_type num_elements); + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain); + //!Sets the new max cached nodes value. This can provoke deallocations + //!if "newmax" is less than current cached nodes. Never throws + void set_max_cached_nodes(size_type newmax); + + //!Returns the max cached nodes parameter. + //!Never throws + size_type get_max_cached_nodes() const; + #endif +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of cached_adaptive_pool +template inline +bool operator==(const cached_adaptive_pool &alloc1, + const cached_adaptive_pool &alloc2); + +//!Inequality test for same type +//!of cached_adaptive_pool +template inline +bool operator!=(const cached_adaptive_pool &alloc1, + const cached_adaptive_pool &alloc2); + +#endif + +} //namespace interprocess { +} //namespace boost { + + +#include + +#endif //#ifndef BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP + diff --git a/libraries/boost/boost/interprocess/allocators/cached_node_allocator.hpp b/libraries/boost/boost/interprocess/allocators/cached_node_allocator.hpp new file mode 100644 index 000000000..4eff061b0 --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/cached_node_allocator.hpp @@ -0,0 +1,328 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP +#define BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes cached_cached_node_allocator pooled shared memory STL compatible allocator + +namespace boost { +namespace interprocess { + + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace ipcdetail { + +template < class T + , class SegmentManager + , std::size_t NodesPerBlock = 64 + > +class cached_node_allocator_v1 + : public ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_node_pool + < SegmentManager + , sizeof_value::value + , NodesPerBlock + > + , 1> +{ + public: + typedef ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_node_pool + < SegmentManager + , sizeof_value::value + , NodesPerBlock + > + , 1> base_t; + + template + struct rebind + { + typedef cached_node_allocator_v1 + other; + }; + + typedef typename base_t::size_type size_type; + + cached_node_allocator_v1(SegmentManager *segment_mngr, + size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES) + : base_t(segment_mngr, max_cached_nodes) + {} + + template + cached_node_allocator_v1 + (const cached_node_allocator_v1 + &other) + : base_t(other) + {} +}; + +} //namespace ipcdetail{ + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +template < class T + , class SegmentManager + , std::size_t NodesPerBlock + > +class cached_node_allocator + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + : public ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_node_pool + < SegmentManager + , sizeof_value::value + , NodesPerBlock + > + , 2> + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + typedef ipcdetail::cached_allocator_impl + < T + , ipcdetail::shared_node_pool + < SegmentManager + , sizeof_value::value + , NodesPerBlock + > + , 2> base_t; + + public: + typedef boost::interprocess::version_type version; + typedef typename base_t::size_type size_type; + + template + struct rebind + { + typedef cached_node_allocator other; + }; + + cached_node_allocator(SegmentManager *segment_mngr, + size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES) + : base_t(segment_mngr, max_cached_nodes) + {} + + template + cached_node_allocator + (const cached_node_allocator &other) + : base_t(other) + {} + + #else + public: + typedef implementation_defined::segment_manager segment_manager; + typedef segment_manager::void_pointer void_pointer; + typedef implementation_defined::pointer pointer; + typedef implementation_defined::const_pointer const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename SegmentManager::size_type size_type; + typedef typename SegmentManager::difference_type difference_type; + + //!Obtains cached_node_allocator from + //!cached_node_allocator + template + struct rebind + { + typedef cached_node_allocator other; + }; + + private: + //!Not assignable from + //!related cached_node_allocator + template + cached_node_allocator& operator= + (const cached_node_allocator&); + + //!Not assignable from + //!other cached_node_allocator + cached_node_allocator& operator=(const cached_node_allocator&); + + public: + //!Constructor from a segment manager. If not present, constructs a node + //!pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + cached_node_allocator(segment_manager *segment_mngr); + + //!Copy constructor from other cached_node_allocator. Increments the reference + //!count of the associated node pool. Never throws + cached_node_allocator(const cached_node_allocator &other); + + //!Copy constructor from related cached_node_allocator. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + cached_node_allocator + (const cached_node_allocator &other); + + //!Destructor, removes node_pool_t from memory + //!if its reference count reaches to zero. Never throws + ~cached_node_allocator(); + + //!Returns a pointer to the node pool. + //!Never throws + node_pool_t* get_node_pool() const; + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const; + + //!Returns the number of elements that could be allocated. + //!Never throws + size_type max_size() const; + + //!Allocate memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_pointer hint = 0); + + //!Deallocate allocated memory. + //!Never throws + void deallocate(const pointer &ptr, size_type count); + + //!Deallocates all free blocks + //!of the pool + void deallocate_free_blocks(); + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2); + + //!Returns address of mutable object. + //!Never throws + pointer address(reference value) const; + + //!Returns address of non mutable object. + //!Never throws + const_pointer address(const_reference value) const; + + //!Default construct an object. + //!Throws if T's default constructor throws + void construct(const pointer &ptr, const_reference v); + + //!Destroys object. Throws if object's + //!destructor throws + void destroy(const pointer &ptr); + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. This size only works for memory allocated with + //!allocate, allocation_command and allocate_many. + size_type size(const pointer &p) const; + + pointer allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain); + + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous block + //!of memory. The elements must be deallocated + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain &chain); + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one(); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + multiallocation_chain allocate_individual(size_type num_elements); + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain it); + //!Sets the new max cached nodes value. This can provoke deallocations + //!if "newmax" is less than current cached nodes. Never throws + void set_max_cached_nodes(size_type newmax); + + //!Returns the max cached nodes parameter. + //!Never throws + size_type get_max_cached_nodes() const; + #endif +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of cached_node_allocator +template inline +bool operator==(const cached_node_allocator &alloc1, + const cached_node_allocator &alloc2); + +//!Inequality test for same type +//!of cached_node_allocator +template inline +bool operator!=(const cached_node_allocator &alloc1, + const cached_node_allocator &alloc2); + +#endif + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP + diff --git a/libraries/boost/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/libraries/boost/boost/interprocess/allocators/detail/adaptive_node_pool.hpp new file mode 100644 index 000000000..2996bc82e --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -0,0 +1,118 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP +#define BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes the real adaptive pool shared by many Interprocess pool allocators + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template< class SegmentManager + , std::size_t NodeSize + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , unsigned char OverheadPercent + > +class private_adaptive_node_pool + : public boost::container::container_detail::private_adaptive_node_pool_impl + < typename SegmentManager::segment_manager_base_type + , ::boost::container::adaptive_pool_flag::size_ordered | + ::boost::container::adaptive_pool_flag::address_ordered + > +{ + typedef boost::container::container_detail::private_adaptive_node_pool_impl + < typename SegmentManager::segment_manager_base_type + , ::boost::container::adaptive_pool_flag::size_ordered | + ::boost::container::adaptive_pool_flag::address_ordered + > base_t; + //Non-copyable + private_adaptive_node_pool(); + private_adaptive_node_pool(const private_adaptive_node_pool &); + private_adaptive_node_pool &operator=(const private_adaptive_node_pool &); + + public: + typedef SegmentManager segment_manager; + typedef typename base_t::size_type size_type; + + static const size_type nodes_per_block = NodesPerBlock; + + //Deprecated, use node_per_block + static const size_type nodes_per_chunk = NodesPerBlock; + + //!Constructor from a segment manager. Never throws + private_adaptive_node_pool(segment_manager *segment_mngr) + : base_t(segment_mngr, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent) + {} + + //!Returns the segment manager. Never throws + segment_manager* get_segment_manager() const + { return static_cast(base_t::get_segment_manager_base()); } +}; + +//!Pooled shared memory allocator using adaptive pool. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time +template< class SegmentManager + , std::size_t NodeSize + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , unsigned char OverheadPercent + > +class shared_adaptive_node_pool + : public ipcdetail::shared_pool_impl + < private_adaptive_node_pool + + > +{ + typedef ipcdetail::shared_pool_impl + < private_adaptive_node_pool + + > base_t; + public: + shared_adaptive_node_pool(SegmentManager *segment_mgnr) + : base_t(segment_mgnr) + {} +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP diff --git a/libraries/boost/boost/interprocess/allocators/detail/allocator_common.hpp b/libraries/boost/boost/interprocess/allocators/detail/allocator_common.hpp new file mode 100644 index 000000000..f613ffd82 --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/detail/allocator_common.hpp @@ -0,0 +1,858 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP +#define BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +#include +#include //to_raw_pointer +#include //boost::addressof +#include //BOOST_ASSERT +#include //bad_alloc +#include //scoped_lock +#include //boost::interprocess::allocation_type +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { + +template +struct sizeof_value +{ + static const std::size_t value = sizeof(T); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +namespace ipcdetail { + +//!Object function that creates the node allocator if it is not created and +//!increments reference count if it is already created +template +struct get_or_create_node_pool_func +{ + + //!This connects or constructs the unique instance of node_pool_t + //!Can throw boost::interprocess::bad_alloc + void operator()() + { + //Find or create the node_pool_t + mp_node_pool = mp_segment_manager->template find_or_construct + (boost::interprocess::unique_instance)(mp_segment_manager); + //If valid, increment link count + if(mp_node_pool != 0) + mp_node_pool->inc_ref_count(); + } + + //!Constructor. Initializes function + //!object parameters + get_or_create_node_pool_func(typename NodePool::segment_manager *mngr) + : mp_segment_manager(mngr){} + + NodePool *mp_node_pool; + typename NodePool::segment_manager *mp_segment_manager; +}; + +template +inline NodePool *get_or_create_node_pool(typename NodePool::segment_manager *mgnr) +{ + ipcdetail::get_or_create_node_pool_func func(mgnr); + mgnr->atomic_func(func); + return func.mp_node_pool; +} + +//!Object function that decrements the reference count. If the count +//!reaches to zero destroys the node allocator from memory. +//!Never throws +template +struct destroy_if_last_link_func +{ + //!Decrements reference count and destroys the object if there is no + //!more attached allocators. Never throws + void operator()() + { + //If not the last link return + if(mp_node_pool->dec_ref_count() != 0) return; + + //Last link, let's destroy the segment_manager + mp_node_pool->get_segment_manager()->template destroy(boost::interprocess::unique_instance); + } + + //!Constructor. Initializes function + //!object parameters + destroy_if_last_link_func(NodePool *pool) + : mp_node_pool(pool) + {} + + NodePool *mp_node_pool; +}; + +//!Destruction function, initializes and executes destruction function +//!object. Never throws +template +inline void destroy_node_pool_if_last_link(NodePool *pool) +{ + //Get segment manager + typename NodePool::segment_manager *mngr = pool->get_segment_manager(); + //Execute destruction functor atomically + destroy_if_last_link_funcfunc(pool); + mngr->atomic_func(func); +} + +template +class cache_impl +{ + typedef typename NodePool::segment_manager:: + void_pointer void_pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type node_pool_ptr; + typedef typename NodePool::multiallocation_chain multiallocation_chain; + typedef typename NodePool::segment_manager::size_type size_type; + node_pool_ptr mp_node_pool; + multiallocation_chain m_cached_nodes; + size_type m_max_cached_nodes; + + public: + typedef typename NodePool::segment_manager segment_manager; + + cache_impl(segment_manager *segment_mngr, size_type max_cached_nodes) + : mp_node_pool(get_or_create_node_pool(segment_mngr)) + , m_max_cached_nodes(max_cached_nodes) + {} + + cache_impl(const cache_impl &other) + : mp_node_pool(other.get_node_pool()) + , m_max_cached_nodes(other.get_max_cached_nodes()) + { + mp_node_pool->inc_ref_count(); + } + + ~cache_impl() + { + this->deallocate_all_cached_nodes(); + ipcdetail::destroy_node_pool_if_last_link(ipcdetail::to_raw_pointer(mp_node_pool)); + } + + NodePool *get_node_pool() const + { return ipcdetail::to_raw_pointer(mp_node_pool); } + + segment_manager *get_segment_manager() const + { return mp_node_pool->get_segment_manager(); } + + size_type get_max_cached_nodes() const + { return m_max_cached_nodes; } + + void *cached_allocation() + { + //If don't have any cached node, we have to get a new list of free nodes from the pool + if(m_cached_nodes.empty()){ + mp_node_pool->allocate_nodes(m_max_cached_nodes/2, m_cached_nodes); + } + void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.pop_front()); + return ret; + } + + void cached_allocation(size_type n, multiallocation_chain &chain) + { + size_type count = n, allocated(0); + BOOST_TRY{ + //If don't have any cached node, we have to get a new list of free nodes from the pool + while(!m_cached_nodes.empty() && count--){ + void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.pop_front()); + chain.push_back(ret); + ++allocated; + } + + if(allocated != n){ + mp_node_pool->allocate_nodes(n - allocated, chain); + } + } + BOOST_CATCH(...){ + this->cached_deallocation(chain); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + void cached_deallocation(void *ptr) + { + //Check if cache is full + if(m_cached_nodes.size() >= m_max_cached_nodes){ + //This only occurs if this allocator deallocate memory allocated + //with other equal allocator. Since the cache is full, and more + //deallocations are probably coming, we'll make some room in cache + //in a single, efficient multi node deallocation. + this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2); + } + m_cached_nodes.push_front(ptr); + } + + void cached_deallocation(multiallocation_chain &chain) + { + m_cached_nodes.splice_after(m_cached_nodes.before_begin(), chain); + + //Check if cache is full + if(m_cached_nodes.size() >= m_max_cached_nodes){ + //This only occurs if this allocator deallocate memory allocated + //with other equal allocator. Since the cache is full, and more + //deallocations are probably coming, we'll make some room in cache + //in a single, efficient multi node deallocation. + this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2); + } + } + + //!Sets the new max cached nodes value. This can provoke deallocations + //!if "newmax" is less than current cached nodes. Never throws + void set_max_cached_nodes(size_type newmax) + { + m_max_cached_nodes = newmax; + this->priv_deallocate_remaining_nodes(); + } + + //!Frees all cached nodes. + //!Never throws + void deallocate_all_cached_nodes() + { + if(m_cached_nodes.empty()) return; + mp_node_pool->deallocate_nodes(m_cached_nodes); + } + + private: + //!Frees all cached nodes at once. + //!Never throws + void priv_deallocate_remaining_nodes() + { + if(m_cached_nodes.size() > m_max_cached_nodes){ + priv_deallocate_n_nodes(m_cached_nodes.size()-m_max_cached_nodes); + } + } + + //!Frees n cached nodes at once. Never throws + void priv_deallocate_n_nodes(size_type n) + { + //This only occurs if this allocator deallocate memory allocated + //with other equal allocator. Since the cache is full, and more + //deallocations are probably coming, we'll make some room in cache + //in a single, efficient multi node deallocation. + size_type count(n); + typename multiallocation_chain::iterator it(m_cached_nodes.before_begin()); + while(count--){ + ++it; + } + multiallocation_chain chain; + chain.splice_after(chain.before_begin(), m_cached_nodes, m_cached_nodes.before_begin(), it, n); + //Deallocate all new linked list at once + mp_node_pool->deallocate_nodes(chain); + } + + public: + void swap(cache_impl &other) + { + ::boost::adl_move_swap(mp_node_pool, other.mp_node_pool); + ::boost::adl_move_swap(m_cached_nodes, other.m_cached_nodes); + ::boost::adl_move_swap(m_max_cached_nodes, other.m_max_cached_nodes); + } +}; + +template +class array_allocation_impl +{ + const Derived *derived() const + { return static_cast(this); } + Derived *derived() + { return static_cast(this); } + + typedef typename SegmentManager::void_pointer void_pointer; + + public: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename SegmentManager::size_type size_type; + typedef typename SegmentManager::difference_type difference_type; + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + + + public: + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. This size only works for memory allocated with + //!allocate, allocation_command and allocate_many. + size_type size(const pointer &p) const + { + return (size_type)this->derived()->get_segment_manager()->size(ipcdetail::to_raw_pointer(p))/sizeof(T); + } + + pointer allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse) + { + value_type *reuse_raw = ipcdetail::to_raw_pointer(reuse); + pointer const p = this->derived()->get_segment_manager()->allocation_command + (command, limit_size, prefer_in_recvd_out_size, reuse_raw); + reuse = reuse_raw; + return p; + } + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain) + { + if(size_overflows(elem_size)){ + throw bad_alloc(); + } + this->derived()->get_segment_manager()->allocate_many(elem_size*sizeof(T), num_elements, chain); + } + + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous block + //!of memory. The elements must be deallocated + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) + { + this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T), chain); + } + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain &chain) + { this->derived()->get_segment_manager()->deallocate_many(chain); } + + //!Returns the number of elements that could be + //!allocated. Never throws + size_type max_size() const + { return this->derived()->get_segment_manager()->get_size()/sizeof(T); } + + //!Returns address of mutable object. + //!Never throws + pointer address(reference value) const + { return pointer(boost::addressof(value)); } + + //!Returns address of non mutable object. + //!Never throws + const_pointer address(const_reference value) const + { return const_pointer(boost::addressof(value)); } + + //!Constructs an object + //!Throws if T's constructor throws + //!For backwards compatibility with libraries using C++03 allocators + template + void construct(const pointer &ptr, BOOST_FWD_REF(P) p) + { ::new((void*)ipcdetail::to_raw_pointer(ptr), boost_container_new_t()) value_type(::boost::forward

(p)); } + + //!Destroys object. Throws if object's + //!destructor throws + void destroy(const pointer &ptr) + { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } +}; + + +template +class node_pool_allocation_impl + : public array_allocation_impl + < Derived + , T + , SegmentManager> +{ + const Derived *derived() const + { return static_cast(this); } + Derived *derived() + { return static_cast(this); } + + typedef typename SegmentManager::void_pointer void_pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type cvoid_pointer; + + public: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename SegmentManager::size_type size_type; + typedef typename SegmentManager::difference_type difference_type; + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + + + template + struct node_pool + { + typedef typename Derived::template node_pool<0>::type type; + static type *get(void *p) + { return static_cast(p); } + }; + + public: + //!Allocate memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_pointer hint = 0) + { + (void)hint; + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + if(size_overflows(count)){ + throw bad_alloc(); + } + else if(Version == 1 && count == 1){ + return pointer(static_cast + (pool->allocate_node())); + } + else{ + return pointer(static_cast + (pool->get_segment_manager()->allocate(count*sizeof(T)))); + } + } + + //!Deallocate allocated memory. Never throws + void deallocate(const pointer &ptr, size_type count) + { + (void)count; + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + if(Version == 1 && count == 1) + pool->deallocate_node(ipcdetail::to_raw_pointer(ptr)); + else + pool->get_segment_manager()->deallocate((void*)ipcdetail::to_raw_pointer(ptr)); + } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one() + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + return pointer(static_cast(pool->allocate_node())); + } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void allocate_individual(size_type num_elements, multiallocation_chain &chain) + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + pool->allocate_nodes(num_elements, chain); + } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p) + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + pool->deallocate_node(ipcdetail::to_raw_pointer(p)); + } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain) + { + node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes + (chain); + } + + //!Deallocates all free blocks of the pool + void deallocate_free_blocks() + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); } + + //!Deprecated, use deallocate_free_blocks. + //!Deallocates all free chunks of the pool. + void deallocate_free_chunks() + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); } +}; + +template +class cached_allocator_impl + : public array_allocation_impl + , T, typename NodePool::segment_manager> +{ + cached_allocator_impl & operator=(const cached_allocator_impl& other); + typedef array_allocation_impl + < cached_allocator_impl + + , T + , typename NodePool::segment_manager> base_t; + + public: + typedef NodePool node_pool_t; + typedef typename NodePool::segment_manager segment_manager; + typedef typename segment_manager::void_pointer void_pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type cvoid_pointer; + typedef typename base_t::pointer pointer; + typedef typename base_t::size_type size_type; + typedef typename base_t::multiallocation_chain multiallocation_chain; + typedef typename base_t::value_type value_type; + + public: + static const std::size_t DEFAULT_MAX_CACHED_NODES = 64; + + cached_allocator_impl(segment_manager *segment_mngr, size_type max_cached_nodes) + : m_cache(segment_mngr, max_cached_nodes) + {} + + cached_allocator_impl(const cached_allocator_impl &other) + : m_cache(other.m_cache) + {} + + //!Copy constructor from related cached_adaptive_pool_base. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + cached_allocator_impl + (const cached_allocator_impl + &other) + : m_cache(other.get_segment_manager(), other.get_max_cached_nodes()) + {} + + //!Returns a pointer to the node pool. + //!Never throws + node_pool_t* get_node_pool() const + { return m_cache.get_node_pool(); } + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const + { return m_cache.get_segment_manager(); } + + //!Sets the new max cached nodes value. This can provoke deallocations + //!if "newmax" is less than current cached nodes. Never throws + void set_max_cached_nodes(size_type newmax) + { m_cache.set_max_cached_nodes(newmax); } + + //!Returns the max cached nodes parameter. + //!Never throws + size_type get_max_cached_nodes() const + { return m_cache.get_max_cached_nodes(); } + + //!Allocate memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_pointer hint = 0) + { + (void)hint; + void * ret; + if(size_overflows(count)){ + throw bad_alloc(); + } + else if(Version == 1 && count == 1){ + ret = m_cache.cached_allocation(); + } + else{ + ret = this->get_segment_manager()->allocate(count*sizeof(T)); + } + return pointer(static_cast(ret)); + } + + //!Deallocate allocated memory. Never throws + void deallocate(const pointer &ptr, size_type count) + { + (void)count; + if(Version == 1 && count == 1){ + m_cache.cached_deallocation(ipcdetail::to_raw_pointer(ptr)); + } + else{ + this->get_segment_manager()->deallocate((void*)ipcdetail::to_raw_pointer(ptr)); + } + } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one() + { return pointer(static_cast(this->m_cache.cached_allocation())); } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void allocate_individual(size_type num_elements, multiallocation_chain &chain) + { this->m_cache.cached_allocation(num_elements, chain); } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p) + { this->m_cache.cached_deallocation(ipcdetail::to_raw_pointer(p)); } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain) + { m_cache.cached_deallocation(chain); } + + //!Deallocates all free blocks of the pool + void deallocate_free_blocks() + { m_cache.get_node_pool()->deallocate_free_blocks(); } + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different shared memory segments, the result is undefined. + friend void swap(cached_allocator_impl &alloc1, cached_allocator_impl &alloc2) + { ::boost::adl_move_swap(alloc1.m_cache, alloc2.m_cache); } + + void deallocate_cache() + { m_cache.deallocate_all_cached_nodes(); } + + //!Deprecated use deallocate_free_blocks. + void deallocate_free_chunks() + { m_cache.get_node_pool()->deallocate_free_blocks(); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + cache_impl m_cache; + #endif //!defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +}; + +//!Equality test for same type of +//!cached_allocator_impl +template inline +bool operator==(const cached_allocator_impl &alloc1, + const cached_allocator_impl &alloc2) + { return alloc1.get_node_pool() == alloc2.get_node_pool(); } + +//!Inequality test for same type of +//!cached_allocator_impl +template inline +bool operator!=(const cached_allocator_impl &alloc1, + const cached_allocator_impl &alloc2) + { return alloc1.get_node_pool() != alloc2.get_node_pool(); } + + +//!Pooled shared memory allocator using adaptive pool. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time +template +class shared_pool_impl + : public private_node_allocator_t +{ + public: + //!Segment manager typedef + typedef typename private_node_allocator_t:: + segment_manager segment_manager; + typedef typename private_node_allocator_t:: + multiallocation_chain multiallocation_chain; + typedef typename private_node_allocator_t:: + size_type size_type; + + private: + typedef typename segment_manager::mutex_family::mutex_type mutex_type; + + public: + //!Constructor from a segment manager. Never throws + shared_pool_impl(segment_manager *segment_mngr) + : private_node_allocator_t(segment_mngr) + {} + + //!Destructor. Deallocates all allocated blocks. Never throws + ~shared_pool_impl() + {} + + //!Allocates array of count elements. Can throw boost::interprocess::bad_alloc + void *allocate_node() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return private_node_allocator_t::allocate_node(); + } + + //!Deallocates an array pointed by ptr. Never throws + void deallocate_node(void *ptr) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_node(ptr); + } + + //!Allocates n nodes. + //!Can throw boost::interprocess::bad_alloc + void allocate_nodes(const size_type n, multiallocation_chain &chain) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::allocate_nodes(n, chain); + } + + //!Deallocates a linked list of nodes ending in null pointer. Never throws + void deallocate_nodes(multiallocation_chain &nodes, size_type num) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_nodes(nodes, num); + } + + //!Deallocates the nodes pointed by the multiallocation iterator. Never throws + void deallocate_nodes(multiallocation_chain &chain) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_nodes(chain); + } + + //!Deallocates all the free blocks of memory. Never throws + void deallocate_free_blocks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_free_blocks(); + } + + //!Deallocates all used memory from the common pool. + //!Precondition: all nodes allocated from this pool should + //!already be deallocated. Otherwise, undefined behavior. Never throws + void purge_blocks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::purge_blocks(); + } + + //!Increments internal reference count and returns new count. Never throws + size_type inc_ref_count() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return ++m_header.m_usecount; + } + + //!Decrements internal reference count and returns new count. Never throws + size_type dec_ref_count() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + BOOST_ASSERT(m_header.m_usecount > 0); + return --m_header.m_usecount; + } + + //!Deprecated, use deallocate_free_blocks. + void deallocate_free_chunks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_free_blocks(); + } + + //!Deprecated, use purge_blocks. + void purge_chunks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::purge_blocks(); + } + + private: + //!This struct includes needed data and derives from + //!the mutex type to allow EBO when using null_mutex + struct header_t : mutex_type + { + size_type m_usecount; //Number of attached allocators + + header_t() + : m_usecount(0) {} + } m_header; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP diff --git a/libraries/boost/boost/interprocess/allocators/detail/node_pool.hpp b/libraries/boost/boost/interprocess/allocators/detail/node_pool.hpp new file mode 100644 index 000000000..9b2041f4e --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/detail/node_pool.hpp @@ -0,0 +1,111 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP +#define BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include + + +//!\file +//!Describes the real adaptive pool shared by many Interprocess adaptive pool allocators + +namespace boost { +namespace interprocess { +namespace ipcdetail { + + + +//!Pooled shared memory allocator using single segregated storage. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time +template< class SegmentManager, std::size_t NodeSize, std::size_t NodesPerBlock > +class private_node_pool + //Inherit from the implementation to avoid template bloat + : public boost::container::container_detail:: + private_node_pool_impl +{ + typedef boost::container::container_detail::private_node_pool_impl + base_t; + //Non-copyable + private_node_pool(); + private_node_pool(const private_node_pool &); + private_node_pool &operator=(const private_node_pool &); + + public: + typedef SegmentManager segment_manager; + typedef typename base_t::size_type size_type; + + static const size_type nodes_per_block = NodesPerBlock; + //Deprecated, use nodes_per_block + static const size_type nodes_per_chunk = NodesPerBlock; + + //!Constructor from a segment manager. Never throws + private_node_pool(segment_manager *segment_mngr) + : base_t(segment_mngr, NodeSize, NodesPerBlock) + {} + + //!Returns the segment manager. Never throws + segment_manager* get_segment_manager() const + { return static_cast(base_t::get_segment_manager_base()); } +}; + + +//!Pooled shared memory allocator using single segregated storage. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time +//!Pooled shared memory allocator using adaptive pool. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time +template< class SegmentManager + , std::size_t NodeSize + , std::size_t NodesPerBlock + > +class shared_node_pool + : public ipcdetail::shared_pool_impl + < private_node_pool + + > +{ + typedef ipcdetail::shared_pool_impl + < private_node_pool + + > base_t; + public: + shared_node_pool(SegmentManager *segment_mgnr) + : base_t(segment_mgnr) + {} +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP diff --git a/libraries/boost/boost/interprocess/allocators/detail/node_tools.hpp b/libraries/boost/boost/interprocess/allocators/detail/node_tools.hpp new file mode 100644 index 000000000..7f5a4f515 --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/detail/node_tools.hpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP +#define BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + + +template +struct node_slist +{ + //This hook will be used to chain the individual nodes + typedef typename bi::make_slist_base_hook + , bi::link_mode >::type slist_hook_t; + + //A node object will hold node_t when it's not allocated + struct node_t + : public slist_hook_t + {}; + + typedef typename bi::make_slist + , bi::base_hook >::type node_slist_t; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP diff --git a/libraries/boost/boost/interprocess/allocators/node_allocator.hpp b/libraries/boost/boost/interprocess/allocators/node_allocator.hpp new file mode 100644 index 000000000..8bd6dfe2c --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/node_allocator.hpp @@ -0,0 +1,453 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP +#define BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes node_allocator pooled shared memory STL compatible allocator + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace ipcdetail{ + +template < unsigned int Version + , class T + , class SegmentManager + , std::size_t NodesPerBlock + > +class node_allocator_base + : public node_pool_allocation_impl + < node_allocator_base + < Version, T, SegmentManager, NodesPerBlock> + , Version + , T + , SegmentManager + > +{ + public: + typedef typename SegmentManager::void_pointer void_pointer; + typedef SegmentManager segment_manager; + typedef node_allocator_base + self_t; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + template + struct node_pool + { + typedef ipcdetail::shared_node_pool + < SegmentManager, sizeof_value::value, NodesPerBlock> type; + + static type *get(void *p) + { return static_cast(p); } + }; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + BOOST_STATIC_ASSERT((Version <=2)); + + public: + //------- + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + typedef boost::interprocess::version_type version; + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + + //!Obtains node_allocator_base from + //!node_allocator_base + template + struct rebind + { + typedef node_allocator_base other; + }; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + //!Not assignable from related node_allocator_base + template + node_allocator_base& operator= + (const node_allocator_base&); + + //!Not assignable from other node_allocator_base + //node_allocator_base& operator=(const node_allocator_base&); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor from a segment manager. If not present, constructs a node + //!pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + node_allocator_base(segment_manager *segment_mngr) + : mp_node_pool(ipcdetail::get_or_create_node_pool::type>(segment_mngr)) { } + + //!Copy constructor from other node_allocator_base. Increments the reference + //!count of the associated node pool. Never throws + node_allocator_base(const node_allocator_base &other) + : mp_node_pool(other.get_node_pool()) + { + node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))->inc_ref_count(); + } + + //!Copy constructor from related node_allocator_base. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + node_allocator_base + (const node_allocator_base &other) + : mp_node_pool(ipcdetail::get_or_create_node_pool::type>(other.get_segment_manager())) { } + + //!Assignment from other node_allocator_base + node_allocator_base& operator=(const node_allocator_base &other) + { + node_allocator_base c(other); + boost::adl_move_swap(*this, c); + return *this; + } + + //!Destructor, removes node_pool_t from memory + //!if its reference count reaches to zero. Never throws + ~node_allocator_base() + { ipcdetail::destroy_node_pool_if_last_link(node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))); } + + //!Returns a pointer to the node pool. + //!Never throws + void* get_node_pool() const + { return ipcdetail::to_raw_pointer(mp_node_pool); } + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const + { return node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))->get_segment_manager(); } + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2) + { boost::adl_move_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + void_pointer mp_node_pool; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!Equality test for same type +//!of node_allocator_base +template inline +bool operator==(const node_allocator_base &alloc1, + const node_allocator_base &alloc2) + { return alloc1.get_node_pool() == alloc2.get_node_pool(); } + +//!Inequality test for same type +//!of node_allocator_base +template inline +bool operator!=(const node_allocator_base &alloc1, + const node_allocator_base &alloc2) + { return alloc1.get_node_pool() != alloc2.get_node_pool(); } + +template < class T + , class SegmentManager + , std::size_t NodesPerBlock = 64 + > +class node_allocator_v1 + : public node_allocator_base + < 1 + , T + , SegmentManager + , NodesPerBlock + > +{ + public: + typedef ipcdetail::node_allocator_base + < 1, T, SegmentManager, NodesPerBlock> base_t; + + template + struct rebind + { + typedef node_allocator_v1 other; + }; + + node_allocator_v1(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + node_allocator_v1 + (const node_allocator_v1 &other) + : base_t(other) + {} +}; + +} //namespace ipcdetail{ + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!An STL node allocator that uses a segment manager as memory +//!source. The internal pointer type will of the same type (raw, smart) as +//!"typename SegmentManager::void_pointer" type. This allows +//!placing the allocator in shared memory, memory mapped-files, etc... +//!This node allocator shares a segregated storage between all instances +//!of node_allocator with equal sizeof(T) placed in the same segment +//!group. NodesPerBlock is the number of nodes allocated at once when the allocator +//!runs out of nodes +template < class T + , class SegmentManager + , std::size_t NodesPerBlock + > +class node_allocator + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + : public ipcdetail::node_allocator_base + < 2 + , T + , SegmentManager + , NodesPerBlock + > + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef ipcdetail::node_allocator_base + < 2, T, SegmentManager, NodesPerBlock> base_t; + public: + typedef boost::interprocess::version_type version; + + template + struct rebind + { + typedef node_allocator other; + }; + + node_allocator(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + node_allocator + (const node_allocator &other) + : base_t(other) + {} + + #else //BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + typedef implementation_defined::segment_manager segment_manager; + typedef segment_manager::void_pointer void_pointer; + typedef implementation_defined::pointer pointer; + typedef implementation_defined::const_pointer const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + //!Obtains node_allocator from + //!node_allocator + template + struct rebind + { + typedef node_allocator other; + }; + + private: + //!Not assignable from + //!related node_allocator + template + node_allocator& operator= + (const node_allocator&); + + //!Not assignable from + //!other node_allocator + //node_allocator& operator=(const node_allocator&); + + public: + //!Constructor from a segment manager. If not present, constructs a node + //!pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + node_allocator(segment_manager *segment_mngr); + + //!Copy constructor from other node_allocator. Increments the reference + //!count of the associated node pool. Never throws + node_allocator(const node_allocator &other); + + //!Copy constructor from related node_allocator. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + node_allocator + (const node_allocator &other); + + //!Destructor, removes node_pool_t from memory + //!if its reference count reaches to zero. Never throws + ~node_allocator(); + + //!Returns a pointer to the node pool. + //!Never throws + void* get_node_pool() const; + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const; + + //!Returns the number of elements that could be allocated. + //!Never throws + size_type max_size() const; + + //!Allocate memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_pointer hint = 0); + + //!Deallocate allocated memory. + //!Never throws + void deallocate(const pointer &ptr, size_type count); + + //!Deallocates all free blocks + //!of the pool + void deallocate_free_blocks(); + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2); + + //!Returns address of mutable object. + //!Never throws + pointer address(reference value) const; + + //!Returns address of non mutable object. + //!Never throws + const_pointer address(const_reference value) const; + + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); + + //!Destroys object. Throws if object's + //!destructor throws + void destroy(const pointer &ptr); + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. This size only works for memory allocated with + //!allocate, allocation_command and allocate_many. + size_type size(const pointer &p) const; + + pointer allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain); + + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous block + //!of memory. The elements must be deallocated + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain &chain); + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one(); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void allocate_individual(size_type num_elements, multiallocation_chain &chain); + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain); + #endif +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of node_allocator +template inline +bool operator==(const node_allocator &alloc1, + const node_allocator &alloc2); + +//!Inequality test for same type +//!of node_allocator +template inline +bool operator!=(const node_allocator &alloc1, + const node_allocator &alloc2); + +#endif + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP diff --git a/libraries/boost/boost/interprocess/allocators/private_adaptive_pool.hpp b/libraries/boost/boost/interprocess/allocators/private_adaptive_pool.hpp new file mode 100644 index 000000000..89299299c --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -0,0 +1,469 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP +#define BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes private_adaptive_pool_base pooled shared memory STL compatible allocator + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace ipcdetail { + +template < unsigned int Version + , class T + , class SegmentManager + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , unsigned char OverheadPercent + > +class private_adaptive_pool_base + : public node_pool_allocation_impl + < private_adaptive_pool_base < Version, T, SegmentManager, NodesPerBlock + , MaxFreeBlocks, OverheadPercent> + , Version + , T + , SegmentManager + > +{ + public: + //Segment manager + typedef SegmentManager segment_manager; + typedef typename SegmentManager::void_pointer void_pointer; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef private_adaptive_pool_base + < Version, T, SegmentManager, NodesPerBlock + , MaxFreeBlocks, OverheadPercent> self_t; + typedef ipcdetail::private_adaptive_node_pool + ::value + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > node_pool_t; + + BOOST_STATIC_ASSERT((Version <=2)); + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::size_type difference_type; + typedef boost::interprocess::version_type + version; + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + + //!Obtains node_allocator from other node_allocator + template + struct rebind + { + typedef private_adaptive_pool_base + other; + }; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + template + struct node_pool + { + typedef ipcdetail::private_adaptive_node_pool + ::value + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > type; + + static type *get(void *p) + { return static_cast(p); } + }; + + private: + //!Not assignable from related private_adaptive_pool_base + template + private_adaptive_pool_base& operator= + (const private_adaptive_pool_base&); + + //!Not assignable from other private_adaptive_pool_base + private_adaptive_pool_base& operator=(const private_adaptive_pool_base&); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor from a segment manager + private_adaptive_pool_base(segment_manager *segment_mngr) + : m_node_pool(segment_mngr) + {} + + //!Copy constructor from other private_adaptive_pool_base. Never throws + private_adaptive_pool_base(const private_adaptive_pool_base &other) + : m_node_pool(other.get_segment_manager()) + {} + + //!Copy constructor from related private_adaptive_pool_base. Never throws. + template + private_adaptive_pool_base + (const private_adaptive_pool_base + &other) + : m_node_pool(other.get_segment_manager()) + {} + + //!Destructor, frees all used memory. Never throws + ~private_adaptive_pool_base() + {} + + //!Returns the segment manager. Never throws + segment_manager* get_segment_manager()const + { return m_node_pool.get_segment_manager(); } + + //!Returns the internal node pool. Never throws + node_pool_t* get_node_pool() const + { return const_cast(&m_node_pool); } + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different shared memory segments, the result is undefined. + friend void swap(self_t &alloc1,self_t &alloc2) + { boost::adl_move_swap(alloc1.m_node_pool, alloc2.m_node_pool); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + node_pool_t m_node_pool; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!Equality test for same type of private_adaptive_pool_base +template inline +bool operator==(const private_adaptive_pool_base &alloc1, + const private_adaptive_pool_base &alloc2) +{ return &alloc1 == &alloc2; } + +//!Inequality test for same type of private_adaptive_pool_base +template inline +bool operator!=(const private_adaptive_pool_base &alloc1, + const private_adaptive_pool_base &alloc2) +{ return &alloc1 != &alloc2; } + +template < class T + , class SegmentManager + , std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2 + , unsigned char OverheadPercent = 5 + > +class private_adaptive_pool_v1 + : public private_adaptive_pool_base + < 1 + , T + , SegmentManager + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > +{ + public: + typedef ipcdetail::private_adaptive_pool_base + < 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; + + template + struct rebind + { + typedef private_adaptive_pool_v1 other; + }; + + private_adaptive_pool_v1(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + private_adaptive_pool_v1 + (const private_adaptive_pool_v1 &other) + : base_t(other) + {} +}; + +} //namespace ipcdetail { + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!An STL node allocator that uses a segment manager as memory +//!source. The internal pointer type will of the same type (raw, smart) as +//!"typename SegmentManager::void_pointer" type. This allows +//!placing the allocator in shared memory, memory mapped-files, etc... +//!This allocator has its own node pool. +//! +//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when +//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks +//!that the adaptive node pool will hold. The rest of the totally free blocks will be +//!deallocated with the segment manager. +//! +//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator: +//!(memory usable for nodes / total memory allocated from the segment manager) +template < class T + , class SegmentManager + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , unsigned char OverheadPercent + > +class private_adaptive_pool + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + : public ipcdetail::private_adaptive_pool_base + < 2 + , T + , SegmentManager + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef ipcdetail::private_adaptive_pool_base + < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; + public: + typedef boost::interprocess::version_type version; + + template + struct rebind + { + typedef private_adaptive_pool + other; + }; + + private_adaptive_pool(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + private_adaptive_pool + (const private_adaptive_pool &other) + : base_t(other) + {} + + #else + public: + typedef implementation_defined::segment_manager segment_manager; + typedef segment_manager::void_pointer void_pointer; + typedef implementation_defined::pointer pointer; + typedef implementation_defined::const_pointer const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + //!Obtains private_adaptive_pool from + //!private_adaptive_pool + template + struct rebind + { + typedef private_adaptive_pool + other; + }; + + private: + //!Not assignable from + //!related private_adaptive_pool + template + private_adaptive_pool& operator= + (const private_adaptive_pool&); + + //!Not assignable from + //!other private_adaptive_pool + private_adaptive_pool& operator=(const private_adaptive_pool&); + + public: + //!Constructor from a segment manager. If not present, constructs a node + //!pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + private_adaptive_pool(segment_manager *segment_mngr); + + //!Copy constructor from other private_adaptive_pool. Increments the reference + //!count of the associated node pool. Never throws + private_adaptive_pool(const private_adaptive_pool &other); + + //!Copy constructor from related private_adaptive_pool. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + private_adaptive_pool + (const private_adaptive_pool &other); + + //!Destructor, removes node_pool_t from memory + //!if its reference count reaches to zero. Never throws + ~private_adaptive_pool(); + + //!Returns a pointer to the node pool. + //!Never throws + node_pool_t* get_node_pool() const; + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const; + + //!Returns the number of elements that could be allocated. + //!Never throws + size_type max_size() const; + + //!Allocate memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_pointer hint = 0); + + //!Deallocate allocated memory. + //!Never throws + void deallocate(const pointer &ptr, size_type count); + + //!Deallocates all free blocks + //!of the pool + void deallocate_free_blocks(); + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2); + + //!Returns address of mutable object. + //!Never throws + pointer address(reference value) const; + + //!Returns address of non mutable object. + //!Never throws + const_pointer address(const_reference value) const; + + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); + + //!Destroys object. Throws if object's + //!destructor throws + void destroy(const pointer &ptr); + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. This size only works for memory allocated with + //!allocate, allocation_command and allocate_many. + size_type size(const pointer &p) const; + + pointer allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain); + + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous block + //!of memory. The elements must be deallocated + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain &chain); + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one(); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void allocate_individual(size_type num_elements, multiallocation_chain &chain); + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain); + #endif +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of private_adaptive_pool +template inline +bool operator==(const private_adaptive_pool &alloc1, + const private_adaptive_pool &alloc2); + +//!Inequality test for same type +//!of private_adaptive_pool +template inline +bool operator!=(const private_adaptive_pool &alloc1, + const private_adaptive_pool &alloc2); + +#endif + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP + diff --git a/libraries/boost/boost/interprocess/allocators/private_node_allocator.hpp b/libraries/boost/boost/interprocess/allocators/private_node_allocator.hpp new file mode 100644 index 000000000..24fb84c15 --- /dev/null +++ b/libraries/boost/boost/interprocess/allocators/private_node_allocator.hpp @@ -0,0 +1,446 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP +#define BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes private_node_allocator_base pooled shared memory STL compatible allocator + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace ipcdetail { + +template < unsigned int Version + , class T + , class SegmentManager + , std::size_t NodesPerBlock + > +class private_node_allocator_base + : public node_pool_allocation_impl + < private_node_allocator_base < Version, T, SegmentManager, NodesPerBlock> + , Version + , T + , SegmentManager + > +{ + public: + //Segment manager + typedef SegmentManager segment_manager; + typedef typename SegmentManager::void_pointer void_pointer; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef private_node_allocator_base + < Version, T, SegmentManager, NodesPerBlock> self_t; + typedef ipcdetail::private_node_pool + ::value + , NodesPerBlock + > node_pool_t; + + BOOST_STATIC_ASSERT((Version <=2)); + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + typedef boost::interprocess::version_type + version; + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + + //!Obtains node_allocator from other node_allocator + template + struct rebind + { + typedef private_node_allocator_base + other; + }; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + template + struct node_pool + { + typedef ipcdetail::private_node_pool + ::value + , NodesPerBlock + > type; + + static type *get(void *p) + { return static_cast(p); } + }; + + private: + //!Not assignable from related private_node_allocator_base + template + private_node_allocator_base& operator= + (const private_node_allocator_base&); + + //!Not assignable from other private_node_allocator_base + private_node_allocator_base& operator=(const private_node_allocator_base&); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor from a segment manager + private_node_allocator_base(segment_manager *segment_mngr) + : m_node_pool(segment_mngr) + {} + + //!Copy constructor from other private_node_allocator_base. Never throws + private_node_allocator_base(const private_node_allocator_base &other) + : m_node_pool(other.get_segment_manager()) + {} + + //!Copy constructor from related private_node_allocator_base. Never throws. + template + private_node_allocator_base + (const private_node_allocator_base + &other) + : m_node_pool(other.get_segment_manager()) + {} + + //!Destructor, frees all used memory. Never throws + ~private_node_allocator_base() + {} + + //!Returns the segment manager. Never throws + segment_manager* get_segment_manager()const + { return m_node_pool.get_segment_manager(); } + + //!Returns the internal node pool. Never throws + node_pool_t* get_node_pool() const + { return const_cast(&m_node_pool); } + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different shared memory segments, the result is undefined. + friend void swap(self_t &alloc1,self_t &alloc2) + { boost::adl_move_swap(alloc1.m_node_pool, alloc2.m_node_pool); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + node_pool_t m_node_pool; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!Equality test for same type of private_node_allocator_base +template inline +bool operator==(const private_node_allocator_base &alloc1, + const private_node_allocator_base &alloc2) +{ return &alloc1 == &alloc2; } + +//!Inequality test for same type of private_node_allocator_base +template inline +bool operator!=(const private_node_allocator_base &alloc1, + const private_node_allocator_base &alloc2) +{ return &alloc1 != &alloc2; } + +template < class T + , class SegmentManager + , std::size_t NodesPerBlock = 64 + > +class private_node_allocator_v1 + : public private_node_allocator_base + < 1 + , T + , SegmentManager + , NodesPerBlock + > +{ + public: + typedef ipcdetail::private_node_allocator_base + < 1, T, SegmentManager, NodesPerBlock> base_t; + + template + struct rebind + { + typedef private_node_allocator_v1 other; + }; + + private_node_allocator_v1(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + private_node_allocator_v1 + (const private_node_allocator_v1 &other) + : base_t(other) + {} +}; + +} //namespace ipcdetail { + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!An STL node allocator that uses a segment manager as memory +//!source. The internal pointer type will of the same type (raw, smart) as +//!"typename SegmentManager::void_pointer" type. This allows +//!placing the allocator in shared memory, memory mapped-files, etc... +//!This allocator has its own node pool. NodesPerBlock is the number of nodes allocated +//!at once when the allocator needs runs out of nodes +template < class T + , class SegmentManager + , std::size_t NodesPerBlock + > +class private_node_allocator + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + : public ipcdetail::private_node_allocator_base + < 2 + , T + , SegmentManager + , NodesPerBlock + > + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef ipcdetail::private_node_allocator_base + < 2, T, SegmentManager, NodesPerBlock> base_t; + public: + typedef boost::interprocess::version_type version; + + template + struct rebind + { + typedef private_node_allocator + other; + }; + + private_node_allocator(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + private_node_allocator + (const private_node_allocator &other) + : base_t(other) + {} + + #else + public: + typedef implementation_defined::segment_manager segment_manager; + typedef segment_manager::void_pointer void_pointer; + typedef implementation_defined::pointer pointer; + typedef implementation_defined::const_pointer const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manage::difference_type difference_type; + + //!Obtains private_node_allocator from + //!private_node_allocator + template + struct rebind + { + typedef private_node_allocator + other; + }; + + private: + //!Not assignable from + //!related private_node_allocator + template + private_node_allocator& operator= + (const private_node_allocator&); + + //!Not assignable from + //!other private_node_allocator + private_node_allocator& operator=(const private_node_allocator&); + + public: + //!Constructor from a segment manager. If not present, constructs a node + //!pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + private_node_allocator(segment_manager *segment_mngr); + + //!Copy constructor from other private_node_allocator. Increments the reference + //!count of the associated node pool. Never throws + private_node_allocator(const private_node_allocator &other); + + //!Copy constructor from related private_node_allocator. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + private_node_allocator + (const private_node_allocator &other); + + //!Destructor, removes node_pool_t from memory + //!if its reference count reaches to zero. Never throws + ~private_node_allocator(); + + //!Returns a pointer to the node pool. + //!Never throws + node_pool_t* get_node_pool() const; + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const; + + //!Returns the number of elements that could be allocated. + //!Never throws + size_type max_size() const; + + //!Allocate memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_pointer hint = 0); + + //!Deallocate allocated memory. + //!Never throws + void deallocate(const pointer &ptr, size_type count); + + //!Deallocates all free blocks + //!of the pool + void deallocate_free_blocks(); + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2); + + //!Returns address of mutable object. + //!Never throws + pointer address(reference value) const; + + //!Returns address of non mutable object. + //!Never throws + const_pointer address(const_reference value) const; + + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); + + //!Destroys object. Throws if object's + //!destructor throws + void destroy(const pointer &ptr); + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. This size only works for memory allocated with + //!allocate, allocation_command and allocate_many. + size_type size(const pointer &p) const; + + pointer allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain); + + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous block + //!of memory. The elements must be deallocated + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain); + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain &chain); + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one(); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void allocate_individual(size_type num_elements, multiallocation_chain &chain); + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p); + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain); + #endif +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of private_node_allocator +template inline +bool operator==(const private_node_allocator &alloc1, + const private_node_allocator &alloc2); + +//!Inequality test for same type +//!of private_node_allocator +template inline +bool operator!=(const private_node_allocator &alloc1, + const private_node_allocator &alloc2); + +#endif + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP + diff --git a/libraries/boost/boost/interprocess/anonymous_shared_memory.hpp b/libraries/boost/boost/interprocess/anonymous_shared_memory.hpp new file mode 100644 index 000000000..f73b55735 --- /dev/null +++ b/libraries/boost/boost/interprocess/anonymous_shared_memory.hpp @@ -0,0 +1,125 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if (!defined(BOOST_INTERPROCESS_WINDOWS)) +# include //open, O_CREAT, O_*... +# include //mmap +# include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, +#else +#include +#endif + + +//!\file +//!Describes a function that creates anonymous shared memory that can be +//!shared between forked processes + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace ipcdetail{ + + class raw_mapped_region_creator + { + public: + static mapped_region + create_posix_mapped_region(void *address, std::size_t size) + { + mapped_region region; + region.m_base = address; + region.m_size = size; + return region; + } + }; +} + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!A function that creates an anonymous shared memory segment of size "size". +//!If "address" is passed the function will try to map the segment in that address. +//!Otherwise the operating system will choose the mapping address. +//!The function returns a mapped_region holding that segment or throws +//!interprocess_exception if the function fails. +//static mapped_region +static mapped_region +anonymous_shared_memory(std::size_t size, void *address = 0) +#if (!defined(BOOST_INTERPROCESS_WINDOWS)) +{ + int flags; + int fd = -1; + + #if defined(MAP_ANONYMOUS) //Use MAP_ANONYMOUS + flags = MAP_ANONYMOUS | MAP_SHARED; + #elif !defined(MAP_ANONYMOUS) && defined(MAP_ANON) //use MAP_ANON + flags = MAP_ANON | MAP_SHARED; + #else // Use "/dev/zero" + fd = open("/dev/zero", O_RDWR); + flags = MAP_SHARED; + if(fd == -1){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + #endif + + + address = mmap( address + , size + , PROT_READ|PROT_WRITE + , flags + , fd + , 0); + + if(address == MAP_FAILED){ + if(fd != -1) + close(fd); + error_info err = system_error_code(); + throw interprocess_exception(err); + } + + if(fd != -1) + close(fd); + + return ipcdetail::raw_mapped_region_creator::create_posix_mapped_region(address, size); +} +#else +{ + windows_shared_memory anonymous_mapping(create_only, 0, read_write, size); + return mapped_region(anonymous_mapping, read_write, 0, size, address); +} + +#endif + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP diff --git a/libraries/boost/boost/interprocess/containers/allocation_type.hpp b/libraries/boost/boost/interprocess/containers/allocation_type.hpp new file mode 100644 index 000000000..717520747 --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/allocation_type.hpp @@ -0,0 +1,44 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +typedef int allocation_type; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +static const allocation_type allocate_new = boost::container::allocate_new; +static const allocation_type expand_fwd = boost::container::expand_fwd; +static const allocation_type expand_bwd = boost::container::expand_bwd; +static const allocation_type shrink_in_place = boost::container::shrink_in_place; +static const allocation_type try_shrink_in_place= boost::container::try_shrink_in_place; +static const allocation_type nothrow_allocation = boost::container::nothrow_allocation; +static const allocation_type zero_memory = boost::container::zero_memory; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP diff --git a/libraries/boost/boost/interprocess/containers/containers_fwd.hpp b/libraries/boost/boost/interprocess/containers/containers_fwd.hpp new file mode 100644 index 000000000..9620a92ee --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/containers_fwd.hpp @@ -0,0 +1,44 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP +#define BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +////////////////////////////////////////////////////////////////////////////// +// Standard predeclarations +////////////////////////////////////////////////////////////////////////////// + +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::ordered_range; +using boost::container::ordered_unique_range; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP diff --git a/libraries/boost/boost/interprocess/containers/deque.hpp b/libraries/boost/boost/interprocess/containers/deque.hpp new file mode 100644 index 000000000..500730600 --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/deque.hpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::deque; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP + diff --git a/libraries/boost/boost/interprocess/containers/flat_map.hpp b/libraries/boost/boost/interprocess/containers/flat_map.hpp new file mode 100644 index 000000000..6b9262b8d --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/flat_map.hpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP +#define BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::flat_map; +using boost::container::flat_multimap; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP diff --git a/libraries/boost/boost/interprocess/containers/flat_set.hpp b/libraries/boost/boost/interprocess/containers/flat_set.hpp new file mode 100644 index 000000000..9c729a67e --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/flat_set.hpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP +#define BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::flat_set; +using boost::container::flat_multiset; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP diff --git a/libraries/boost/boost/interprocess/containers/list.hpp b/libraries/boost/boost/interprocess/containers/list.hpp new file mode 100644 index 000000000..465e88286 --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/list.hpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP +#define BOOST_INTERPROCESS_CONTAINERS_LIST_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::list; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP + diff --git a/libraries/boost/boost/interprocess/containers/map.hpp b/libraries/boost/boost/interprocess/containers/map.hpp new file mode 100644 index 000000000..966abdf39 --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/map.hpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP +#define BOOST_INTERPROCESS_CONTAINERS_MAP_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::map; +using boost::container::multimap; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP diff --git a/libraries/boost/boost/interprocess/containers/pair.hpp b/libraries/boost/boost/interprocess/containers/pair.hpp new file mode 100644 index 000000000..a6e11f49d --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/pair.hpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::container_detail::pair; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP + diff --git a/libraries/boost/boost/interprocess/containers/set.hpp b/libraries/boost/boost/interprocess/containers/set.hpp new file mode 100644 index 000000000..433607ba2 --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/set.hpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP +#define BOOST_INTERPROCESS_CONTAINERS_SET_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::set; +using boost::container::multiset; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP diff --git a/libraries/boost/boost/interprocess/containers/slist.hpp b/libraries/boost/boost/interprocess/containers/slist.hpp new file mode 100644 index 000000000..1f1aee63d --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/slist.hpp @@ -0,0 +1,36 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP +#define BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::slist; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP diff --git a/libraries/boost/boost/interprocess/containers/stable_vector.hpp b/libraries/boost/boost/interprocess/containers/stable_vector.hpp new file mode 100644 index 000000000..f6d1ee1b0 --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/stable_vector.hpp @@ -0,0 +1,36 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { + namespace interprocess { + + using boost::container::stable_vector; + + } //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP diff --git a/libraries/boost/boost/interprocess/containers/string.hpp b/libraries/boost/boost/interprocess/containers/string.hpp new file mode 100644 index 000000000..bd1286411 --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/string.hpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP +#define BOOST_INTERPROCESS_CONTAINERS_STRING_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::basic_string; +using boost::container::string; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP diff --git a/libraries/boost/boost/interprocess/containers/vector.hpp b/libraries/boost/boost/interprocess/containers/vector.hpp new file mode 100644 index 000000000..89b3e4714 --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/vector.hpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::vector; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP + diff --git a/libraries/boost/boost/interprocess/containers/version_type.hpp b/libraries/boost/boost/interprocess/containers/version_type.hpp new file mode 100644 index 000000000..22b5eef4f --- /dev/null +++ b/libraries/boost/boost/interprocess/containers/version_type.hpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::container_detail::version_type; +using boost::container::container_detail::version; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP + diff --git a/libraries/boost/boost/interprocess/creation_tags.hpp b/libraries/boost/boost/interprocess/creation_tags.hpp new file mode 100644 index 000000000..faf4e6f2d --- /dev/null +++ b/libraries/boost/boost/interprocess/creation_tags.hpp @@ -0,0 +1,85 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CREATION_TAGS_HPP +#define BOOST_INTERPROCESS_CREATION_TAGS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +//!Tag to indicate that the resource must +//!be only created +struct create_only_t {}; + +//!Tag to indicate that the resource must +//!be only opened +struct open_only_t {}; + +//!Tag to indicate that the resource must +//!be only opened for reading +struct open_read_only_t {}; + +//!Tag to indicate that the resource must +//!be only opened privately for reading +struct open_read_private_t {}; + +//!Tag to indicate that the resource must +//!be only opened for reading +struct open_copy_on_write_t {}; + +//!Tag to indicate that the resource must +//!be created. If already created, it must be opened. +struct open_or_create_t {}; + +//!Value to indicate that the resource must +//!be only created +static const create_only_t create_only = create_only_t(); + +//!Value to indicate that the resource must +//!be only opened +static const open_only_t open_only = open_only_t(); + +//!Value to indicate that the resource must +//!be only opened for reading +static const open_read_only_t open_read_only = open_read_only_t(); + +//!Value to indicate that the resource must +//!be created. If already created, it must be opened. +static const open_or_create_t open_or_create = open_or_create_t(); + +//!Value to indicate that the resource must +//!be only opened for reading +static const open_copy_on_write_t open_copy_on_write = open_copy_on_write_t(); + +namespace ipcdetail { + +enum create_enum_t +{ DoCreate, DoOpen, DoOpenOrCreate }; + +} //namespace ipcdetail { + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_CREATION_TAGS_HPP + diff --git a/libraries/boost/boost/interprocess/detail/atomic.hpp b/libraries/boost/boost/interprocess/detail/atomic.hpp new file mode 100644 index 000000000..e32f056c3 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/atomic.hpp @@ -0,0 +1,601 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012 +// (C) Copyright Markus Schoepflin 2007 +// (C) Copyright Bryce Lelbach 2010 +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP +#define BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#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 + +#if defined( _MSC_VER ) + extern "C" void _ReadWriteBarrier(void); + #pragma intrinsic(_ReadWriteBarrier) + #define BOOST_INTERPROCESS_READ_WRITE_BARRIER _ReadWriteBarrier() +#elif defined(__GNUC__) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 + #define BOOST_INTERPROCESS_READ_WRITE_BARRIER __sync_synchronize() + #else + #define BOOST_INTERPROCESS_READ_WRITE_BARRIER __asm__ __volatile__("" : : : "memory") + #endif +#endif + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +//! Atomically decrement an boost::uint32_t by 1 +//! "mem": pointer to the atomic value +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) +{ return winapi::interlocked_decrement(reinterpret_cast(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) +{ + const boost::uint32_t val = *mem; + BOOST_INTERPROCESS_READ_WRITE_BARRIER; + return val; +} + +//! Atomically set an boost::uint32_t in memory +//! "mem": pointer to the object +//! "param": val value that the object will assume +inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ winapi::interlocked_exchange(reinterpret_cast(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__)) && !defined(_CRAYC) + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! Returns the old value of *mem +inline boost::uint32_t atomic_cas32 + (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) +{ + boost::uint32_t prev = cmp; + // This version by Mans Rullgard of Pathscale + __asm__ __volatile__ ( "lock\n\t" + "cmpxchg %2,%0" + : "+m"(*mem), "+a"(prev) + : "r"(with) + : "cc"); + + return prev; +} + +//! Atomically add 'val' to an boost::uint32_t +//! "mem": pointer to the object +//! "val": amount to add +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_add32 + (volatile boost::uint32_t *mem, boost::uint32_t val) +{ + // int r = *pw; + // *mem += val; + // return r; + int r; + + asm volatile + ( + "lock\n\t" + "xadd %1, %0": + "+m"( *mem ), "=r"( r ): // outputs (%0, %1) + "1"( val ): // inputs (%2 == %1) + "memory", "cc" // clobbers + ); + + return r; +} + +//! Atomically increment an apr_uint32_t by 1 +//! "mem": pointer to the object +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) +{ return atomic_add32(mem, 1); } + +//! Atomically decrement an boost::uint32_t by 1 +//! "mem": pointer to the atomic value +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) +{ return atomic_add32(mem, (boost::uint32_t)-1); } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ + const boost::uint32_t val = *mem; + __asm__ __volatile__ ( "" ::: "memory" ); + return val; +} + +//! Atomically set an boost::uint32_t in memory +//! "mem": pointer to the object +//! "param": val value that the object will assume +inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ + __asm__ __volatile__ + ( + "xchgl %0, %1" + : "+r" (val), "+m" (*mem) + :: "memory" + ); +} + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#elif defined(__GNUC__) && (defined(__PPC__) || defined(__ppc__)) + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +//! Atomically add 'val' to an boost::uint32_t +//! "mem": pointer to the object +//! "val": amount to add +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ + boost::uint32_t prev, temp; + + asm volatile ("1:\n\t" + "lwarx %0,0,%2\n\t" + "add %1,%0,%3\n\t" + "stwcx. %1,0,%2\n\t" + "bne- 1b" + : "=&r" (prev), "=&r" (temp) + : "b" (mem), "r" (val) + : "cc", "memory"); + return prev; +} + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! Returns the old value of *mem +inline boost::uint32_t atomic_cas32 + (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) +{ + boost::uint32_t prev; + + asm volatile ("1:\n\t" + "lwarx %0,0,%1\n\t" + "cmpw %0,%3\n\t" + "bne- 2f\n\t" + "stwcx. %2,0,%1\n\t" + "bne- 1b\n\t" + "2:" + : "=&r"(prev) + : "b" (mem), "r" (with), "r" (cmp) + : "cc", "memory"); + return prev; +} + +//! Atomically increment an apr_uint32_t by 1 +//! "mem": pointer to the object +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) +{ return atomic_add32(mem, 1); } + +//! Atomically decrement an boost::uint32_t by 1 +//! "mem": pointer to the atomic value +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) +{ return atomic_add32(mem, boost::uint32_t(-1u)); } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ + const boost::uint32_t val = *mem; + __asm__ __volatile__ ( "" ::: "memory" ); + return val; +} + +//! Atomically set an boost::uint32_t in memory +//! "mem": pointer to the object +//! "param": val value that the object will assume +inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ *mem = val; } + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#elif (defined(sun) || defined(__sun)) + +#include + +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 + +#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) +{ boost::uint32_t old_val = *mem; __sync_synchronize(); return old_val; } + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! Returns the old value of *mem +inline boost::uint32_t atomic_cas32 + (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) +{ return __sync_val_compare_and_swap(const_cast(mem), cmp, with); } + +//! Atomically set an boost::uint32_t in memory +//! "mem": pointer to the object +//! "param": val value that the object will assume +inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ __sync_synchronize(); *mem = val; } + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#else + +#error No atomic operations implemented for this platform, sorry! + +#endif + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +inline bool atomic_add_unless32 + (volatile boost::uint32_t *mem, boost::uint32_t value, boost::uint32_t unless_this) +{ + boost::uint32_t old, c(atomic_read32(mem)); + while(c != unless_this && (old = atomic_cas32(mem, c + value, c)) != c){ + c = old; + } + return c != unless_this; +} + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP diff --git a/libraries/boost/boost/interprocess/detail/cast_tags.hpp b/libraries/boost/boost/interprocess/detail/cast_tags.hpp new file mode 100644 index 000000000..e47b86344 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/cast_tags.hpp @@ -0,0 +1,31 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP +#define BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +namespace boost { namespace interprocess { namespace ipcdetail { + +struct static_cast_tag {}; +struct const_cast_tag {}; +struct dynamic_cast_tag {}; +struct reinterpret_cast_tag {}; + +}}} //namespace boost { namespace interprocess { namespace ipcdetail { + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP diff --git a/libraries/boost/boost/interprocess/detail/config_begin.hpp b/libraries/boost/boost/interprocess/detail/config_begin.hpp new file mode 100644 index 000000000..d003ccd31 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/config_begin.hpp @@ -0,0 +1,50 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_CONFIG_INCLUDED +#define BOOST_INTERPROCESS_CONFIG_INCLUDED +#include +#endif + +#ifdef BOOST_MSVC + #pragma warning (push) + #pragma warning (disable : 4702) // unreachable code + #pragma warning (disable : 4706) // assignment within conditional expression + #pragma warning (disable : 4127) // conditional expression is constant + #pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned + #pragma warning (disable : 4284) // odd return type for operator-> + #pragma warning (disable : 4244) // possible loss of data + #pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2" + #pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data + #pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier" + #pragma warning (disable : 4355) // "this" : used in base member initializer list + #pragma warning (disable : 4345) // behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized + #pragma warning (disable : 4503) // "identifier" : decorated name length exceeded, name was truncated + #pragma warning (disable : 4511) // copy constructor could not be generated + #pragma warning (disable : 4512) // assignment operator could not be generated + #pragma warning (disable : 4514) // unreferenced inline removed + #pragma warning (disable : 4521) // Disable "multiple copy constructors specified" + #pragma warning (disable : 4522) // "class" : multiple assignment operators specified + #pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter + #pragma warning (disable : 4710) // function not inlined + #pragma warning (disable : 4711) // function selected for automatic inline expansion + #pragma warning (disable : 4786) // identifier truncated in debug info + #pragma warning (disable : 4996) // "function": was declared deprecated + #pragma warning (disable : 4197) // top-level volatile in cast is ignored + #pragma warning (disable : 4541) // 'typeid' used on polymorphic type 'boost::exception' + // with /GR-; unpredictable behavior may result + #pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site + #pragma warning (disable : 4671) // the copy constructor is inaccessible + #pragma warning (disable : 4250) // inherits 'x' via dominance +#endif + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif diff --git a/libraries/boost/boost/interprocess/detail/config_end.hpp b/libraries/boost/boost/interprocess/detail/config_end.hpp new file mode 100644 index 000000000..55bccd1bf --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/config_end.hpp @@ -0,0 +1,16 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#if defined BOOST_MSVC + #pragma warning (pop) +#endif + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic pop +#endif diff --git a/libraries/boost/boost/interprocess/detail/config_external_begin.hpp b/libraries/boost/boost/interprocess/detail/config_external_begin.hpp new file mode 100644 index 000000000..fb578ef01 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/config_external_begin.hpp @@ -0,0 +1,18 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_EXTERNAL_CONFIG_INCLUDED +#define BOOST_INTERPROCESS_EXTERNAL_CONFIG_INCLUDED +#include +#endif + +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wshadow" +#endif diff --git a/libraries/boost/boost/interprocess/detail/config_external_end.hpp b/libraries/boost/boost/interprocess/detail/config_external_end.hpp new file mode 100644 index 000000000..214558f58 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/config_external_end.hpp @@ -0,0 +1,12 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406) +# pragma GCC diagnostic pop +#endif diff --git a/libraries/boost/boost/interprocess/detail/file_locking_helpers.hpp b/libraries/boost/boost/interprocess/detail/file_locking_helpers.hpp new file mode 100644 index 000000000..c6688e619 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/file_locking_helpers.hpp @@ -0,0 +1,302 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP +#define BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +#include +#include +#include + +#else //defined(BOOST_INTERPROCESS_WINDOWS) + +#include +#include +#include + +#endif //defined(BOOST_INTERPROCESS_WINDOWS) + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +struct locking_file_serial_id +{ + int fd; + unsigned long dwVolumeSerialNumber; + unsigned long nFileIndexHigh; + unsigned long nFileIndexLow; + //This reference count counts the number of modules attached + //to the shared memory and lock file. This serves to unlink + //the locking file and shared memory when all modules are + //done with the global memory (shared memory) + volatile boost::uint32_t modules_attached_to_gmem_count; +}; + +inline bool lock_locking_file(int fd) +{ + int ret = 0; + while(ret != 0 && errno == EDEADLK){ + ret = _locking(fd, _LK_LOCK, 1/*lock_file_contents_length()*/); + } + return 0 == ret; +} + +inline bool try_lock_locking_file(int fd) +{ + return 0 == _locking(fd, _LK_NBLCK , 1); +} + +inline int open_or_create_and_lock_file(const char *name) +{ + permissions p; + p.set_unrestricted(); + while(1){ + file_handle_t handle = create_or_open_file(name, read_write, p); + int fd = _open_osfhandle((intptr_t)handle, _O_TEXT); + if(fd < 0){ + close_file(handle); + return fd; + } + if(!try_lock_locking_file(fd)){ + _close(fd); + return -1; + } + struct _stat s; + if(0 == _stat(name, &s)){ + return fd; + } + else{ + _close(fd); + } + } +} + +inline int try_open_and_lock_file(const char *name) +{ + file_handle_t handle = open_existing_file(name, read_write); + int fd = _open_osfhandle((intptr_t)handle, _O_TEXT); + if(fd < 0){ + close_file(handle); + return fd; + } + if(!try_lock_locking_file(fd)){ + _close(fd); + return -1; + } + return fd; +} + +inline void close_lock_file(int fd) +{ _close(fd); } + +inline bool is_valid_fd(int fd) +{ + struct _stat s; + return EBADF != _fstat(fd, &s); +} + +inline bool is_normal_file(int fd) +{ + if(_isatty(fd)) + return false; + struct _stat s; + if(0 != _fstat(fd, &s)) + return false; + return 0 != (s.st_mode & _S_IFREG); +} + +inline std::size_t get_size(int fd) +{ + struct _stat s; + if(0 != _fstat(fd, &s)) + return 0u; + return (std::size_t)s.st_size; +} + +inline bool fill_file_serial_id(int fd, locking_file_serial_id &id) +{ + winapi::interprocess_by_handle_file_information info; + if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info)) + return false; + id.fd = fd; + id.dwVolumeSerialNumber = info.dwVolumeSerialNumber; + id.nFileIndexHigh = info.nFileIndexHigh; + id.nFileIndexLow = info.nFileIndexLow; + id.modules_attached_to_gmem_count = 1; //Initialize attached count + return true; +} + +inline bool compare_file_serial(int fd, const locking_file_serial_id &id) +{ + winapi::interprocess_by_handle_file_information info; + if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info)) + return false; + + return id.dwVolumeSerialNumber == info.dwVolumeSerialNumber && + id.nFileIndexHigh == info.nFileIndexHigh && + id.nFileIndexLow == info.nFileIndexLow; +} + +#else //UNIX + +struct locking_file_serial_id +{ + int fd; + dev_t st_dev; + ino_t st_ino; + //This reference count counts the number of modules attached + //to the shared memory and lock file. This serves to unlink + //the locking file and shared memory when all modules are + //done with the global memory (shared memory) + volatile boost::uint32_t modules_attached_to_gmem_count; +}; + +inline bool lock_locking_file(int fd) +{ + int ret = 0; + while(ret != 0 && errno != EINTR){ + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + ret = fcntl (fd, F_SETLKW, &lock); + } + return 0 == ret; +} + +inline bool try_lock_locking_file(int fd) +{ + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + return 0 == fcntl (fd, F_SETLK, &lock); +} + +inline int open_or_create_and_lock_file(const char *name) +{ + permissions p; + p.set_unrestricted(); + while(1){ + int fd = create_or_open_file(name, read_write, p); + if(fd < 0){ + return fd; + } + if(!try_lock_locking_file(fd)){ + close(fd); + return -1; + } + struct stat s; + if(0 == stat(name, &s)){ + return fd; + } + else{ + close(fd); + } + } +} + +inline int try_open_and_lock_file(const char *name) +{ + int fd = open_existing_file(name, read_write); + if(fd < 0){ + return fd; + } + if(!try_lock_locking_file(fd)){ + close(fd); + return -1; + } + return fd; +} + +inline void close_lock_file(int fd) +{ close(fd); } + +inline bool is_valid_fd(int fd) +{ + struct stat s; + return EBADF != fstat(fd, &s); +} + +inline bool is_normal_file(int fd) +{ + struct stat s; + if(0 != fstat(fd, &s)) + return false; + return 0 != (s.st_mode & S_IFREG); +} + +inline std::size_t get_size(int fd) +{ + struct stat s; + if(0 != fstat(fd, &s)) + return 0u; + return (std::size_t)s.st_size; +} + +inline bool fill_file_serial_id(int fd, locking_file_serial_id &id) +{ + struct stat s; + if(0 != fstat(fd, &s)) + return false; + id.fd = fd; + id.st_dev = s.st_dev; + id.st_ino = s.st_ino; + id.modules_attached_to_gmem_count = 1; //Initialize attached count + return true; +} + +inline bool compare_file_serial(int fd, const locking_file_serial_id &id) +{ + struct stat info; + if(0 != fstat(fd, &info)) + return false; + + return id.st_dev == info.st_dev && + id.st_ino == info.st_ino; +} + +#endif + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif //BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP diff --git a/libraries/boost/boost/interprocess/detail/file_wrapper.hpp b/libraries/boost/boost/interprocess/detail/file_wrapper.hpp new file mode 100644 index 000000000..58f28e97f --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/file_wrapper.hpp @@ -0,0 +1,212 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP +#define BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +class file_wrapper +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + BOOST_MOVABLE_BUT_NOT_COPYABLE(file_wrapper) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + //!Default constructor. + //!Represents an empty file_wrapper. + file_wrapper(); + + //!Creates a file object with name "name" and mode "mode", with the access mode "mode" + //!If the file previously exists, throws an error. + file_wrapper(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm); } + + //!Tries to create a file with name "name" and mode "mode", with the + //!access mode "mode". If the file previously exists, it tries to open it with mode "mode". + //!Otherwise throws an error. + file_wrapper(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm); } + + //!Tries to open a file with name "name", with the access mode "mode". + //!If the file does not previously exist, it throws an error. + file_wrapper(open_only_t, const char *name, mode_t mode) + { this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); } + + //!Moves the ownership of "moved"'s file to *this. + //!After the call, "moved" does not represent any file. + //!Does not throw + file_wrapper(BOOST_RV_REF(file_wrapper) moved) + : m_handle(file_handle_t(ipcdetail::invalid_file())) + { this->swap(moved); } + + //!Moves the ownership of "moved"'s file to *this. + //!After the call, "moved" does not represent any file. + //!Does not throw + file_wrapper &operator=(BOOST_RV_REF(file_wrapper) moved) + { + file_wrapper tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps to file_wrappers. + //!Does not throw + void swap(file_wrapper &other); + + //!Erases a file from the system. + //!Returns false on error. Never throws + static bool remove(const char *name); + + //!Sets the size of the file + void truncate(offset_t length); + + //!Closes the + //!file + ~file_wrapper(); + + //!Returns the name of the file + //!used in the constructor + const char *get_name() const; + + //!Returns the name of the file + //!used in the constructor + bool get_size(offset_t &size) const; + + //!Returns access mode + //!used in the constructor + mode_t get_mode() const; + + //!Get mapping handle + //!to use with mapped_region + mapping_handle_t get_mapping_handle() const; + + private: + //!Closes a previously opened file mapping. Never throws. + void priv_close(); + //!Closes a previously opened file mapping. Never throws. + bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm); + + file_handle_t m_handle; + mode_t m_mode; + std::string m_filename; +}; + +inline file_wrapper::file_wrapper() + : m_handle(file_handle_t(ipcdetail::invalid_file())) +{} + +inline file_wrapper::~file_wrapper() +{ this->priv_close(); } + +inline const char *file_wrapper::get_name() const +{ return m_filename.c_str(); } + +inline bool file_wrapper::get_size(offset_t &size) const +{ return get_file_size((file_handle_t)m_handle, size); } + +inline void file_wrapper::swap(file_wrapper &other) +{ + (simple_swap)(m_handle, other.m_handle); + (simple_swap)(m_mode, other.m_mode); + m_filename.swap(other.m_filename); +} + +inline mapping_handle_t file_wrapper::get_mapping_handle() const +{ return mapping_handle_from_file_handle(m_handle); } + +inline mode_t file_wrapper::get_mode() const +{ return m_mode; } + +inline bool file_wrapper::priv_open_or_create + (ipcdetail::create_enum_t type, + const char *filename, + mode_t mode, + const permissions &perm = permissions()) +{ + m_filename = filename; + + if(mode != read_only && mode != read_write){ + error_info err(mode_error); + throw interprocess_exception(err); + } + + //Open file existing native API to obtain the handle + switch(type){ + case ipcdetail::DoOpen: + m_handle = open_existing_file(filename, mode); + break; + case ipcdetail::DoCreate: + m_handle = create_new_file(filename, mode, perm); + break; + case ipcdetail::DoOpenOrCreate: + m_handle = create_or_open_file(filename, mode, perm); + break; + default: + { + error_info err = other_error; + throw interprocess_exception(err); + } + } + + //Check for error + if(m_handle == invalid_file()){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + + m_mode = mode; + return true; +} + +inline bool file_wrapper::remove(const char *filename) +{ return delete_file(filename); } + +inline void file_wrapper::truncate(offset_t length) +{ + if(!truncate_file(m_handle, length)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } +} + +inline void file_wrapper::priv_close() +{ + if(m_handle != invalid_file()){ + close_file(m_handle); + m_handle = invalid_file(); + } +} + +} //namespace ipcdetail{ +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP diff --git a/libraries/boost/boost/interprocess/detail/in_place_interface.hpp b/libraries/boost/boost/interprocess/detail/in_place_interface.hpp new file mode 100644 index 000000000..013691ad7 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/in_place_interface.hpp @@ -0,0 +1,77 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP +#define BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include //alignment_of, aligned_storage +#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::container::container_detail::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/libraries/boost/boost/interprocess/detail/intermodule_singleton.hpp b/libraries/boost/boost/interprocess/detail/intermodule_singleton.hpp new file mode 100644 index 000000000..9279e92b4 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/intermodule_singleton.hpp @@ -0,0 +1,53 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_INTERMODULE_SINGLETON_HPP +#define BOOST_INTERPROCESS_INTERMODULE_SINGLETON_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + +#ifdef BOOST_INTERPROCESS_WINDOWS + #include +#else + #include +#endif + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +//Now this class is a singleton, initializing the singleton in +//the first get() function call if LazyInit is false. If true +//then the singleton will be initialized when loading the module. +template +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/libraries/boost/boost/interprocess/detail/intermodule_singleton_common.hpp b/libraries/boost/boost/interprocess/detail/intermodule_singleton_common.hpp new file mode 100644 index 000000000..c890c326b --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/intermodule_singleton_common.hpp @@ -0,0 +1,504 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_HPP +#define BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + +#include +#include +#include +#include //alignment_of, aligned_storage +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +namespace intermodule_singleton_helpers { + +inline void get_pid_creation_time_str(std::string &s) +{ + std::stringstream stream; + stream << get_current_process_id() << '_'; + stream.precision(6); + stream << std::fixed << get_current_process_creation_time(); + s = stream.str(); +} + +inline const char *get_map_base_name() +{ return "bip.gmem.map."; } + +inline void get_map_name(std::string &map_name) +{ + get_pid_creation_time_str(map_name); + map_name.insert(0, get_map_base_name()); +} + +inline std::size_t get_map_size() +{ return 65536; } + +template +struct thread_safe_global_map_dependant; + +} //namespace intermodule_singleton_helpers { + +//This class contains common code for all singleton types, so that we instantiate this +//code just once per module. This class also holds a thread soafe global map +//to be used by all instances protected with a reference count +template +class intermodule_singleton_common +{ + public: + typedef void*(singleton_constructor_t)(ThreadSafeGlobalMap &); + typedef void (singleton_destructor_t)(void *, ThreadSafeGlobalMap &); + + static const ::boost::uint32_t Uninitialized = 0u; + static const ::boost::uint32_t Initializing = 1u; + static const ::boost::uint32_t Initialized = 2u; + static const ::boost::uint32_t Broken = 3u; + static const ::boost::uint32_t Destroyed = 4u; + + //Initialize this_module_singleton_ptr, creates the global map if needed and also creates an unique + //opaque type in global map through a singleton_constructor_t function call, + //initializing the passed pointer to that unique instance. + // + //We have two concurrency types here. a)the global map/singleton creation must + //be safe between threads of this process but in different modules/dlls. b) + //the pointer to the singleton is per-module, so we have to protect this + //initization between threads of the same module. + // + //All static variables declared here are shared between inside a module + //so atomic operations will synchronize only threads of the same module. + static void initialize_singleton_logic + (void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_constructor_t constructor, bool phoenix) + { + //If current module is not initialized enter to lock free logic + if(atomic_read32(&this_module_singleton_initialized) != Initialized){ + //Now a single thread of the module will succeed in this CAS. + //trying to pass from Uninitialized to Initializing + ::boost::uint32_t previous_module_singleton_initialized = atomic_cas32 + (&this_module_singleton_initialized, Initializing, Uninitialized); + //If the thread succeeded the CAS (winner) it will compete with other + //winner threads from other modules to create the global map + if(previous_module_singleton_initialized == Destroyed){ + //Trying to resurrect a dead Phoenix singleton. Just try to + //mark it as uninitialized and start again + if(phoenix){ + atomic_cas32(&this_module_singleton_initialized, Uninitialized, Destroyed); + previous_module_singleton_initialized = atomic_cas32 + (&this_module_singleton_initialized, Initializing, Uninitialized); + } + //Trying to resurrect a non-Phoenix dead singleton is an error + else{ + throw interprocess_exception("Boost.Interprocess: Dead reference on non-Phoenix singleton of type"); + } + } + if(previous_module_singleton_initialized == Uninitialized){ + try{ + //Now initialize the global map, this function must solve concurrency + //issues between threads of several modules + initialize_global_map_handle(); + //Now try to create the singleton in global map. + //This function solves concurrency issues + //between threads of several modules + ThreadSafeGlobalMap *const pmap = get_map_ptr(); + void *tmp = constructor(*pmap); + //Increment the module reference count that reflects how many + //singletons this module holds, so that we can safely destroy + //module global map object when no singleton is left + atomic_inc32(&this_module_singleton_count); + //Insert a barrier before assigning the pointer to + //make sure this assignment comes after the initialization + atomic_write32(&this_module_singleton_initialized, Initializing); + //Assign the singleton address to the module-local pointer + ptr = tmp; + //Memory barrier inserted, all previous operations should complete + //before this one. Now marked as initialized + atomic_write32(&this_module_singleton_initialized, Initialized); + } + catch(...){ + //Mark singleton failed to initialize + atomic_write32(&this_module_singleton_initialized, Broken); + throw; + } + } + //If previous state was initializing, this means that another winner thread is + //trying to initialize the singleton. Just wait until completes its work. + else if(previous_module_singleton_initialized == Initializing){ + spin_wait swait; + while(1){ + previous_module_singleton_initialized = atomic_read32(&this_module_singleton_initialized); + if(previous_module_singleton_initialized >= Initialized){ + //Already initialized, or exception thrown by initializer thread + break; + } + else if(previous_module_singleton_initialized == Initializing){ + swait.yield(); + } + else{ + //This can't be happening! + BOOST_ASSERT(0); + } + } + } + else if(previous_module_singleton_initialized == Initialized){ + //Nothing to do here, the singleton is ready + } + //If previous state was greater than initialized, then memory is broken + //trying to initialize the singleton. + else{//(previous_module_singleton_initialized > Initialized) + throw interprocess_exception("boost::interprocess::intermodule_singleton initialization failed"); + } + } + BOOST_ASSERT(ptr != 0); + } + + static void finalize_singleton_logic(void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_destructor_t destructor) + { + //Protect destruction against lazy singletons not initialized in this execution + if(ptr){ + //Note: this destructor might provoke a Phoenix singleton + //resurrection. This means that this_module_singleton_count + //might change after this call. + ThreadSafeGlobalMap * const pmap = get_map_ptr(); + destructor(ptr, *pmap); + ptr = 0; + + //Memory barrier to make sure pointer is nulled. + //Mark this singleton as destroyed. + atomic_write32(&this_module_singleton_initialized, Destroyed); + + //If this is the last singleton of this module + //apply map destruction. + //Note: singletons are destroyed when the module is unloaded + //so no threads should be executing or holding references + //to this module + if(1 == atomic_dec32(&this_module_singleton_count)){ + destroy_global_map_handle(); + } + } + } + + private: + static ThreadSafeGlobalMap *get_map_ptr() + { + return static_cast(static_cast(mem_holder.map_mem)); + } + + static void initialize_global_map_handle() + { + //Obtain unique map name and size + spin_wait swait; + while(1){ + //Try to pass map state to initializing + ::boost::uint32_t tmp = atomic_cas32(&this_module_map_initialized, Initializing, Uninitialized); + if(tmp == Initialized || tmp == Broken){ + break; + } + else if(tmp == Destroyed){ + tmp = atomic_cas32(&this_module_map_initialized, Uninitialized, Destroyed); + continue; + } + //If some other thread is doing the work wait + else if(tmp == Initializing){ + swait.yield(); + } + else{ //(tmp == Uninitialized) + //If not initialized try it again? + try{ + //Remove old global map from the system + intermodule_singleton_helpers::thread_safe_global_map_dependant::remove_old_gmem(); + //in-place construction of the global map class + ThreadSafeGlobalMap * const pmap = get_map_ptr(); + intermodule_singleton_helpers::thread_safe_global_map_dependant + ::construct_map(static_cast(pmap)); + //Use global map's internal lock to initialize the lock file + //that will mark this gmem as "in use". + typename intermodule_singleton_helpers::thread_safe_global_map_dependant:: + lock_file_logic f(*pmap); + //If function failed (maybe a competing process has erased the shared + //memory between creation and file locking), retry with a new instance. + if(f.retry()){ + pmap->~ThreadSafeGlobalMap(); + atomic_write32(&this_module_map_initialized, Destroyed); + } + else{ + //Locking succeeded, so this global map module-instance is ready + atomic_write32(&this_module_map_initialized, Initialized); + break; + } + } + catch(...){ + // + throw; + } + } + } + } + + static void destroy_global_map_handle() + { + if(!atomic_read32(&this_module_singleton_count)){ + //This module is being unloaded, so destroy + //the global map object of this module + //and unlink the global map if it's the last + ThreadSafeGlobalMap * const pmap = get_map_ptr(); + typename intermodule_singleton_helpers::thread_safe_global_map_dependant:: + unlink_map_logic f(*pmap); + pmap->~ThreadSafeGlobalMap(); + atomic_write32(&this_module_map_initialized, Destroyed); + //Do some cleanup for other processes old gmem instances + intermodule_singleton_helpers::thread_safe_global_map_dependant::remove_old_gmem(); + } + } + + //Static data, zero-initalized without any dependencies + //this_module_singleton_count is the number of singletons used by this module + static volatile boost::uint32_t this_module_singleton_count; + + //this_module_map_initialized is the state of this module's map class object. + //Values: Uninitialized, Initializing, Initialized, Broken + static volatile boost::uint32_t this_module_map_initialized; + + //Raw memory to construct the global map manager + static union mem_holder_t + { + unsigned char map_mem [sizeof(ThreadSafeGlobalMap)]; + ::boost::container::container_detail::max_align_t aligner; + } mem_holder; +}; + +template +volatile boost::uint32_t intermodule_singleton_common::this_module_singleton_count; + +template +volatile boost::uint32_t intermodule_singleton_common::this_module_map_initialized; + +template +typename intermodule_singleton_common::mem_holder_t + intermodule_singleton_common::mem_holder; + +//A reference count to be stored in global map holding the number +//of singletons (one per module) attached to the instance pointed by +//the internal ptr. +struct ref_count_ptr +{ + ref_count_ptr(void *p, boost::uint32_t count) + : ptr(p), singleton_ref_count(count) + {} + void *ptr; + //This reference count serves to count the number of attached + //modules to this singleton + volatile boost::uint32_t singleton_ref_count; +}; + + +//Now this class is a singleton, initializing the singleton in +//the first get() function call if LazyInit is true. If false +//then the singleton will be initialized when loading the module. +template +class intermodule_singleton_impl +{ + public: + + static C& get() //Let's make inlining easy + { + if(!this_module_singleton_ptr){ + if(lifetime.dummy_function()){ //This forces lifetime instantiation, for reference counted destruction + atentry_work(); + } + } + return *static_cast(this_module_singleton_ptr); + } + + private: + + static void atentry_work() + { + intermodule_singleton_common::initialize_singleton_logic + (this_module_singleton_ptr, this_module_singleton_initialized, singleton_constructor, Phoenix); + } + + static void atexit_work() + { + intermodule_singleton_common::finalize_singleton_logic + (this_module_singleton_ptr, this_module_singleton_initialized, singleton_destructor); + } + + //These statics will be zero-initialized without any constructor call dependency + //this_module_singleton_ptr will be a module-local pointer to the singleton + static void* this_module_singleton_ptr; + + //this_module_singleton_count will be used to synchronize threads of the same module + //for access to a singleton instance, and to flag the state of the + //singleton. + static volatile boost::uint32_t this_module_singleton_initialized; + + //This class destructor will trigger singleton destruction + struct lifetime_type_lazy + { + bool dummy_function() + { return m_dummy == 0; } + + ~lifetime_type_lazy() + { + //if(!Phoenix){ + //atexit_work(); + //} + } + + //Dummy volatile so that the compiler can't resolve its value at compile-time + //and can't avoid lifetime_type instantiation if dummy_function() is called. + static volatile int m_dummy; + }; + + struct lifetime_type_static + : public lifetime_type_lazy + { + lifetime_type_static() + { atentry_work(); } + }; + + typedef typename if_c + ::type lifetime_type; + + static lifetime_type lifetime; + + //A functor to be executed inside global map lock that just + //searches for the singleton in map and if not present creates a new one. + //If singleton constructor throws, the exception is propagated + struct init_atomic_func + { + init_atomic_func(ThreadSafeGlobalMap &m) + : m_map(m), ret_ptr() + {} + + void operator()() + { + ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant + ::find(m_map, typeid(C).name()); + if(!rcount){ + C *p = new C; + try{ + ref_count_ptr val(p, 0u); + rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant + ::insert(m_map, typeid(C).name(), val); + } + catch(...){ + intermodule_singleton_helpers::thread_safe_global_map_dependant + ::erase(m_map, typeid(C).name()); + delete p; + throw; + } + } + //if(Phoenix){ + std::atexit(&atexit_work); + //} + atomic_inc32(&rcount->singleton_ref_count); + ret_ptr = rcount->ptr; + } + void *data() const + { return ret_ptr; } + + private: + ThreadSafeGlobalMap &m_map; + void *ret_ptr; + }; + + //A functor to be executed inside global map lock that just + //deletes the singleton in map if the attached count reaches to zero + struct fini_atomic_func + { + fini_atomic_func(ThreadSafeGlobalMap &m) + : m_map(m) + {} + + void operator()() + { + ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant + ::find(m_map, typeid(C).name()); + //The object must exist + BOOST_ASSERT(rcount); + BOOST_ASSERT(rcount->singleton_ref_count > 0); + //Check if last reference + if(atomic_dec32(&rcount->singleton_ref_count) == 1){ + //If last, destroy the object + BOOST_ASSERT(rcount->ptr != 0); + C *pc = static_cast(rcount->ptr); + //Now destroy map entry + bool destroyed = intermodule_singleton_helpers::thread_safe_global_map_dependant + ::erase(m_map, typeid(C).name()); + (void)destroyed; BOOST_ASSERT(destroyed == true); + delete pc; + } + } + + private: + ThreadSafeGlobalMap &m_map; + }; + + //A wrapper to execute init_atomic_func + static void *singleton_constructor(ThreadSafeGlobalMap &map) + { + init_atomic_func f(map); + intermodule_singleton_helpers::thread_safe_global_map_dependant + ::atomic_func(map, f); + return f.data(); + } + + //A wrapper to execute fini_atomic_func + static void singleton_destructor(void *p, ThreadSafeGlobalMap &map) + { (void)p; + fini_atomic_func f(map); + intermodule_singleton_helpers::thread_safe_global_map_dependant + ::atomic_func(map, 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; + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_HPP diff --git a/libraries/boost/boost/interprocess/detail/interprocess_tester.hpp b/libraries/boost/boost/interprocess/detail/interprocess_tester.hpp new file mode 100644 index 000000000..368820f82 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/interprocess_tester.hpp @@ -0,0 +1,39 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP +#define BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +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/libraries/boost/boost/interprocess/detail/intersegment_ptr.hpp b/libraries/boost/boost/interprocess/detail/intersegment_ptr.hpp new file mode 100644 index 000000000..1bf97e5a2 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/intersegment_ptr.hpp @@ -0,0 +1,1044 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP +#define BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +// interprocess +#include +#include +#include +#include +#include //vector +#include //set +// interprocess/detail +#include +#include +#include +#include +#include +// other boost +#include +#include //BOOST_STATIC_ASSERT +#include +#include //BOOST_ASSERT +// std +#include //CHAR_BIT + +//!\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 standard 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/libraries/boost/boost/interprocess/detail/managed_global_memory.hpp b/libraries/boost/boost/interprocess/detail/managed_global_memory.hpp new file mode 100644 index 000000000..0f389fda2 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/managed_global_memory.hpp @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_BASIC_GLOBAL_MEMORY_HPP +#define BOOST_INTERPROCESS_BASIC_GLOBAL_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +struct intermodule_singleton_mutex_family +{ + typedef boost::interprocess::ipcdetail::spin_mutex mutex_type; + typedef boost::interprocess::ipcdetail::spin_recursive_mutex recursive_mutex_type; +}; + +struct intermodule_types +{ + //We must use offset_ptr since a loaded DLL can map the singleton holder shared memory + //at a different address than other DLLs or the main executable + typedef rbtree_best_fit > mem_algo; + template + struct open_or_create + { + typedef managed_open_or_create_impl + type; + }; +}; + +//we must implement our own managed shared memory to avoid circular dependencies +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 +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + 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) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: //functions + + basic_managed_global_memory (open_or_create_t open_or_create, + const char *name, size_type size, + const void *addr = 0, const permissions& perm = permissions()) + : base_t() + , base2_t(open_or_create, name, size, read_write, addr, + create_open_func_t(get_this_pointer(), + DoOpenOrCreate), perm) + {} + + basic_managed_global_memory (open_only_t open_only, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, read_write, addr, + create_open_func_t(get_this_pointer(), + DoOpen)) + {} +}; + + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_INTERPROCESS_BASIC_GLOBAL_MEMORY_HPP diff --git a/libraries/boost/boost/interprocess/detail/managed_memory_impl.hpp b/libraries/boost/boost/interprocess/detail/managed_memory_impl.hpp new file mode 100644 index 000000000..939dc6a97 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/managed_memory_impl.hpp @@ -0,0 +1,775 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP +#define BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# 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; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + typedef typename + segment_manager::char_ptr_holder_t char_ptr_holder_t; + //Experimental. Don't use. + + typedef typename segment_manager::multiallocation_chain multiallocation_chain; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + static const size_type PayloadPerAllocation = segment_manager::PayloadPerAllocation; + + private: + typedef basic_managed_memory_impl + 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, boost_container_new_t()) segment_manager(size); + } + BOOST_CATCH(...){ + return false; + } + BOOST_CATCH_END + return true; + } + + //!Connects to a segment manager in the reserved buffer. Never throws. + bool open_impl (void *addr, size_type) + { + if(mp_header) return false; + mp_header = static_cast(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, const std::nothrow_t &tag) + { return mp_header->allocate(nbytes, tag); } + + //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" + //!must be power of two. If no memory + //!is available returns 0. Never throws. + void * allocate_aligned (size_type nbytes, size_type alignment, const std::nothrow_t &tag) + { return mp_header->allocate_aligned(nbytes, alignment, tag); } + + template + T * allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type &prefer_in_recvd_out_size, T *&reuse) + { return mp_header->allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); } + + //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" + //!must be power of two. If no + //!memory is available throws a boost::interprocess::bad_alloc exception + void * allocate_aligned(size_type nbytes, size_type alignment) + { return mp_header->allocate_aligned(nbytes, alignment); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Experimental. Don't use. + + //!Allocates n_elements of elem_bytes bytes. + //!Throws bad_alloc on failure. chain.size() is not increased on failure. + void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + { mp_header->allocate_many(elem_bytes, n_elements, chain); } + + //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes. + //!Throws bad_alloc on failure. chain.size() is not increased on failure. + void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { mp_header->allocate_many(element_lengths, n_elements, sizeof_element, chain); } + + //!Allocates n_elements of elem_bytes bytes. + //!Non-throwing version. chain.size() is not increased on failure. + void allocate_many(const std::nothrow_t &tag, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + { mp_header->allocate_many(tag, elem_bytes, n_elements, chain); } + + //!Allocates n_elements, each one of + //!element_lengths[i]*sizeof_element bytes. + //!Non-throwing version. chain.size() is not increased on failure. + void allocate_many(const std::nothrow_t &tag, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { mp_header->allocate_many(tag, elem_sizes, n_elements, sizeof_element, chain); } + + //!Deallocates all elements contained in chain. + //!Never throws. + void deallocate_many(multiallocation_chain &chain) + { mp_header->deallocate_many(chain); } + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Marks previously allocated memory as free. Never throws. + void deallocate (void *addr) + { if (mp_header) mp_header->deallocate(addr); } + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + 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, const std::nothrow_t &tag) + { return mp_header->template construct(name, tag); } + + //!Finds or creates a named object or array in memory + //! + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. If an array is being constructed all objects are + //!created using the same parameters given to this function. + //! + //!-> Returns 0 if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and if an + //!array was being constructed, destructors of created objects are called + //!before freeing the memory. + template + typename segment_manager::template construct_proxy::type + find_or_construct(char_ptr_holder_t name, const std::nothrow_t &tag) + { return mp_header->template find_or_construct(name, tag); } + + //!Creates a named array from iterators in memory + //! + //!Allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. Each element in the array is created using the + //!objects returned when dereferencing iterators as parameters + //!and incrementing all iterators for each element. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and + //!destructors of created objects are called before freeing the memory. + template + 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, const std::nothrow_t &tag) + { return mp_header->template construct_it(name, tag); } + + //!Finds or creates a named array from iterators in memory + //! + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. Each element in the array is created using the + //!objects returned when dereferencing iterators as parameters + //!and incrementing all iterators for each element. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> If there is no available memory, returns 0. + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and + //!destructors of created objects are called before freeing the memory.*/ + template + typename segment_manager::template construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name, const std::nothrow_t &tag) + { return mp_header->template find_or_construct_it(name, tag); } + + //!Calls a functor and guarantees that no new construction, search or + //!destruction will be executed by any process while executing the object + //!function call. If the functor throws, this function throws. + template + 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. If ptr points to an unique instance typeid(T).name() is returned. + 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(); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find_no_lock (char_ptr_holder_t name) + { return mp_header->template find_no_lock(name); } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + protected: + //!Swaps the segment manager's managed by this managed memory segment. + //!NOT thread-safe. Never throws. + void swap(basic_managed_memory_impl &other) + { (simple_swap)(mp_header, other.mp_header); } + + private: + segment_manager *mp_header; +}; + +template +class create_open_func +{ + typedef typename BasicManagedMemoryImpl::size_type size_type; + + public: + + create_open_func(BasicManagedMemoryImpl * const frontend, create_enum_t type) + : m_frontend(frontend), m_type(type){} + + bool operator()(void *addr, std::size_t size, bool created) const + { + if( ((m_type == DoOpen) && created) || + ((m_type == DoCreate) && !created) || + //Check for overflow + size_type(-1) < size ){ + return false; + } + else if(created){ + return m_frontend->create_impl(addr, static_cast(size)); + } + else{ + return m_frontend->open_impl (addr, static_cast(size)); + } + } + + static std::size_t get_min_size() + { + const size_type sz = BasicManagedMemoryImpl::segment_manager::get_min_size(); + if(sz > std::size_t(-1)){ + //The minimum size is not representable by std::size_t + BOOST_ASSERT(false); + return std::size_t(-1); + } + else{ + return static_cast(sz); + } + } + + 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/libraries/boost/boost/interprocess/detail/managed_multi_shared_memory.hpp b/libraries/boost/boost/interprocess/detail/managed_multi_shared_memory.hpp new file mode 100644 index 000000000..68799b02e --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/managed_multi_shared_memory.hpp @@ -0,0 +1,429 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# 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 //string +#include //bad_alloc +#include //std::ends + +#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; + } + + static std::size_t get_min_size() + { + const size_type sz = self_t::segment_manager::get_min_size(); + if(sz > std::size_t(-1)){ + //The minimum size is not representable by std::size_t + BOOST_ASSERT(false); + return std::size_t(-1); + } + else{ + return static_cast(sz); + } + } + + self_t * const mp_frontend; + type_t m_type; + size_type m_segment_number; + }; + + //!Functor to execute atomically when closing a shared memory segment. + struct close_func + { + typedef typename + basic_managed_multi_shared_memory::void_pointer void_pointer; + + close_func(self_t * const frontend) + : mp_frontend(frontend){} + + void operator()(const mapped_region ®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/libraries/boost/boost/interprocess/detail/managed_open_or_create_impl.hpp b/libraries/boost/boost/interprocess/detail/managed_open_or_create_impl.hpp new file mode 100644 index 000000000..9351f391f --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -0,0 +1,501 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL +#define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //alignment_of, aligned_storage +#include +#include +#include + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +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 + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +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::container::container_detail::alignment_of + < ::boost::container::container_detail::max_align_t >::value) + >::value; + + managed_open_or_create_impl() + {} + + managed_open_or_create_impl(create_only_t, + const device_id_t & id, + std::size_t size, + mode_t mode, + const void *addr, + const permissions &perm) + { + priv_open_or_create + ( DoCreate + , id + , size + , mode + , addr + , perm + , null_mapped_region_function()); + } + + managed_open_or_create_impl(open_only_t, + const device_id_t & id, + mode_t mode, + const void *addr) + { + priv_open_or_create + ( DoOpen + , id + , 0 + , mode + , addr + , permissions() + , null_mapped_region_function()); + } + + + managed_open_or_create_impl(open_or_create_t, + const device_id_t & id, + std::size_t size, + mode_t mode, + const void *addr, + const permissions &perm) + { + priv_open_or_create + ( DoOpenOrCreate + , id + , size + , mode + , addr + , perm + , null_mapped_region_function()); + } + + template + 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; + bool created = false; + bool ronly = false; + bool cow = false; + DeviceAbstraction dev; + + if(type != DoOpen){ + //Check if the requested size is enough to build the managed metadata + const std::size_t func_min_size = construct_func.get_min_size(); + if( (std::size_t(-1) - ManagedOpenOrCreateUserOffset) < func_min_size || + size < (func_min_size + ManagedOpenOrCreateUserOffset) ){ + throw interprocess_exception(error_info(size_error)); + } + } + //Check size can be represented by offset_t (used by truncate) + if(type != DoOpen && !check_offset_t_size(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; + spin_wait swait; + 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 &e){ + if(e.get_error_code() != not_found_error){ + throw; + } + } + catch(...){ + throw; + } + } + } + catch(...){ + throw; + } + swait.yield(); + } + } + + if(created){ + try{ + //If this throws, we are lost + truncate_device(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; + spin_wait swait; + while(filesize == 0){ + if(!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + swait.yield(); + } + if(filesize == 1){ + throw interprocess_exception(error_info(corrupted_error)); + } + } + + mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr); + + boost::uint32_t *patomic_word = static_cast(region.get_address()); + boost::uint32_t value = atomic_read32(patomic_word); + + spin_wait swait; + while(value == InitializingSegment || value == UninitializedSegment){ + swait.yield(); + value = atomic_read32(patomic_word); + } + + if(value != InitializedSegment) + throw interprocess_exception(error_info(corrupted_error)); + + construct_func( static_cast(region.get_address()) + ManagedOpenOrCreateUserOffset + , region.get_size() - ManagedOpenOrCreateUserOffset + , false); + //All ok, just move resources to the external mapped region + m_mapped_region.swap(region); + } + if(StoreDevice){ + this->DevHolder::get_device() = boost::move(dev); + } + } + + friend void swap(managed_open_or_create_impl &left, managed_open_or_create_impl &right) + { + left.swap(right); + } + + private: + friend class interprocess_tester; + void dont_close_on_destruction() + { interprocess_tester::dont_close_on_destruction(m_mapped_region); } + + mapped_region m_mapped_region; +}; + +} //namespace ipcdetail { + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL diff --git a/libraries/boost/boost/interprocess/detail/math_functions.hpp b/libraries/boost/boost/interprocess/detail/math_functions.hpp new file mode 100644 index 000000000..a19efac1a --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/math_functions.hpp @@ -0,0 +1,118 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Stephen Cleary 2000. +// (C) Copyright Ion Gaztanaga 2007-2012. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +// This file is a slightly modified file from Boost.Pool +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#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/libraries/boost/boost/interprocess/detail/min_max.hpp b/libraries/boost/boost/interprocess/detail/min_max.hpp new file mode 100644 index 000000000..2097ff424 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/min_max.hpp @@ -0,0 +1,44 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP +#define BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# 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/libraries/boost/boost/interprocess/detail/move.hpp b/libraries/boost/boost/interprocess/detail/move.hpp new file mode 100644 index 000000000..3a2c29b05 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/move.hpp @@ -0,0 +1,36 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//! \file + +#ifndef BOOST_INTERPROCESS_DETAIL_MOVE_HPP +#define BOOST_INTERPROCESS_DETAIL_MOVE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#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/libraries/boost/boost/interprocess/detail/mpl.hpp b/libraries/boost/boost/interprocess/detail/mpl.hpp new file mode 100644 index 000000000..3dd8d63e1 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/mpl.hpp @@ -0,0 +1,122 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2016. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MPL_HPP +#define BOOST_INTERPROCESS_DETAIL_MPL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# 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< + 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 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/libraries/boost/boost/interprocess/detail/named_proxy.hpp b/libraries/boost/boost/interprocess/detail/named_proxy.hpp new file mode 100644 index 000000000..4bec375b6 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/named_proxy.hpp @@ -0,0 +1,316 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP +#define BOOST_INTERPROCESS_NAMED_PROXY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +// interprocess/detail +#include +#include +#include +#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING +#include +#else +#include +#include +#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#include + +#include + +//!\file +//!Describes a proxy class that implements named allocation syntax. + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +template +struct CtorArgN : public placement_destroy +{ + typedef bool_ IsIterator; + typedef CtorArgN 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; } + + CtorArgN(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, boost_container_new_t())T(*boost::forward(get(args_))...); } + + template + void construct(void *mem, false_, const index_tuple&) + { ::new((void*)mem, boost_container_new_t())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 + { + CtorArgN &&ctor_obj = CtorArgN + (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 + +//////////////////////////////////////////////////////////////// +// 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; +// }; +//////////////////////////////////////////////////////////////// + +#define BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN(N)\ +\ +template \ +struct CtorArg##N : placement_destroy\ +{\ + typedef CtorArg##N self_t;\ + \ + CtorArg##N ( BOOST_MOVE_UREF##N )\ + BOOST_MOVE_COLON##N BOOST_MOVE_FWD_INIT##N{}\ + \ + virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed)\ + {\ + T* memory = static_cast(mem);\ + for(constructed = 0; constructed < num; ++constructed){\ + ::new((void*)memory++) T ( BOOST_MOVE_MFWD##N );\ + }\ + }\ + \ + private:\ + BOOST_MOVE_MREF##N\ +};\ +//! +BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN) +#undef BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN + +#define BOOST_INTERPROCESS_NAMED_PROXY_CTORITN(N)\ +\ +template \ +struct CtorIt##N : public placement_destroy\ +{\ + typedef CtorIt##N self_t;\ + \ + self_t& operator++()\ + { BOOST_MOVE_MINC##N; return *this; }\ + \ + self_t operator++(int) { return ++*this; *this; }\ + \ + CtorIt##N ( BOOST_MOVE_VAL##N )\ + BOOST_MOVE_COLON##N BOOST_MOVE_VAL_INIT##N{}\ + \ + virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed)\ + {\ + T* memory = static_cast(mem);\ + for(constructed = 0; constructed < num; ++constructed){\ + ::new((void*)memory++) T( BOOST_MOVE_MITFWD##N );\ + ++(*this);\ + }\ + }\ + \ + private:\ + BOOST_MOVE_MEMB##N\ +};\ +//! +BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CTORITN) +#undef BOOST_INTERPROCESS_NAMED_PROXY_CTORITN + +//!Describes a proxy class that implements named +//!allocation syntax. +template + < class SegmentManager //segment manager to construct the object + , class T //type of object to build + , bool is_iterator //passing parameters are normal object or iterators? + > +class named_proxy +{ + typedef typename SegmentManager::char_type char_type; + const char_type * mp_name; + SegmentManager * mp_mngr; + mutable std::size_t m_num; + const bool m_find; + const bool m_dothrow; + + public: + named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow) + : mp_name(name), mp_mngr(mngr), m_num(1) + , m_find(find), m_dothrow(dothrow) + {} + + #define BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR(N)\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + T *operator()( BOOST_MOVE_UREF##N ) const\ + {\ + typedef typename if_c \ + , CtorArg##N \ + >::type ctor_obj_t;\ + ctor_obj_t ctor_obj = ctor_obj_t( BOOST_MOVE_FWD##N );\ + return mp_mngr->template generic_construct(mp_name, m_num, m_find, m_dothrow, ctor_obj);\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR) + #undef BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR + + //////////////////////////////////////////////////////////////////////// + // What the macro should generate (n == 2) + //////////////////////////////////////////////////////////////////////// + // + // template + // T *operator()(P1 &p1, P2 &p2) const + // { + // typedef CtorArg2 + // + // 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/libraries/boost/boost/interprocess/detail/nothrow.hpp b/libraries/boost/boost/interprocess/detail/nothrow.hpp new file mode 100644 index 000000000..646c9e04a --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/nothrow.hpp @@ -0,0 +1,41 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP +#define BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +namespace std { //no namespace versioning in clang+libc++ + +struct nothrow_t; + +} //namespace std { + +namespace boost{ namespace interprocess { + +template +struct nothrow +{ + static const std::nothrow_t &get() { return *pnothrow; } + static std::nothrow_t *pnothrow; +}; + +template +std::nothrow_t *nothrow::pnothrow; + +}} //namespace boost{ namespace interprocess { + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP diff --git a/libraries/boost/boost/interprocess/detail/os_file_functions.hpp b/libraries/boost/boost/interprocess/detail/os_file_functions.hpp new file mode 100644 index 000000000..bcb9576a1 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/os_file_functions.hpp @@ -0,0 +1,739 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include //make_unsigned + +#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 __int64 offset_t; +typedef struct mapping_handle_impl_t{ + void * handle; + bool is_shm; +} mapping_handle_t; + +typedef enum { read_only = winapi::generic_read + , read_write = winapi::generic_read | winapi::generic_write + , copy_on_write + , read_private + , invalid_mode = 0xffff + } mode_t; + +typedef enum { file_begin = winapi::file_begin + , file_end = winapi::file_end + , file_current = winapi::file_current + } file_pos_t; + +typedef unsigned long map_options_t; +static const map_options_t default_map_options = map_options_t(-1); + +namespace ipcdetail{ + +inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd) +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_shm = false; + return ret; +} + +inline mapping_handle_t mapping_handle_from_shm_handle(file_handle_t hnd) +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_shm = true; + return ret; +} + +inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) +{ return hnd.handle; } + +inline bool create_directory(const char *path) +{ return winapi::create_directory(path); } + +inline bool get_temporary_path(char *buffer, std::size_t buf_len, std::size_t &required_len) +{ + required_len = 0; + //std::size_t is always bigger or equal than unsigned long in Windows systems + //In case std::size_t is bigger than unsigned long + unsigned long buf = buf_len; + if(buf_len != buf){ //maybe overflowed + return false; + } + required_len = winapi::get_temp_path(buf_len, buffer); + const bool ret = !(buf_len < required_len); + if(ret && buffer[required_len-1] == '\\'){ + buffer[required_len-1] = 0; + } + return ret; +} + +inline file_handle_t create_new_file + (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) +{ + unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; + return winapi::create_file + ( name, (unsigned int)mode, winapi::create_new, attr + , (winapi::interprocess_security_attributes*)perm.get_permissions()); +} + +inline file_handle_t create_or_open_file + (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) +{ + unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; + return winapi::create_file + ( name, (unsigned int)mode, winapi::open_always, attr + , (winapi::interprocess_security_attributes*)perm.get_permissions()); +} + +inline file_handle_t open_existing_file + (const char *name, mode_t mode, bool temporary = false) +{ + unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; + return winapi::create_file + (name, (unsigned int)mode, winapi::open_existing, attr, 0); +} + +inline bool delete_file(const char *name) +{ return winapi::unlink_file(name); } + +inline bool truncate_file (file_handle_t hnd, std::size_t size) +{ + offset_t filesize; + if(!winapi::get_file_size(hnd, filesize)) + return false; + + typedef ::boost::move_detail::make_unsigned::type uoffset_t; + const uoffset_t max_filesize = uoffset_t((std::numeric_limits::max)()); + const uoffset_t uoff_size = uoffset_t(size); + //Avoid unused variable warnings in 32 bit systems + if(uoff_size > max_filesize){ + winapi::set_last_error(winapi::error_file_too_large); + return false; + } + + if(offset_t(size) > filesize){ + if(!winapi::set_file_pointer_ex(hnd, filesize, 0, winapi::file_begin)){ + return false; + } + //We will write zeros in the end of the file + //since set_end_of_file does not guarantee this + for(std::size_t remaining = size - filesize, write_size = 0 + ;remaining > 0 + ;remaining -= write_size){ + const std::size_t DataSize = 512; + static char data [DataSize]; + write_size = DataSize < remaining ? DataSize : remaining; + unsigned long written; + winapi::write_file(hnd, data, (unsigned long)write_size, &written, 0); + if(written != write_size){ + return false; + } + } + } + else{ + if(!winapi::set_file_pointer_ex(hnd, size, 0, winapi::file_begin)){ + return false; + } + if(!winapi::set_end_of_file(hnd)){ + return false; + } + } + return true; +} + +inline bool get_file_size(file_handle_t hnd, offset_t &size) +{ return winapi::get_file_size(hnd, size); } + +inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos) +{ return winapi::set_file_pointer_ex(hnd, off, 0, (unsigned long) pos); } + +inline bool get_file_pointer(file_handle_t hnd, offset_t &off) +{ return winapi::set_file_pointer_ex(hnd, 0, &off, winapi::file_current); } + +inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata) +{ + unsigned long written; + return 0 != winapi::write_file(hnd, data, (unsigned long)numdata, &written, 0); +} + +inline file_handle_t invalid_file() +{ return winapi::invalid_handle_value; } + +inline bool close_file(file_handle_t hnd) +{ return 0 != winapi::close_handle(hnd); } + +inline bool acquire_file_lock(file_handle_t hnd) +{ + static winapi::interprocess_overlapped overlapped; + const unsigned long len = ((unsigned long)-1); +// winapi::interprocess_overlapped overlapped; +// std::memset(&overlapped, 0, sizeof(overlapped)); + return winapi::lock_file_ex + (hnd, winapi::lockfile_exclusive_lock, 0, len, len, &overlapped); +} + +inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired) +{ + const unsigned long len = ((unsigned long)-1); + winapi::interprocess_overlapped overlapped; + std::memset(&overlapped, 0, sizeof(overlapped)); + if(!winapi::lock_file_ex + (hnd, winapi::lockfile_exclusive_lock | winapi::lockfile_fail_immediately, + 0, len, len, &overlapped)){ + return winapi::get_last_error() == winapi::error_lock_violation ? + acquired = false, true : false; + + } + return (acquired = true); +} + +inline bool release_file_lock(file_handle_t hnd) +{ + const unsigned long len = ((unsigned long)-1); + winapi::interprocess_overlapped overlapped; + std::memset(&overlapped, 0, sizeof(overlapped)); + return winapi::unlock_file_ex(hnd, 0, len, len, &overlapped); +} + +inline bool acquire_file_lock_sharable(file_handle_t hnd) +{ + const unsigned long len = ((unsigned long)-1); + winapi::interprocess_overlapped overlapped; + std::memset(&overlapped, 0, sizeof(overlapped)); + return winapi::lock_file_ex(hnd, 0, 0, len, len, &overlapped); +} + +inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) +{ + const unsigned long len = ((unsigned long)-1); + winapi::interprocess_overlapped overlapped; + std::memset(&overlapped, 0, sizeof(overlapped)); + if(!winapi::lock_file_ex + (hnd, winapi::lockfile_fail_immediately, 0, len, len, &overlapped)){ + return winapi::get_last_error() == winapi::error_lock_violation ? + acquired = false, true : false; + } + return (acquired = true); +} + +inline bool release_file_lock_sharable(file_handle_t hnd) +{ return release_file_lock(hnd); } + +inline bool delete_subdirectories_recursive + (const std::string &refcstrRootDirectory, const char *dont_delete_this, unsigned int count) +{ + bool bSubdirectory = false; // Flag, indicating whether + // subdirectories have been found + void * hFile; // Handle to directory + std::string strFilePath; // Filepath + std::string strPattern; // Pattern + winapi::win32_find_data FileInformation; // File information + + //Find all files and directories + strPattern = refcstrRootDirectory + "\\*.*"; + hFile = winapi::find_first_file(strPattern.c_str(), &FileInformation); + if(hFile != winapi::invalid_handle_value){ + do{ + //If it's not "." or ".." or the pointed root_level dont_delete_this erase it + if(FileInformation.cFileName[0] != '.' && + !(dont_delete_this && count == 0 && std::strcmp(dont_delete_this, FileInformation.cFileName) == 0)){ + strFilePath.erase(); + strFilePath = refcstrRootDirectory + "\\" + FileInformation.cFileName; + + //If it's a directory, go recursive + if(FileInformation.dwFileAttributes & winapi::file_attribute_directory){ + // Delete subdirectory + if(!delete_subdirectories_recursive(strFilePath, dont_delete_this, count+1)){ + winapi::find_close(hFile); + return false; + } + } + //If it's a file, just delete it + else{ + // Set file attributes + //if(::SetFileAttributes(strFilePath.c_str(), winapi::file_attribute_normal) == 0) + //return winapi::get_last_error(); + // Delete file + winapi::unlink_file(strFilePath.c_str()); + } + } + //Go to the next file + } while(winapi::find_next_file(hFile, &FileInformation) == 1); + + // Close handle + winapi::find_close(hFile); + + //See if the loop has ended with an error or just because we've traversed all the files + if(winapi::get_last_error() != winapi::error_no_more_files){ + return false; + } + else + { + //Erase empty subdirectories or original refcstrRootDirectory + if(!bSubdirectory && count) + { + // Set directory attributes + //if(::SetFileAttributes(refcstrRootDirectory.c_str(), FILE_ATTRIBUTE_NORMAL) == 0) + //return ::GetLastError(); + // Delete directory + if(winapi::remove_directory(refcstrRootDirectory.c_str()) == 0) + return false; + } + } + } + return true; +} + +//This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this" +inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this) +{ + return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this, 0u); +} + + +template +inline bool for_each_file_in_dir(const char *dir, Function f) +{ + void * hFile; // Handle to directory + winapi::win32_find_data FileInformation; // File information + + //Get base directory + std::string str(dir); + const std::size_t base_root_dir_len = str.size(); + + //Find all files and directories + str += "\\*.*"; + hFile = winapi::find_first_file(str.c_str(), &FileInformation); + if(hFile != winapi::invalid_handle_value){ + do{ //Now loop every file + str.erase(base_root_dir_len); + //If it's not "." or ".." skip it + if(FileInformation.cFileName[0] != '.'){ + str += "\\"; str += FileInformation.cFileName; + //If it's a file, apply erase logic + if(!(FileInformation.dwFileAttributes & winapi::file_attribute_directory)){ + f(str.c_str(), FileInformation.cFileName); + } + } + //Go to the next file + } while(winapi::find_next_file(hFile, &FileInformation) == 1); + + // Close handle and see if the loop has ended with an error + winapi::find_close(hFile); + if(winapi::get_last_error() != winapi::error_no_more_files){ + return false; + } + } + return true; +} + + +#else //#if defined (BOOST_INTERPROCESS_WINDOWS) + +typedef int file_handle_t; +typedef off_t offset_t; + +typedef struct mapping_handle_impl_t +{ + file_handle_t handle; + bool is_xsi; +} mapping_handle_t; + +typedef enum { read_only = O_RDONLY + , read_write = O_RDWR + , copy_on_write + , read_private + , invalid_mode = 0xffff + } mode_t; + +typedef enum { file_begin = SEEK_SET + , file_end = SEEK_END + , file_current = SEEK_CUR + } file_pos_t; + +typedef int map_options_t; +static const map_options_t default_map_options = map_options_t(-1); + +namespace ipcdetail{ + +inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd) +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_xsi = false; + return ret; +} + +inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) +{ return hnd.handle; } + +inline bool create_directory(const char *path) +{ return ::mkdir(path, 0777) == 0 && ::chmod(path, 0777) == 0; } + +inline bool get_temporary_path(char *buffer, std::size_t buf_len, std::size_t &required_len) +{ + required_len = 5u; + if(buf_len < required_len) + return false; + else{ + std::strcpy(buffer, "/tmp"); + } + return true; +} + +inline file_handle_t create_new_file + (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) +{ + (void)temporary; + int ret = ::open(name, ((int)mode) | O_EXCL | O_CREAT, perm.get_permissions()); + if(ret >= 0){ + ::fchmod(ret, perm.get_permissions()); + } + return ret; +} + +inline file_handle_t create_or_open_file + (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) +{ + (void)temporary; + int ret = -1; + //We need a loop to change permissions correctly using fchmod, since + //with "O_CREAT only" ::open we don't know if we've created or opened the file. + while(1){ + ret = ::open(name, ((int)mode) | O_EXCL | O_CREAT, perm.get_permissions()); + if(ret >= 0){ + ::fchmod(ret, perm.get_permissions()); + break; + } + else if(errno == EEXIST){ + if((ret = ::open(name, (int)mode)) >= 0 || errno != ENOENT){ + break; + } + } + else{ + break; + } + } + return ret; +} + +inline file_handle_t open_existing_file + (const char *name, mode_t mode, bool temporary = false) +{ + (void)temporary; + return ::open(name, (int)mode); +} + +inline bool delete_file(const char *name) +{ return ::unlink(name) == 0; } + +inline bool truncate_file (file_handle_t hnd, std::size_t size) +{ + typedef boost::move_detail::make_unsigned::type uoff_t; + if(uoff_t((std::numeric_limits::max)()) < size){ + errno = EINVAL; + return false; + } + return 0 == ::ftruncate(hnd, off_t(size)); +} + +inline bool get_file_size(file_handle_t hnd, offset_t &size) +{ + struct stat data; + bool ret = 0 == ::fstat(hnd, &data); + if(ret){ + size = data.st_size; + } + return ret; +} + +inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos) +{ return ((off_t)(-1)) != ::lseek(hnd, off, (int)pos); } + +inline bool get_file_pointer(file_handle_t hnd, offset_t &off) +{ + off = ::lseek(hnd, 0, SEEK_CUR); + return off != ((off_t)-1); +} + +inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata) +{ return (ssize_t(numdata)) == ::write(hnd, data, numdata); } + +inline file_handle_t invalid_file() +{ return -1; } + +inline bool close_file(file_handle_t hnd) +{ return ::close(hnd) == 0; } + +inline bool acquire_file_lock(file_handle_t hnd) +{ + struct ::flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + return -1 != ::fcntl(hnd, F_SETLKW, &lock); +} + +inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired) +{ + struct ::flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + int ret = ::fcntl(hnd, F_SETLK, &lock); + if(ret == -1){ + return (errno == EAGAIN || errno == EACCES) ? + acquired = false, true : false; + } + return (acquired = true); +} + +inline bool release_file_lock(file_handle_t hnd) +{ + struct ::flock lock; + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + return -1 != ::fcntl(hnd, F_SETLK, &lock); +} + +inline bool acquire_file_lock_sharable(file_handle_t hnd) +{ + struct ::flock lock; + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + return -1 != ::fcntl(hnd, F_SETLKW, &lock); +} + +inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) +{ + struct flock lock; + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + int ret = ::fcntl(hnd, F_SETLK, &lock); + if(ret == -1){ + return (errno == EAGAIN || errno == EACCES) ? + acquired = false, true : false; + } + return (acquired = true); +} + +inline bool release_file_lock_sharable(file_handle_t hnd) +{ return release_file_lock(hnd); } + +#if 0 +inline bool acquire_file_lock(file_handle_t hnd) +{ return 0 == ::flock(hnd, LOCK_EX); } + +inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired) +{ + int ret = ::flock(hnd, LOCK_EX | LOCK_NB); + acquired = ret == 0; + return (acquired || errno == EWOULDBLOCK); +} + +inline bool release_file_lock(file_handle_t hnd) +{ return 0 == ::flock(hnd, LOCK_UN); } + +inline bool acquire_file_lock_sharable(file_handle_t hnd) +{ return 0 == ::flock(hnd, LOCK_SH); } + +inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) +{ + int ret = ::flock(hnd, LOCK_SH | LOCK_NB); + acquired = ret == 0; + return (acquired || errno == EWOULDBLOCK); +} + +inline bool release_file_lock_sharable(file_handle_t hnd) +{ return 0 == ::flock(hnd, LOCK_UN); } +#endif + +inline bool delete_subdirectories_recursive + (const std::string &refcstrRootDirectory, const char *dont_delete_this) +{ + DIR *d = opendir(refcstrRootDirectory.c_str()); + if(!d) { + return false; + } + + struct dir_close + { + DIR *d_; + dir_close(DIR *d) : d_(d) {} + ~dir_close() { ::closedir(d_); } + } dc(d); (void)dc; + + struct ::dirent *de; + struct ::stat st; + std::string fn; + + while((de=::readdir(d))) { + if( de->d_name[0] == '.' && ( de->d_name[1] == '\0' + || (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){ + continue; + } + if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){ + continue; + } + fn = refcstrRootDirectory; + fn += '/'; + fn += de->d_name; + + if(std::remove(fn.c_str())) { + if(::stat(fn.c_str(), & st)) { + return false; + } + if(S_ISDIR(st.st_mode)) { + if(!delete_subdirectories_recursive(fn, 0) ){ + return false; + } + } else { + return false; + } + } + } + return std::remove(refcstrRootDirectory.c_str()) ? false : true; +} + +template +inline bool for_each_file_in_dir(const char *dir, Function f) +{ + std::string refcstrRootDirectory(dir); + + DIR *d = opendir(refcstrRootDirectory.c_str()); + if(!d) { + return false; + } + + struct dir_close + { + DIR *d_; + dir_close(DIR *d) : d_(d) {} + ~dir_close() { ::closedir(d_); } + } dc(d); (void)dc; + + struct ::dirent *de; + struct ::stat st; + std::string fn; + + while((de=::readdir(d))) { + if( de->d_name[0] == '.' && ( de->d_name[1] == '\0' + || (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){ + continue; + } + fn = refcstrRootDirectory; + fn += '/'; + fn += de->d_name; + + if(::stat(fn.c_str(), & st)) { + return false; + } + //If it's a file, apply erase logic + if(!S_ISDIR(st.st_mode)) { + f(fn.c_str(), de->d_name); + } + } + return true; +} + + +//This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this" +inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this) +{ + return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this ); +} + +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) + +inline bool open_or_create_directory(const char *dir_name) +{ + //If fails, check that it's because it already exists + if(!create_directory(dir_name)){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + return false; + } + } + return true; +} + +inline std::string get_temporary_path() +{ + std::size_t required_len = 0; + get_temporary_path(0, 0, required_len); + std::string ret_str(required_len, char(0)); + get_temporary_path(&ret_str[0], ret_str.size(), required_len); + while(!ret_str.empty() && !ret_str[ret_str.size()-1]){ + ret_str.erase(ret_str.size()-1); + } + + return ret_str; +} + +} //namespace ipcdetail{ +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP diff --git a/libraries/boost/boost/interprocess/detail/os_thread_functions.hpp b/libraries/boost/boost/interprocess/detail/os_thread_functions.hpp new file mode 100644 index 000000000..3ff0a402b --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/os_thread_functions.hpp @@ -0,0 +1,617 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//Thread launching functions are adapted from boost/detail/lightweight_thread.hpp +// +// boost/detail/lightweight_thread.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_WINDOWS) +# include +# include +#else +# include +# include +# include +# include +# ifdef BOOST_INTERPROCESS_BSD_DERIVATIVE + //Some *BSD systems (OpenBSD & NetBSD) need sys/param.h before sys/sysctl.h, whereas + //others (FreeBSD & Darwin) need sys/types.h +# include +# include +# include +# endif +//According to the article "C/C++ tip: How to measure elapsed real time for benchmarking" +# if defined(CLOCK_MONOTONIC_PRECISE) //BSD +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_PRECISE +# elif defined(CLOCK_MONOTONIC_RAW) //Linux +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW +# elif defined(CLOCK_HIGHRES) //Solaris +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_HIGHRES +# elif defined(CLOCK_MONOTONIC) //POSIX (AIX, BSD, Linux, Solaris) +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC +# elif !defined(CLOCK_MONOTONIC) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) +# include // mach_absolute_time, mach_timebase_info_data_t +# define BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME +# else +# error "No high resolution steady clock in your system, please provide a patch" +# endif +#endif + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +#if defined (BOOST_INTERPROCESS_WINDOWS) + +typedef unsigned long OS_process_id_t; +typedef unsigned long OS_thread_id_t; +struct OS_thread_t +{ + OS_thread_t() + : m_handle() + {} + + + void* handle() const + { return m_handle; } + + void* m_handle; +}; + +typedef OS_thread_id_t OS_systemwide_thread_id_t; + +//process +inline OS_process_id_t get_current_process_id() +{ return winapi::get_current_process_id(); } + +inline OS_process_id_t get_invalid_process_id() +{ return OS_process_id_t(0); } + +//thread +inline OS_thread_id_t get_current_thread_id() +{ return winapi::get_current_thread_id(); } + +inline OS_thread_id_t get_invalid_thread_id() +{ return OS_thread_id_t(0xffffffff); } + +inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) +{ return id1 == id2; } + +//return the system tick in ns +inline unsigned long get_system_tick_ns() +{ + unsigned long curres; + winapi::set_timer_resolution(10000, 0, &curres); + //Windows API returns the value in hundreds of ns + return (curres - 1ul)*100ul; +} + +//return the system tick in us +inline unsigned long get_system_tick_us() +{ + unsigned long curres; + winapi::set_timer_resolution(10000, 0, &curres); + //Windows API returns the value in hundreds of ns + return (curres - 1ul)/10ul + 1ul; +} + +typedef unsigned __int64 OS_highres_count_t; + +inline unsigned long get_system_tick_in_highres_counts() +{ + __int64 freq; + unsigned long curres; + winapi::set_timer_resolution(10000, 0, &curres); + //Frequency in counts per second + if(!winapi::query_performance_frequency(&freq)){ + //Tick resolution in ms + return (curres-1ul)/10000ul + 1ul; + } + else{ + //In femtoseconds + __int64 count_fs = (1000000000000000LL - 1LL)/freq + 1LL; + __int64 tick_counts = (static_cast<__int64>(curres)*100000000LL - 1LL)/count_fs + 1LL; + return static_cast(tick_counts); + } +} + +inline OS_highres_count_t get_current_system_highres_count() +{ + __int64 count; + if(!winapi::query_performance_counter(&count)){ + count = winapi::get_tick_count(); + } + return count; +} + +inline void zero_highres_count(OS_highres_count_t &count) +{ count = 0; } + +inline bool is_highres_count_zero(const OS_highres_count_t &count) +{ return count == 0; } + +template +inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) +{ + ostream << count; + return ostream; +} + +inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l - r; } + +inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l < r; } + +inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r) +{ return l < static_cast(r); } + +inline void thread_sleep_tick() +{ winapi::sleep_tick(); } + +inline void thread_yield() +{ winapi::sched_yield(); } + +inline void thread_sleep(unsigned int ms) +{ winapi::sleep(ms); } + +//systemwide thread +inline OS_systemwide_thread_id_t get_current_systemwide_thread_id() +{ + return get_current_thread_id(); +} + +inline void systemwide_thread_id_copy + (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) +{ + to = from; +} + +inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2) +{ + return equal_thread_id(id1, id2); +} + +inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() +{ + return get_invalid_thread_id(); +} + +inline long double get_current_process_creation_time() +{ + winapi::interprocess_filetime CreationTime, ExitTime, KernelTime, UserTime; + + winapi::get_process_times + ( winapi::get_current_process(), &CreationTime, &ExitTime, &KernelTime, &UserTime); + + typedef long double ldouble_t; + const ldouble_t resolution = (100.0l/1000000000.0l); + return CreationTime.dwHighDateTime*(ldouble_t(1u<<31u)*2.0l*resolution) + + CreationTime.dwLowDateTime*resolution; +} + +inline unsigned int get_num_cores() +{ + winapi::system_info sysinfo; + winapi::get_system_info( &sysinfo ); + //in Windows dw is long which is equal in bits to int + return static_cast(sysinfo.dwNumberOfProcessors); +} + +#else //#if defined (BOOST_INTERPROCESS_WINDOWS) + +typedef pthread_t OS_thread_t; +typedef pthread_t OS_thread_id_t; +typedef pid_t OS_process_id_t; + +struct OS_systemwide_thread_id_t +{ + OS_systemwide_thread_id_t() + : pid(), tid() + {} + + OS_systemwide_thread_id_t(pid_t p, pthread_t t) + : pid(p), tid(t) + {} + + OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x) + : pid(x.pid), tid(x.tid) + {} + + OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x) + : pid(x.pid), tid(x.tid) + {} + + OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x) + { pid = x.pid; tid = x.tid; return *this; } + + OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x) + { pid = x.pid; tid = x.tid; return *this; } + + void operator=(const OS_systemwide_thread_id_t &x) volatile + { pid = x.pid; tid = x.tid; } + + pid_t pid; + pthread_t tid; +}; + +inline void systemwide_thread_id_copy + (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) +{ + to.pid = from.pid; + to.tid = from.tid; +} + +//process +inline OS_process_id_t get_current_process_id() +{ return ::getpid(); } + +inline OS_process_id_t get_invalid_process_id() +{ return pid_t(0); } + +//thread +inline OS_thread_id_t get_current_thread_id() +{ return ::pthread_self(); } + +inline OS_thread_id_t get_invalid_thread_id() +{ + static pthread_t invalid_id; + return invalid_id; +} + +inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) +{ return 0 != pthread_equal(id1, id2); } + +inline void thread_yield() +{ ::sched_yield(); } + +#ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME +typedef struct timespec OS_highres_count_t; +#else +typedef unsigned long long OS_highres_count_t; +#endif + +inline unsigned long get_system_tick_ns() +{ + #ifdef _SC_CLK_TCK + long ticks_per_second =::sysconf(_SC_CLK_TCK); // ticks per sec + if(ticks_per_second <= 0){ //Try a typical value on error + ticks_per_second = 100; + } + return 999999999ul/static_cast(ticks_per_second)+1ul; + #else + #error "Can't obtain system tick value for your system, please provide a patch" + #endif +} + +inline unsigned long get_system_tick_in_highres_counts() +{ + #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME + return get_system_tick_ns(); + #else + mach_timebase_info_data_t info; + mach_timebase_info(&info); + //ns + return static_cast + ( + static_cast(get_system_tick_ns()) + / (static_cast(info.numer) / info.denom) + ); + #endif +} + +//return system ticks in us +inline unsigned long get_system_tick_us() +{ + return (get_system_tick_ns()-1)/1000ul + 1ul; +} + +inline OS_highres_count_t get_current_system_highres_count() +{ + #if defined(BOOST_INTERPROCESS_CLOCK_MONOTONIC) + struct timespec count; + ::clock_gettime(BOOST_INTERPROCESS_CLOCK_MONOTONIC, &count); + return count; + #elif defined(BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME) + return ::mach_absolute_time(); + #endif +} + +#ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME + +inline void zero_highres_count(OS_highres_count_t &count) +{ count.tv_sec = 0; count.tv_nsec = 0; } + +inline bool is_highres_count_zero(const OS_highres_count_t &count) +{ return count.tv_sec == 0 && count.tv_nsec == 0; } + +template +inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) +{ + ostream << count.tv_sec << "s:" << count.tv_nsec << "ns"; + return ostream; +} + +inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ + OS_highres_count_t res; + + if (l.tv_nsec < r.tv_nsec){ + res.tv_nsec = 1000000000 + l.tv_nsec - r.tv_nsec; + res.tv_sec = l.tv_sec - 1 - r.tv_sec; + } + else{ + res.tv_nsec = l.tv_nsec - r.tv_nsec; + res.tv_sec = l.tv_sec - r.tv_sec; + } + + return res; +} + +inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l.tv_sec < r.tv_sec || (l.tv_sec == r.tv_sec && l.tv_nsec < r.tv_nsec); } + +inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r) +{ return !l.tv_sec && (static_cast(l.tv_nsec) < r); } + +#else + +inline void zero_highres_count(OS_highres_count_t &count) +{ count = 0; } + +inline bool is_highres_count_zero(const OS_highres_count_t &count) +{ return count == 0; } + +template +inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) +{ + ostream << count ; + return ostream; +} + +inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l - r; } + +inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l < r; } + +inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r) +{ return l < static_cast(r); } + +#endif + +inline void thread_sleep_tick() +{ + struct timespec rqt; + //Sleep for the half of the tick time + rqt.tv_sec = 0; + rqt.tv_nsec = get_system_tick_ns()/2; + ::nanosleep(&rqt, 0); +} + +inline void thread_sleep(unsigned int ms) +{ + struct timespec rqt; + rqt.tv_sec = ms/1000u; + rqt.tv_nsec = (ms%1000u)*1000000u; + ::nanosleep(&rqt, 0); +} + +//systemwide thread +inline OS_systemwide_thread_id_t get_current_systemwide_thread_id() +{ + return OS_systemwide_thread_id_t(::getpid(), ::pthread_self()); +} + +inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2) +{ + return (0 != pthread_equal(id1.tid, id2.tid)) && (id1.pid == id2.pid); +} + +inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() +{ + return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id()); +} + +inline long double get_current_process_creation_time() +{ return 0.0L; } + +inline unsigned int get_num_cores() +{ + #ifdef _SC_NPROCESSORS_ONLN + long cores = ::sysconf(_SC_NPROCESSORS_ONLN); + // sysconf returns -1 if the name is invalid, the option does not exist or + // does not have a definite limit. + // if sysconf returns some other negative number, we have no idea + // what is going on. Default to something safe. + if(cores <= 0){ + return 1; + } + //Check for overflow (unlikely) + else if(static_cast(cores) >= + static_cast(static_cast(-1))){ + return static_cast(-1); + } + else{ + return static_cast(cores); + } + #elif defined(BOOST_INTERPROCESS_BSD_DERIVATIVE) && defined(HW_NCPU) + int request[2] = { CTL_HW, HW_NCPU }; + int num_cores; + std::size_t result_len = sizeof(num_cores); + if ( (::sysctl (request, 2, &num_cores, &result_len, 0, 0) < 0) || (num_cores <= 0) ){ + //Return a safe value + return 1; + } + else{ + return static_cast(num_cores); + } + #endif +} + +inline int thread_create(OS_thread_t * thread, void *(*start_routine)(void*), void* arg) +{ return pthread_create(thread, 0, start_routine, arg); } + +inline void thread_join(OS_thread_t thread) +{ (void)pthread_join(thread, 0); } + +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) + +typedef char pid_str_t[sizeof(OS_process_id_t)*3+1]; + +inline void get_pid_str(pid_str_t &pid_str, OS_process_id_t pid) +{ + bufferstream bstream(pid_str, sizeof(pid_str)); + bstream << pid << std::ends; +} + +inline void get_pid_str(pid_str_t &pid_str) +{ get_pid_str(pid_str, get_current_process_id()); } + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +inline int thread_create( OS_thread_t * thread, unsigned (__stdcall * start_routine) (void*), void* arg ) +{ + void* h = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 ); + + if( h != 0 ){ + thread->m_handle = h; + return 0; + } + else{ + return 1; + } + + thread->m_handle = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 ); + return thread->m_handle != 0; +} + +inline void thread_join( OS_thread_t thread) +{ + winapi::wait_for_single_object( thread.handle(), winapi::infinite_time ); + winapi::close_handle( thread.handle() ); +} + +#endif + +class abstract_thread +{ + public: + virtual ~abstract_thread() {} + virtual void run() = 0; +}; + +template +class os_thread_func_ptr_deleter +{ + public: + explicit os_thread_func_ptr_deleter(T* p) + : m_p(p) + {} + + T *release() + { T *p = m_p; m_p = 0; return p; } + + T *get() const + { return m_p; } + + T *operator ->() const + { return m_p; } + + ~os_thread_func_ptr_deleter() + { delete m_p; } + + private: + T *m_p; +}; + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +inline unsigned __stdcall launch_thread_routine( void * pv ) +{ + os_thread_func_ptr_deleter pt( static_cast( pv ) ); + pt->run(); + return 0; +} + +#else + +extern "C" void * launch_thread_routine( void * pv ); + +inline void * launch_thread_routine( void * pv ) +{ + os_thread_func_ptr_deleter pt( static_cast( pv ) ); + pt->run(); + return 0; +} + +#endif + +template +class launch_thread_impl + : public abstract_thread +{ + public: + explicit launch_thread_impl( F f ) + : f_( f ) + {} + + void run() + { f_(); } + + private: + F f_; +}; + +template +inline int thread_launch( OS_thread_t & pt, F f ) +{ + os_thread_func_ptr_deleter p( new launch_thread_impl( f ) ); + + int r = thread_create(&pt, launch_thread_routine, p.get()); + if( r == 0 ){ + p.release(); + } + + return r; +} + +} //namespace ipcdetail{ +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP diff --git a/libraries/boost/boost/interprocess/detail/pointer_type.hpp b/libraries/boost/boost/interprocess/detail/pointer_type.hpp new file mode 100644 index 000000000..125858653 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/pointer_type.hpp @@ -0,0 +1,78 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP +#define BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# 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/libraries/boost/boost/interprocess/detail/portable_intermodule_singleton.hpp b/libraries/boost/boost/interprocess/detail/portable_intermodule_singleton.hpp new file mode 100644 index 000000000..43df34c73 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/portable_intermodule_singleton.hpp @@ -0,0 +1,361 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP +#define BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +typedef basic_managed_global_memory managed_global_memory; + +namespace intermodule_singleton_helpers { + +static void create_tmp_subdir_and_get_pid_based_filepath + (const char *subdir_name, const char *file_prefix, OS_process_id_t pid, std::string &s, bool creation_time = false) +{ + //Let's create a lock file for each process gmem that will mark if + //the process is alive or not + create_shared_dir_and_clean_old(s); + s += "/"; + s += subdir_name; + if(!open_or_create_directory(s.c_str())){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + s += "/"; + s += file_prefix; + if(creation_time){ + std::string sstamp; + get_pid_creation_time_str(sstamp); + s += sstamp; + } + else{ + pid_str_t pid_str; + get_pid_str(pid_str, pid); + s += pid_str; + } +} + +static bool check_if_filename_complies_with_pid + (const char *filename, const char *prefix, OS_process_id_t pid, std::string &file_suffix, bool creation_time = false) +{ + //Check if filename complies with lock file name pattern + std::string fname(filename); + std::string fprefix(prefix); + if(fname.size() <= fprefix.size()){ + return false; + } + fname.resize(fprefix.size()); + if(fname != fprefix){ + return false; + } + + //If not our lock file, delete it if we can lock it + fname = filename; + fname.erase(0, fprefix.size()); + pid_str_t pid_str; + get_pid_str(pid_str, pid); + file_suffix = pid_str; + if(creation_time){ + std::size_t p = fname.find('_'); + if (p == std::string::npos){ + return false; + } + std::string save_suffix(fname); + fname.erase(p); + fname.swap(file_suffix); + bool ret = (file_suffix == fname); + file_suffix.swap(save_suffix); + return ret; + } + else{ + fname.swap(file_suffix); + return (file_suffix == fname); + } +} + +template<> +struct thread_safe_global_map_dependant +{ + private: + static const int GMemMarkToBeRemoved = -1; + static const int GMemNotPresent = -2; + + static const char *get_lock_file_subdir_name() + { return "gmem"; } + + static const char *get_lock_file_base_name() + { return "lck"; } + + static void create_and_get_singleton_lock_file_path(std::string &s) + { + create_tmp_subdir_and_get_pid_based_filepath + (get_lock_file_subdir_name(), get_lock_file_base_name(), get_current_process_id(), s, true); + } + + struct gmem_erase_func + { + gmem_erase_func(const char *shm_name, const char *singleton_lock_file_path, managed_global_memory & shm) + :shm_name_(shm_name), singleton_lock_file_path_(singleton_lock_file_path), shm_(shm) + {} + + void operator()() + { + locking_file_serial_id *pserial_id = shm_.find("lock_file_fd").first; + if(pserial_id){ + pserial_id->fd = GMemMarkToBeRemoved; + } + delete_file(singleton_lock_file_path_); + shared_memory_object::remove(shm_name_); + } + + const char * const shm_name_; + const char * const singleton_lock_file_path_; + managed_global_memory & shm_; + }; + + //This function applies shared memory erasure logic based on the passed lock file. + static void apply_gmem_erase_logic(const char *filepath, const char *filename) + { + int fd = GMemMarkToBeRemoved; + try{ + std::string str; + //If the filename is current process lock file, then avoid it + if(check_if_filename_complies_with_pid + (filename, get_lock_file_base_name(), get_current_process_id(), str, true)){ + return; + } + //Open and lock the other process' lock file + fd = try_open_and_lock_file(filepath); + if(fd < 0){ + return; + } + //If done, then the process is dead so take global shared memory name + //(the name is based on the lock file name) and try to apply erasure logic + str.insert(0, get_map_base_name()); + try{ + managed_global_memory shm(open_only, str.c_str()); + gmem_erase_func func(str.c_str(), filepath, shm); + shm.try_atomic_func(func); + } + catch(interprocess_exception &e){ + //If shared memory is not found erase the lock file + if(e.get_error_code() == not_found_error){ + delete_file(filepath); + } + } + } + catch(...){ + + } + if(fd >= 0){ + close_lock_file(fd); + } + } + + public: + + static bool remove_old_gmem() + { + std::string refcstrRootDirectory; + get_shared_dir(refcstrRootDirectory); + refcstrRootDirectory += "/"; + refcstrRootDirectory += get_lock_file_subdir_name(); + return for_each_file_in_dir(refcstrRootDirectory.c_str(), apply_gmem_erase_logic); + } + + struct lock_file_logic + { + lock_file_logic(managed_global_memory &shm) + : mshm(shm) + { shm.atomic_func(*this); } + + void operator()(void) + { + retry_with_new_map = false; + + //First find the file locking descriptor id + locking_file_serial_id *pserial_id = + mshm.find("lock_file_fd").first; + + int fd; + //If not found schedule a creation + if(!pserial_id){ + fd = GMemNotPresent; + } + //Else get it + else{ + fd = pserial_id->fd; + } + //If we need to create a new one, do it + if(fd == GMemNotPresent){ + std::string lck_str; + //Create a unique current pid based lock file path + create_and_get_singleton_lock_file_path(lck_str); + //Open or create and lock file + int fd_lockfile = open_or_create_and_lock_file(lck_str.c_str()); + //If failed, write a bad file descriptor to notify other modules that + //something was wrong and unlink shared memory. Mark the function object + //to tell caller to retry with another shared memory + if(fd_lockfile < 0){ + this->register_lock_file(GMemMarkToBeRemoved); + std::string s; + get_map_name(s); + shared_memory_object::remove(s.c_str()); + retry_with_new_map = true; + } + //If successful, register the file descriptor + else{ + this->register_lock_file(fd_lockfile); + } + } + //If the fd was invalid (maybe a previous try failed) notify caller that + //should retry creation logic, since this shm might have been already + //unlinked since the shm was removed + else if (fd == GMemMarkToBeRemoved){ + retry_with_new_map = true; + } + //If the stored fd is not valid (a open fd, a normal file with the + //expected size, or does not have the same file id number, + //then it's an old shm from an old process with the same pid. + //If that's the case, mark it as invalid + else if(!is_valid_fd(fd) || + !is_normal_file(fd) || + 0 != get_size(fd) || + !compare_file_serial(fd, *pserial_id)){ + pserial_id->fd = GMemMarkToBeRemoved; + std::string s; + get_map_name(s); + shared_memory_object::remove(s.c_str()); + retry_with_new_map = true; + } + else{ + //If the lock file is ok, increment reference count of + //attached modules to shared memory + atomic_inc32(&pserial_id->modules_attached_to_gmem_count); + } + } + + bool retry() const { return retry_with_new_map; } + + private: + locking_file_serial_id * register_lock_file(int fd) + { + locking_file_serial_id *pinfo = mshm.construct("lock_file_fd")(); + fill_file_serial_id(fd, *pinfo); + return pinfo; + } + + managed_global_memory &mshm; + bool retry_with_new_map; + }; + + static void construct_map(void *addr) + { + std::string s; + intermodule_singleton_helpers::get_map_name(s); + const char *MapName = s.c_str(); + const std::size_t MapSize = intermodule_singleton_helpers::get_map_size();; + ::new (addr)managed_global_memory(open_or_create, MapName, MapSize); + } + + struct unlink_map_logic + { + unlink_map_logic(managed_global_memory &mshm) + : mshm_(mshm) + { mshm.atomic_func(*this); } + + void operator()() + { + locking_file_serial_id *pserial_id = + mshm_.find + ("lock_file_fd").first; + BOOST_ASSERT(0 != pserial_id); + if(1 == atomic_dec32(&pserial_id->modules_attached_to_gmem_count)){ + int fd = pserial_id->fd; + if(fd > 0){ + pserial_id->fd = GMemMarkToBeRemoved; + std::string s; + create_and_get_singleton_lock_file_path(s); + delete_file(s.c_str()); + close_lock_file(fd); + intermodule_singleton_helpers::get_map_name(s); + shared_memory_object::remove(s.c_str()); + } + } + } + + private: + managed_global_memory &mshm_; + }; + + static ref_count_ptr *find(managed_global_memory &map, const char *name) + { + return map.find(name).first; + } + + static ref_count_ptr *insert(managed_global_memory &map, const char *name, const ref_count_ptr &ref) + { + return map.construct(name)(ref); + } + + static bool erase(managed_global_memory &map, const char *name) + { + return map.destroy(name); + } + + template + static void atomic_func(managed_global_memory &map, F &f) + { + map.atomic_func(f); + } +}; + +} //namespace intermodule_singleton_helpers { + +template +class portable_intermodule_singleton + : public intermodule_singleton_impl +{}; + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP diff --git a/libraries/boost/boost/interprocess/detail/posix_time_types_wrk.hpp b/libraries/boost/boost/interprocess/detail/posix_time_types_wrk.hpp new file mode 100644 index 000000000..5a12d83d7 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/posix_time_types_wrk.hpp @@ -0,0 +1,51 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP +#define BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +//workaround to avoid winsock redefines when using date-time + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#define BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN +#endif //#ifndef WIN32_LEAN_AND_MEAN +#endif //#ifdef _WIN32 + +#include +#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/libraries/boost/boost/interprocess/detail/ptime_wrk.hpp b/libraries/boost/boost/interprocess/detail/ptime_wrk.hpp new file mode 100644 index 000000000..ca58b7d40 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/ptime_wrk.hpp @@ -0,0 +1,41 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_PTIME_WRK_HPP +#define BOOST_INTERPROCESS_PTIME_WRK_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +//workaround to avoid winsock redefines when using date-time + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#define BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN +#endif //#ifndef WIN32_LEAN_AND_MEAN +#endif //#ifdef _WIN32 + +#include + +#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/libraries/boost/boost/interprocess/detail/robust_emulation.hpp b/libraries/boost/boost/interprocess/detail/robust_emulation.hpp new file mode 100644 index 000000000..d3e4fa619 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/robust_emulation.hpp @@ -0,0 +1,385 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2010-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_ROBUST_EMULATION_HPP +#define BOOST_INTERPROCESS_ROBUST_EMULATION_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#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) +{ + get_shared_dir(s); + s += "/"; + s += robust_lock_subdir_path(); +} + +inline void create_and_get_robust_lock_file_path(std::string &s, OS_process_id_t pid) +{ + intermodule_singleton_helpers::create_tmp_subdir_and_get_pid_based_filepath + (robust_lock_subdir_path(), robust_lock_prefix(), pid, s); +} + +//This class will be a intermodule_singleton. The constructor will create +//a lock file, the destructor will erase it. +// +//We should take in care that another process might be erasing unlocked +//files while creating this one, so there are some race conditions we must +//take in care to guarantee some robustness. +class robust_mutex_lock_file +{ + file_handle_t fd; + std::string fname; + public: + robust_mutex_lock_file() + { + permissions p; + p.set_unrestricted(); + //Remove old lock files of other processes + remove_old_robust_lock_files(); + //Create path and obtain lock file path for this process + create_and_get_robust_lock_file_path(fname, get_current_process_id()); + + //Now try to open or create the lock file + fd = create_or_open_file(fname.c_str(), read_write, p); + //If we can't open or create it, then something unrecoverable has happened + if(fd == invalid_file()){ + throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: could not open or create file"); + } + + //Now we must take in care a race condition with another process + //calling "remove_old_robust_lock_files()". No other threads from this + //process will be creating the lock file because intermodule_singleton + //guarantees this. So let's loop acquiring the lock and checking if we + //can't exclusively create the file (if the file is erased by another process + //then this exclusive open would fail). If the file can't be exclusively created + //then we have correctly open/create and lock the file. If the file can + //be exclusively created, then close previous locked file and try again. + while(1){ + bool acquired; + if(!try_acquire_file_lock(fd, acquired) || !acquired ){ + throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: try_acquire_file_lock"); + } + //Creating exclusively must fail with already_exists_error + //to make sure we've locked the file and no one has + //deleted it between creation and locking + file_handle_t fd2 = create_new_file(fname.c_str(), read_write, p); + if(fd2 != invalid_file()){ + close_file(fd); + fd = fd2; + continue; + } + //If exclusive creation fails with expected error go ahead + else if(error_info(system_error_code()).get_error_code() == already_exists_error){ //must already exist + //Leak descriptor to mantain the file locked until the process dies + break; + } + //If exclusive creation fails with unexpected error throw an unrecoverable error + else{ + close_file(fd); + throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: create_file filed with unexpected error"); + } + } + } + + ~robust_mutex_lock_file() + { + //The destructor is guaranteed by intermodule_singleton to be + //executed serialized between all threads from current process, + //so we just need to close and unlink the file. + close_file(fd); + //If some other process deletes the file before us after + //closing it there should not be any problem. + delete_file(fname.c_str()); + } + + private: + //This functor is execute for all files in the lock file directory + class other_process_lock_remover + { + public: + void operator()(const char *filepath, const char *filename) + { + std::string pid_str; + //If the lock file is not our own lock file, then try to do the cleanup + if(!intermodule_singleton_helpers::check_if_filename_complies_with_pid + (filename, robust_lock_prefix(), get_current_process_id(), pid_str)){ + remove_if_can_lock_file(filepath); + } + } + }; + + bool remove_old_robust_lock_files() + { + std::string refcstrRootDirectory; + robust_lock_path(refcstrRootDirectory); + return for_each_file_in_dir(refcstrRootDirectory.c_str(), other_process_lock_remover()); + } +}; + +} //namespace robust_emulation_helpers { + +//This is the mutex class. Mutex should follow mutex concept +//with an additonal "take_ownership()" function to take ownership of the +//mutex when robust_spin_mutex determines the previous owner was dead. +template +class 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 own); + void owner_to_filename(boost::uint32_t own, std::string &s); + //The real mutex + Mutex mtx; + //The pid of the owner + volatile boost::uint32_t owner; + //The state of the mutex (correct, fixing, broken) + volatile boost::uint32_t state; +}; + +template +inline robust_spin_mutex::robust_spin_mutex() + : mtx(), owner(get_invalid_process_id()), state(correct_state) +{} + +template +inline void robust_spin_mutex::lock() +{ try_based_lock(*this); } + +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) +{ return try_based_timed_lock(*this, abs_time); } + +template +inline void robust_spin_mutex::owner_to_filename(boost::uint32_t own, std::string &s) +{ + robust_emulation_helpers::create_and_get_robust_lock_file_path(s, own); +} + +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 own) +{ + //If owner is an invalid id, then it's clear it's dead + if(own == (boost::uint32_t)get_invalid_process_id()){ + return true; + } + + //Obtain the lock filename of the owner field + std::string file; + this->owner_to_filename(own, file); + + //Now the logic is to open and lock it + file_handle_t fhnd = open_existing_file(file.c_str(), read_write); + + if(fhnd != invalid_file()){ + //If we can open the file, lock it. + bool acquired; + if(try_acquire_file_lock(fhnd, acquired) && acquired){ + //If locked, just delete the file + delete_file(file.c_str()); + close_file(fhnd); + return true; + } + //If not locked, the owner is suppossed to be still alive + close_file(fhnd); + } + else{ + //If the lock file does not exist then the owner is dead (a previous cleanup) + //function has deleted the file. If there is another reason, then this is + //an unrecoverable error + if(error_info(system_error_code()).get_error_code() == not_found_error){ + return true; + } + } + return false; +} + +template +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/libraries/boost/boost/interprocess/detail/segment_manager_helper.hpp b/libraries/boost/boost/interprocess/detail/segment_manager_helper.hpp new file mode 100644 index 000000000..cfa4bd2ba --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/segment_manager_helper.hpp @@ -0,0 +1,518 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP +#define BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +// interprocess +#include +// interprocess/detail +#include +#include +#include +// container/detail +#include //alignment_of +#include +// intrusive +#include +// move/detail +#include //make_unsigned +// other boost +#include //BOOST_ASSERT +#include +// std +#include //std::size_t + +//!\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); } +}; + +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 val_bytes + ,size_type val_alignment + ,unsigned char al_type + ,std::size_t szof_char + ,std::size_t num_char + ) + : m_value_bytes(val_bytes) + , m_num_char((unsigned short)num_char) + , m_value_alignment((unsigned char)val_alignment) + , m_alloc_type_sizeof_char( (al_type << 5u) | ((unsigned char)szof_char & 0x1F) ) + {}; + + template + 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::container::container_detail::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::container::container_detail::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::container::container_detail::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::container::container_detail::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::container::container_detail::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; } + + const CharType *get() const + { return m_name; } + + bool is_unique() const + { return m_name == reinterpret_cast(-1); } + + bool is_anonymous() const + { return m_name == static_cast(0); } + + private: + const CharType *m_name; +}; + +//!The key of the the named allocation information index. Stores an offset pointer +//!to a null terminated string and the length of the string to speed up sorting +template +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::move_detail::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 *nm, size_type length) + : mp_str(nm), m_len(length) + {} + + //!Less than function for index ordering + bool operator < (const index_key & right) const + { + return (m_len < right.m_len) || + (m_len == right.m_len && + std::char_traits::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 *nm) + { mp_str = nm; } + + void name_length(size_type len) + { m_len = len; } + + const CharT *name() const + { return to_raw_pointer(mp_str); } + + size_type name_length() const + { return m_len; } +}; + +//!The index_data stores a pointer to a buffer and the element count needed +//!to know how many destructors must be called when calling destroy +template +struct index_data +{ + typedef VoidPointer void_pointer; + void_pointer m_ptr; + explicit index_data(void *ptr) : m_ptr(ptr){} + + void *value() const + { return static_cast(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 +{ + typedef segment_manager_iterator_value_adaptor result_type; + + template result_type operator()(const T &arg) const + { return result_type(arg); } +}; + +} //namespace ipcdetail { + +//These pointers are the ones the user will use to +//indicate previous allocation types +static const ipcdetail::anonymous_instance_t * anonymous_instance = 0; +static const ipcdetail::unique_instance_t * unique_instance = 0; + +namespace ipcdetail_really_deep_namespace { + +//Otherwise, gcc issues a warning of previously defined +//anonymous_instance and unique_instance +struct dummy +{ + dummy() + { + (void)anonymous_instance; + (void)unique_instance; + } +}; + +} //detail_really_deep_namespace + +}} //namespace boost { namespace interprocess + +#include + +#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP + diff --git a/libraries/boost/boost/interprocess/detail/shared_dir_helpers.hpp b/libraries/boost/boost/interprocess/detail/shared_dir_helpers.hpp new file mode 100644 index 000000000..a0ac766f4 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/shared_dir_helpers.hpp @@ -0,0 +1,199 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_SHARED_DIR_HELPERS_HPP +#define BOOST_INTERPROCESS_DETAIL_SHARED_DIR_HELPERS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) && defined(BOOST_INTERPROCESS_WINDOWS) + #include +#endif + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + #if defined(BOOST_INTERPROCESS_WINDOWS) + //This type will initialize the stamp + struct windows_bootstamp + { + windows_bootstamp() + { + //Throw if bootstamp not available + if(!winapi::get_last_bootup_time(stamp)){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + } + //Use std::string. Even if this will be constructed in shared memory, all + //modules/dlls are from this process so internal raw pointers to heap are always valid + std::string stamp; + }; + + inline void get_bootstamp(std::string &s, bool add = false) + { + const windows_bootstamp &bootstamp = windows_intermodule_singleton::get(); + if(add){ + s += bootstamp.stamp; + } + else{ + s = bootstamp.stamp; + } + } + #elif defined(BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME) + inline void get_bootstamp(std::string &s, bool add = false) + { + // FreeBSD specific: sysctl "kern.boottime" + int request[2] = { CTL_KERN, KERN_BOOTTIME }; + struct ::timeval result; + std::size_t result_len = sizeof result; + + if (::sysctl (request, 2, &result, &result_len, 0, 0) < 0) + return; + + char bootstamp_str[256]; + + const char Characters [] = + { '0', '1', '2', '3', '4', '5', '6', '7' + , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + std::size_t char_counter = 0; + //32 bit values to allow 32 and 64 bit process IPC + boost::uint32_t fields[2] = { boost::uint32_t(result.tv_sec), boost::uint32_t(result.tv_usec) }; + for(std::size_t field = 0; field != 2; ++field){ + for(std::size_t i = 0; i != sizeof(fields[0]); ++i){ + const char *ptr = (const char *)&fields[field]; + bootstamp_str[char_counter++] = Characters[(ptr[i]&0xF0)>>4]; + bootstamp_str[char_counter++] = Characters[(ptr[i]&0x0F)]; + } + } + bootstamp_str[char_counter] = 0; + if(add){ + s += bootstamp_str; + } + else{ + s = bootstamp_str; + } + } + #else + #error "BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME defined with no known implementation" + #endif +#endif //#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + +inline void get_shared_dir_root(std::string &dir_path) +{ + #if defined (BOOST_INTERPROCESS_WINDOWS) + winapi::get_shared_documents_folder(dir_path); + #else + dir_path = "/tmp"; + #endif + //We always need this path, so throw on error + if(dir_path.empty()){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + //Remove final null. + dir_path += "/boost_interprocess"; +} + +inline void get_shared_dir(std::string &shared_dir) +{ + #if defined(BOOST_INTERPROCESS_SHARED_DIR_PATH) + shared_dir = BOOST_INTERPROCESS_SHARED_DIR_PATH; + #else + get_shared_dir_root(shared_dir); + #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + shared_dir += "/"; + get_bootstamp(shared_dir, true); + #endif + #endif +} + +inline void shared_filepath(const char *filename, std::string &filepath) +{ + get_shared_dir(filepath); + filepath += "/"; + filepath += filename; +} + +inline void create_shared_dir_and_clean_old(std::string &shared_dir) +{ + #if defined(BOOST_INTERPROCESS_SHARED_DIR_PATH) + shared_dir = BOOST_INTERPROCESS_SHARED_DIR_PATH; + #else + //First get the temp directory + std::string root_shared_dir; + get_shared_dir_root(root_shared_dir); + + //If fails, check that it's because already exists + if(!create_directory(root_shared_dir.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } + } + + #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + get_shared_dir(shared_dir); + + //If fails, check that it's because already exists + if(!create_directory(shared_dir.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } + } + //Now erase all old directories created in the previous boot sessions + std::string subdir = shared_dir; + subdir.erase(0, root_shared_dir.size()+1); + delete_subdirectories(root_shared_dir, subdir.c_str()); + #else + shared_dir = root_shared_dir; + #endif + #endif +} + +inline void create_shared_dir_cleaning_old_and_get_filepath(const char *filename, std::string &shared_dir) +{ + create_shared_dir_and_clean_old(shared_dir); + shared_dir += "/"; + shared_dir += filename; +} + +inline void add_leading_slash(const char *name, std::string &new_name) +{ + if(name[0] != '/'){ + new_name = '/'; + } + new_name += name; +} + +} //namespace boost{ +} //namespace interprocess { +} //namespace ipcdetail { + +#include + +#endif //ifndef BOOST_INTERPROCESS_DETAIL_SHARED_DIR_HELPERS_HPP diff --git a/libraries/boost/boost/interprocess/detail/simple_swap.hpp b/libraries/boost/boost/interprocess/detail/simple_swap.hpp new file mode 100644 index 000000000..797a99707 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/simple_swap.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_INTERPROCESS_DETAIL_SWAP_HPP +#define BOOST_INTERPROCESS_DETAIL_SWAP_HPP +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +namespace boost { namespace interprocess { + +template +void simple_swap(T&x, T&y) +{ T tmp(x); x = y; y = tmp; } + +}} //namespace boost{ namespace interprocess { + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_SWAP_HPP diff --git a/libraries/boost/boost/interprocess/detail/std_fwd.hpp b/libraries/boost/boost/interprocess/detail/std_fwd.hpp new file mode 100644 index 000000000..282771c3e --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/std_fwd.hpp @@ -0,0 +1,57 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_DETAIL_STD_FWD_HPP +#define BOOST_INTERPROCESS_DETAIL_STD_FWD_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +////////////////////////////////////////////////////////////////////////////// +// Standard predeclarations +////////////////////////////////////////////////////////////////////////////// + +#include +BOOST_MOVE_STD_NS_BEG + +struct input_iterator_tag; +struct forward_iterator_tag; +struct bidirectional_iterator_tag; +struct random_access_iterator_tag; + +template +struct char_traits; + +#if defined(BOOST_MSVC) && (BOOST_MSVC >= 1800) &&defined(BOOST_DINKUMWARE_STDLIB) +#define BOOST_INTERPROCESS_STD_FWD_MSVC_IOS_BUG +// Compiler bug workaround. Previous versions (<= VC11) +// used dummy virtual functions +# pragma vtordisp(push, 2) +#endif + +template +class basic_ostream; + +template +class basic_istream; + +#ifdef BOOST_INTERPROCESS_STD_FWD_MSVC_IOS_BUG +# pragma vtordisp(pop) +# undef BOOST_INTERPROCESS_STD_FWD_MSVC_IOS_BUG +#endif + +BOOST_MOVE_STD_NS_END +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_STD_FWD_HPP diff --git a/libraries/boost/boost/interprocess/detail/transform_iterator.hpp b/libraries/boost/boost/interprocess/detail/transform_iterator.hpp new file mode 100644 index 000000000..1c4dcd3ae --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/transform_iterator.hpp @@ -0,0 +1,200 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2015. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP +#define BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +// interprocess +#include +// interprocess/detail +#include +// move/detail +#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: + typedef typename ::boost::container::iterator_traits::iterator_category iterator_category; + typedef typename ipcdetail::remove_reference::type value_type; + typedef typename ::boost::container::iterator_traits::difference_type difference_type; + typedef operator_arrow_proxy pointer; + typedef typename UnaryFunction::result_type reference; + + 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 difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + transform_iterator& operator+=(difference_type off) + { this->advance(off); return *this; } + + transform_iterator operator+(difference_type off) const + { + transform_iterator other(*this); + other.advance(off); + return other; + } + + friend transform_iterator operator+(difference_type off, const transform_iterator& right) + { return right + off; } + + transform_iterator& operator-=(difference_type off) + { this->advance(-off); return *this; } + + transform_iterator operator-(difference_type off) const + { return *this + (-off); } + + typename UnaryFunction::result_type operator*() const + { return dereference(); } + + typename UnaryFunction::result_type operator[](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(difference_type n) + { ::boost::container::iterator_advance(m_it, n); } + + difference_type distance_to(const transform_iterator &other)const + { return ::boost::container::iterator_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/libraries/boost/boost/interprocess/detail/type_traits.hpp b/libraries/boost/boost/interprocess/detail/type_traits.hpp new file mode 100644 index 000000000..5765c888e --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/type_traits.hpp @@ -0,0 +1,162 @@ +////////////////////////////////////////////////////////////////////////////// +// (C) Copyright John Maddock 2000. +// (C) Copyright Ion Gaztanaga 2005-2012. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP +#define BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# 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 remove_const_volatile +{ + typedef typename remove_const::type>::type 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)); +}; + +template +struct is_cv_same +{ + static const bool value = is_same< typename remove_const_volatile::type + , typename remove_const_volatile::type >::value; +}; + +} // namespace ipcdetail +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP diff --git a/libraries/boost/boost/interprocess/detail/utilities.hpp b/libraries/boost/boost/interprocess/detail/utilities.hpp new file mode 100644 index 000000000..e1be2f159 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/utilities.hpp @@ -0,0 +1,213 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2015. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP +#define BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#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->()); } + +//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 +{ + BOOST_STATIC_ASSERT((RoundTo != 0)); + static const std::size_t intermediate_value = (OrigSize-1)/RoundTo+1; + BOOST_STATIC_ASSERT(intermediate_value <= std::size_t(-1)/RoundTo); + static const std::size_t value = intermediate_value*RoundTo; +}; + +// Gennaro Prota wrote this. Thanks! +template +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 +BOOST_INTERPROCESS_FORCEINLINE T* addressof(T& v) +{ + return reinterpret_cast( + &const_cast(reinterpret_cast(v))); +} + +template +struct sqrt_size_type_max +{ + static const SizeType value = (SizeType(1) << (sizeof(SizeType)*(CHAR_BIT/2)))-1; +}; + +template +inline bool multiplication_overflows(SizeType a, SizeType b) +{ + const SizeType sqrt_size_max = sqrt_size_type_max::value; + return //Fast runtime check + ( (a | b) > sqrt_size_max && + //Slow division check + b && a > SizeType(-1)/b + ); +} + +template +BOOST_INTERPROCESS_FORCEINLINE bool size_overflows(SizeType count) +{ + //Compile time-check + BOOST_STATIC_ASSERT(SztSizeOfType <= SizeType(-1)); + //Runtime check + return multiplication_overflows(SizeType(SztSizeOfType), count); +} + +template +class pointer_uintptr_caster; + +template +class pointer_uintptr_caster +{ + public: + BOOST_INTERPROCESS_FORCEINLINE explicit pointer_uintptr_caster(uintptr_t sz) + : m_uintptr(sz) + {} + + BOOST_INTERPROCESS_FORCEINLINE explicit pointer_uintptr_caster(const volatile T *p) + : m_uintptr(reinterpret_cast(p)) + {} + + BOOST_INTERPROCESS_FORCEINLINE uintptr_t uintptr() const + { return m_uintptr; } + + BOOST_INTERPROCESS_FORCEINLINE T* pointer() const + { return reinterpret_cast(m_uintptr); } + + private: + uintptr_t m_uintptr; +}; + + +template +inline bool sum_overflows(SizeType a, SizeType b) +{ return SizeType(-1) - a < b; } + +//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); } + + BOOST_INTERPROCESS_FORCEINLINE void release() { m_erase = false; } + + private: + Cont &m_cont; + typename Cont::iterator m_index_it; + bool m_erase; +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP + diff --git a/libraries/boost/boost/interprocess/detail/variadic_templates_tools.hpp b/libraries/boost/boost/interprocess/detail/variadic_templates_tools.hpp new file mode 100644 index 000000000..c0f591312 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/variadic_templates_tools.hpp @@ -0,0 +1,35 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP +#define BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +using boost::container::container_detail::tuple; +using boost::container::container_detail::build_number_seq; +using boost::container::container_detail::index_tuple; +using boost::container::container_detail::get; + +}}} //namespace boost { namespace interprocess { namespace ipcdetail { + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP diff --git a/libraries/boost/boost/interprocess/detail/win32_api.hpp b/libraries/boost/boost/interprocess/detail/win32_api.hpp new file mode 100644 index 000000000..02c7b4270 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/win32_api.hpp @@ -0,0 +1,2349 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_WIN32_API_HPP +#define BOOST_INTERPROCESS_WIN32_API_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef BOOST_USE_WINDOWS_H +#include + +# if defined(BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME) +# include +# include +# endif + +#include +#endif + +#if defined(_MSC_VER) +# pragma once +# pragma comment( lib, "Advapi32.lib" ) +# pragma comment( lib, "oleaut32.lib" ) +# pragma comment( lib, "Ole32.lib" ) +# pragma comment( lib, "Shell32.lib" ) //SHGetFolderPath +#endif + +#if defined (BOOST_INTERPROCESS_WINDOWS) +# include +# include +#else +# error "This file can only be included in Windows OS" +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// Declaration of Windows structures or typedefs if BOOST_USE_WINDOWS_H is used +// +////////////////////////////////////////////////////////////////////////////// + +//Ignore -pedantic errors here (anonymous structs, etc.) +#if defined(BOOST_GCC) +# if (BOOST_GCC >= 40600) +# pragma GCC diagnostic push +# if (BOOST_GCC >= 60000) +# pragma GCC diagnostic ignored "-Wpedantic" +# else +# pragma GCC diagnostic ignored "-pedantic" +# endif +# else +# pragma GCC system_header +# endif +#endif + +namespace boost { +namespace interprocess { +namespace winapi { + +//Own defines +static const unsigned long MaxPath = 260; + +#ifndef BOOST_USE_WINDOWS_H + +struct GUID_BIPC +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +}; + +#if defined(_MSC_VER) +#pragma warning (push) +#pragma warning (disable : 4201) // nonstandard extension used +#endif + +struct decimal +{ + unsigned short wReserved; + union { + struct { + unsigned char scale; + unsigned char sign; + }; + unsigned short signscale; + }; + unsigned long Hi32; + union { + struct { + unsigned long Lo32; + unsigned long Mid32; + }; + ::boost::ulong_long_type Lo64; + }; +}; + +typedef unsigned short *bstr; + + +struct wchar_variant +{ + union + { + struct + { + unsigned short vt; + unsigned short wReserved1; + unsigned short wReserved2; + unsigned short wReserved3; + union + { + bstr bstrVal; + struct + { + void* pvRecord; + void* pRecInfo; + }; + }; + }; + decimal decVal; + }; +}; + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif + +struct IUnknown_BIPC +{ + public: + virtual long __stdcall QueryInterface( + const GUID_BIPC &riid, // [in] + void **ppvObject) = 0; // [iid_is][out] + + 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 bstr 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 bstr wszName, + /* [in] */ long lFlags, + /* [in] */ wchar_variant *pVal, + /* [in] */ long Type) = 0; + + virtual long __stdcall Delete( + /* [string][in] */ const bstr wszName) = 0; + + virtual long __stdcall GetNames( + /* [string][in] */ const bstr 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] */ bstr *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 bstr wszProperty, + /* [out] */ void **ppQualSet) = 0; + + virtual long __stdcall Clone( + /* [out] */ IWbemClassObject_BIPC **ppCopy) = 0; + + virtual long __stdcall GetObjectText( + /* [in] */ long lFlags, + /* [out] */ bstr *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 bstr wszName, + /* [out] */ bstr *pstrClassName) = 0; + + virtual long __stdcall InheritsFrom( + /* [in] */ const bstr strAncestor) = 0; + + virtual long __stdcall GetMethod( + /* [string][in] */ const bstr wszName, + /* [in] */ long lFlags, + /* [out] */ IWbemClassObject_BIPC **ppInSignature, + /* [out] */ IWbemClassObject_BIPC **ppOutSignature) = 0; + + virtual long __stdcall PutMethod( + /* [string][in] */ const bstr wszName, + /* [in] */ long lFlags, + /* [in] */ IWbemClassObject_BIPC *pInSignature, + /* [in] */ IWbemClassObject_BIPC *pOutSignature) = 0; + + virtual long __stdcall DeleteMethod( + /* [string][in] */ const bstr wszName) = 0; + + virtual long __stdcall BeginMethodEnumeration( + /* [in] */ long lEnumFlags) = 0; + + virtual long __stdcall NextMethod( + /* [in] */ long lFlags, + /* [unique][in][out] */ bstr *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 bstr wszMethod, + /* [out] */ void **ppQualSet) = 0; + + virtual long __stdcall GetMethodOrigin( + /* [string][in] */ const bstr wszMethodName, + /* [out] */ bstr *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] */ bstr *pstrName, + /* [out] */ wchar_variant *pValue) = 0; + + virtual long __stdcall EndEnumeration( void) = 0; + + virtual long __stdcall SetValue( + /* [string][in] */ const bstr wszName, + /* [in] */ long lFlags, + /* [in] */ wchar_variant *pValue) = 0; + + virtual long __stdcall GetValue( + /* [string][in] */ const bstr wszName, + /* [in] */ long lFlags, + /* [out] */ wchar_variant *pValue) = 0; + + virtual long __stdcall DeleteValue( + /* [string][in] */ const bstr 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 bstr 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 bstr strObjectPath, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppObject, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall GetObjectAsync( + /* [in] */ const bstr 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 bstr strClass, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall DeleteClassAsync( + /* [in] */ const bstr strClass, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall CreateClassEnum( + /* [in] */ const bstr strSuperclass, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [out] */ void **ppEnum) = 0; + + virtual long __stdcall CreateClassEnumAsync( + /* [in] */ const bstr 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 bstr strObjectPath, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall DeleteInstanceAsync( + /* [in] */ const bstr strObjectPath, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall CreateInstanceEnum( + /* [in] */ const bstr strFilter, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [out] */ void **ppEnum) = 0; + + virtual long __stdcall CreateInstanceEnumAsync( + /* [in] */ const bstr strFilter, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall ExecQuery( + /* [in] */ const bstr strQueryLanguage, + /* [in] */ const bstr strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [out] */ IEnumWbemClassObject_BIPC **ppEnum) = 0; + + virtual long __stdcall ExecQueryAsync( + /* [in] */ const bstr strQueryLanguage, + /* [in] */ const bstr strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall ExecNotificationQuery( + /* [in] */ const bstr strQueryLanguage, + /* [in] */ const bstr strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [out] */ void **ppEnum) = 0; + + virtual long __stdcall ExecNotificationQueryAsync( + /* [in] */ const bstr strQueryLanguage, + /* [in] */ const bstr strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall ExecMethod( + /* [in] */ const bstr strObjectPath, + /* [in] */ const bstr 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 bstr strObjectPath, + /* [in] */ const bstr 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 bstr strNetworkResource, + /* [in] */ const bstr strUser, + /* [in] */ const bstr strPassword, + /* [in] */ const bstr strLocale, + /* [in] */ long lSecurityFlags, + /* [in] */ const bstr 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 +{ + 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_acl +{ + unsigned char AclRevision; + unsigned char Sbz1; + unsigned short AclSize; + unsigned short AceCount; + unsigned short Sbz2; +}; + +struct interprocess_security_descriptor +{ + unsigned char Revision; + unsigned char Sbz1; + unsigned short Control; + void *Owner; + void *Group; + interprocess_acl *Sacl; + interprocess_acl *Dacl; +}; + +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; +}; + +struct interprocess_eventlogrecord +{ + unsigned long Length; // Length of full record + unsigned long Reserved; // Used by the service + unsigned long RecordNumber; // Absolute record number + unsigned long TimeGenerated; // Seconds since 1-1-1970 + unsigned long TimeWritten; // Seconds since 1-1-1970 + unsigned long EventID; + unsigned short EventType; + unsigned short NumStrings; + unsigned short EventCategory; + unsigned short ReservedFlags; // For use with paired events (auditing) + unsigned long ClosingRecordNumber; // For use with paired events (auditing) + unsigned long StringOffset; // Offset from beginning of record + unsigned long UserSidLength; + unsigned long UserSidOffset; + unsigned long DataLength; + unsigned long DataOffset; // Offset from beginning of record + // + // Then follow: + // + // wchar_t SourceName[] + // wchar_t Computername[] + // SID UserSid + // wchar_t Strings[] + // BYTE Data[] + // CHAR Pad[] + // unsigned long Length; + // +}; + +union large_integer +{ + __int64 QuadPart; +}; + +struct hinstance_struct { int unused; }; +typedef hinstance_struct *hmodule; + +struct hkey_struct; +typedef hkey_struct *hkey; + +#ifdef _WIN64 +typedef __int64 (__stdcall *farproc_t)(); +#else +typedef int (__stdcall *farproc_t)(); +#endif // _WIN64 + +#else //#ifndef BOOST_USE_WINDOWS_H + +typedef GUID GUID_BIPC; +typedef VARIANT wchar_variant; + +#if defined(BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME) + +typedef IUnknown IUnknown_BIPC; + +typedef IWbemClassObject IWbemClassObject_BIPC; + +typedef IWbemContext IWbemContext_BIPC; + +typedef IEnumWbemClassObject IEnumWbemClassObject_BIPC; + +typedef IWbemServices IWbemServices_BIPC; + +typedef IWbemLocator IWbemLocator_BIPC; + +#endif + +typedef OVERLAPPED interprocess_overlapped; + +typedef FILETIME interprocess_filetime; + +typedef WIN32_FIND_DATAA win32_find_data; + +typedef SECURITY_ATTRIBUTES interprocess_security_attributes; + +typedef SYSTEM_INFO system_info; + +typedef ACL interprocess_acl; + +typedef SECURITY_DESCRIPTOR interprocess_security_descriptor; + +typedef BY_HANDLE_FILE_INFORMATION interprocess_by_handle_file_information; + +typedef EVENTLOGRECORD interprocess_eventlogrecord; + +typedef LARGE_INTEGER large_integer; + +typedef HMODULE hmodule; + +typedef HKEY hkey; + +typedef BSTR bstr; + +typedef FARPROC farproc_t; + +#endif //#ifndef BOOST_USE_WINDOWS_H + +////////////////////////////////////////////////////////////////////////////// +// +// Nt native structures +// +////////////////////////////////////////////////////////////////////////////// + +struct interprocess_semaphore_basic_information +{ + unsigned int count; // current semaphore count + unsigned int limit; // max semaphore count +}; + +struct interprocess_section_basic_information +{ + void * base_address; + unsigned long section_attributes; + __int64 section_size; +}; + +struct 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; + ::boost::ulong_long_type ullBootTimeBias; + ::boost::ulong_long_type ullSleepTimeBias; + } data; + unsigned char Reserved1[sizeof(data_t)]; +}; + +static const long BootstampLength = sizeof(__int64); +static const long BootAndSystemstampLength = sizeof(__int64)*2; +static const long SystemTimeOfDayInfoLength = sizeof(system_timeofday_information::data_t); + +struct object_name_information_t +{ + unicode_string_t Name; + wchar_t NameBuffer[1]; +}; + +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 +}; + +enum semaphore_information_class { + semaphore_basic_information = 0 +}; + + +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 +}; + +enum section_information_class +{ + section_basic_information, + section_image_information +}; + +////////////////////////////////////////////////////////////////////////////// +// +// Forward declaration of winapi +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_USE_WINDOWS_H + +//Kernel32.dll + +//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) unsigned long __stdcall GetTickCount(void); +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) long __stdcall GetFileType(void *hFile); +extern "C" __declspec(dllimport) void *__stdcall FindFirstFileA(const char *lpFileName, win32_find_data *lpFindFileData); +extern "C" __declspec(dllimport) int __stdcall FindNextFileA(void *hFindFile, win32_find_data *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) void __stdcall GetSystemInfo (struct system_info *); +extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile (void *, std::size_t); +extern "C" __declspec(dllimport) int __stdcall VirtualUnlock (void *, std::size_t); +extern "C" __declspec(dllimport) int __stdcall VirtualProtect (void *, std::size_t, unsigned long, unsigned long *); +extern "C" __declspec(dllimport) int __stdcall FlushFileBuffers (void *); +extern "C" __declspec(dllimport) int __stdcall GetFileSizeEx (void *, large_integer *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 *, large_integer distance, large_integer *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 ReadFile(void *hnd, void *buffer, unsigned long bytes_to_read, unsigned long *bytes_read, interprocess_overlapped* overlapped); +extern "C" __declspec(dllimport) int __stdcall InitializeSecurityDescriptor(interprocess_security_descriptor *pSecurityDescriptor, unsigned long dwRevision); +extern "C" __declspec(dllimport) int __stdcall SetSecurityDescriptorDacl(interprocess_security_descriptor *pSecurityDescriptor, int bDaclPresent, interprocess_acl *pDacl, int bDaclDefaulted); +extern "C" __declspec(dllimport) hmodule __stdcall LoadLibraryA(const char *); +extern "C" __declspec(dllimport) int __stdcall FreeLibrary(hmodule); +extern "C" __declspec(dllimport) farproc_t __stdcall GetProcAddress(void *, const char*); +extern "C" __declspec(dllimport) hmodule __stdcall GetModuleHandleA(const char*); +extern "C" __declspec(dllimport) void *__stdcall GetFileInformationByHandle(void *, interprocess_by_handle_file_information*); + +//Advapi32.dll +extern "C" __declspec(dllimport) long __stdcall RegOpenKeyExA(hkey, const char *, unsigned long, unsigned long, hkey*); +extern "C" __declspec(dllimport) long __stdcall RegQueryValueExA(hkey, const char *, unsigned long*, unsigned long*, unsigned char *, unsigned long*); +extern "C" __declspec(dllimport) long __stdcall RegCloseKey(hkey); + +//Ole32.dll +extern "C" __declspec(dllimport) long __stdcall CoInitializeEx(void *pvReserved, unsigned long dwCoInit); +extern "C" __declspec(dllimport) long __stdcall CoInitializeSecurity( + void* pSecDesc, + long cAuthSvc, + void * asAuthSvc, + void *pReserved1, + unsigned long dwAuthnLevel, + unsigned long dwImpLevel, + void *pAuthList, + unsigned long dwCapabilities, + void *pReserved3 ); + + 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 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); + +//OleAut32.dll +extern "C" __declspec(dllimport) long __stdcall VariantClear(wchar_variant * pvarg); + +//Shell32.dll +extern "C" __declspec(dllimport) int __stdcall SHGetSpecialFolderPathA + (void* hwnd, const char *pszPath, int csidl, int fCreate); + +extern "C" __declspec(dllimport) int __stdcall SHGetFolderPathA(void *hwnd, int csidl, void *hToken, unsigned long dwFlags, const char *pszPath); + +//EventLog access functions + +extern "C" __declspec(dllimport) void* __stdcall OpenEventLogA + (const char* lpUNCServerName, const char* lpSourceName); + +extern "C" __declspec(dllimport) int __stdcall CloseEventLog(void *hEventLog); + +extern "C" __declspec(dllimport) int __stdcall ReadEventLogA + (void *hEventLog, + unsigned long dwReadFlags, + unsigned long dwRecordOffset, + void *lpBuffer, + unsigned long nNumberOfBytesToRead, + unsigned long *pnBytesRead, + unsigned long *pnMinNumberOfBytesNeeded + ); + +#endif //#ifndef BOOST_USE_WINDOWS_H + +//kernel32.dll +typedef int (__stdcall *QueryPerformanceCounter_t) (__int64 *lpPerformanceCount); +typedef int (__stdcall *QueryPerformanceFrequency_t)(__int64 *lpFrequency); + +//ntdll.dll +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 *NtOpenFile)(void **FileHandle, unsigned long DesiredAccess, object_attributes_t *ObjectAttributes + , io_status_block_t *IoStatusBlock, unsigned long ShareAccess, unsigned long Length, unsigned long OpenOptions); +typedef long (__stdcall *NtQuerySystemInformation_t)(int, void*, unsigned long, unsigned long *); +typedef long (__stdcall *NtQueryObject_t)(void*, object_information_class, void *, unsigned long, unsigned long *); +typedef long (__stdcall *NtQuerySemaphore_t)(void*, unsigned int info_class, interprocess_semaphore_basic_information *pinfo, unsigned int info_size, unsigned int *ret_len); +typedef long (__stdcall *NtQuerySection_t)(void*, section_information_class, interprocess_section_basic_information *pinfo, unsigned long info_size, unsigned long *ret_len); +typedef long (__stdcall *NtQueryInformationFile_t)(void *,io_status_block_t *,void *, long, int); +typedef long (__stdcall *NtOpenFile_t)(void*,unsigned long ,object_attributes_t*,io_status_block_t*,unsigned long,unsigned long); +typedef long (__stdcall *NtClose_t) (void*); +typedef long (__stdcall *NtQueryTimerResolution_t) (unsigned long* LowestResolution, unsigned long* HighestResolution, unsigned long* CurrentResolution); +typedef long (__stdcall *NtSetTimerResolution_t) (unsigned long RequestedResolution, int Set, unsigned long* ActualResolution); + +} //namespace winapi { +} //namespace interprocess { +} //namespace boost { + +////////////////////////////////////////////////////////////////////////////// +// +// Forward declaration of constants +// +////////////////////////////////////////////////////////////////////////////// + +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_invalid_handle = 6L; +static const unsigned long error_sharing_violation = 32L; +static const unsigned long error_file_not_found = 2u; +static const unsigned long error_no_more_files = 18u; +static const unsigned long error_not_locked = 158L; +//Retries in CreateFile, see http://support.microsoft.com/kb/316609 +static const unsigned long error_sharing_violation_tries = 3L; +static const unsigned long error_sharing_violation_sleep_ms = 250L; +static const unsigned long error_file_too_large = 223L; +static const unsigned long error_insufficient_buffer = 122L; +static const unsigned long error_handle_eof = 38L; +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 page_noaccess = 0x01; + +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 long delete_flag = 0x00010000L; + +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 file_type_char = 0x0002L; +static const unsigned long file_type_disk = 0x0001L; +static const unsigned long file_type_pipe = 0x0003L; +static const unsigned long file_type_remote = 0x8000L; +static const unsigned long file_type_unknown = 0x0000L; + +static const unsigned long create_new = 1; +static const unsigned long create_always = 2; +static const unsigned long open_existing = 3; +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; + +const unsigned long max_record_buffer_size = 0x10000L; // 64K +const unsigned long max_path = 260; + +//Keys +static const hkey hkey_local_machine = (hkey)(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; +const signed long RPC_E_CHANGED_MODE_BIPC = 0x80010106L; +const unsigned long COINIT_APARTMENTTHREADED_BIPC = 0x2; +const unsigned long COINIT_MULTITHREADED_BIPC = 0x0; +const unsigned long COINIT_DISABLE_OLE1DDE_BIPC = 0x4; +const unsigned long COINIT_SPEED_OVER_MEMORY_BIPC = 0x4; + + +//If the user needs to change default COM initialization model, +//it can define BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL to one of these: +// +// COINIT_APARTMENTTHREADED_BIPC +// COINIT_MULTITHREADED_BIPC +// COINIT_DISABLE_OLE1DDE_BIPC +// COINIT_SPEED_OVER_MEMORY_BIPC +#if !defined(BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL) + #define BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL COINIT_APARTMENTTHREADED_BIPC +#elif (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_APARTMENTTHREADED_BIPC) &&\ + (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_MULTITHREADED_BIPC) &&\ + (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_DISABLE_OLE1DDE_BIPC) &&\ + (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_SPEED_OVER_MEMORY_BIPC) + #error "Wrong value for BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL macro" +#endif + +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}}; + +static const unsigned long eventlog_sequential_read = 0x0001; +static const unsigned long eventlog_backwards_read = 0x0008; + +} //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(0); + } +} + +inline void sleep_tick() +{ 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 *lpFindFileData) +{ return FindFirstFileA(lpFileName, lpFindFileData); } + +inline bool find_next_file(void *hFindFile, win32_find_data *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 unsigned long get_file_type(void *hFile) +{ + return GetFileType(hFile); +} + +/* +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 void *open_semaphore(const char *name) +{ return OpenSemaphoreA(semaphore_all_access, 0, name); } + +inline int release_semaphore(void *handle, long release_count, long *prev_count) +{ return ReleaseSemaphore(handle, release_count, prev_count); } + +class interprocess_all_access_security +{ + interprocess_security_attributes sa; + interprocess_security_descriptor sd; + 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, ::boost::ulong_long_type file_offset, const char * name, interprocess_security_attributes *psec) +{ + const unsigned long high_size(file_offset >> 32), low_size((boost::uint32_t)file_offset); + return CreateFileMappingA (handle, psec, access, high_size, low_size, name); +} + +inline void * open_file_mapping (unsigned long access, const char *name) +{ return OpenFileMappingA (access, 0, name); } + +inline void *map_view_of_file_ex(void *handle, unsigned long file_access, ::boost::ulong_long_type offset, std::size_t numbytes, void *base_addr) +{ + const unsigned long offset_low = (unsigned long)(offset & ((::boost::ulong_long_type)0xFFFFFFFF)); + const unsigned long offset_high = offset >> 32; + return MapViewOfFileEx(handle, file_access, offset_high, offset_low, numbytes, base_addr); +} + +inline void *create_file(const char *name, unsigned long access, unsigned long creation_flags, unsigned long attributes, interprocess_security_attributes *psec) +{ + 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 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 virtual_unlock(void *base_addr, std::size_t numbytes) +{ return 0 != VirtualUnlock(base_addr, numbytes); } + +inline bool virtual_protect(void *base_addr, std::size_t numbytes, unsigned long flNewProtect, unsigned long &lpflOldProtect) +{ return 0 != VirtualProtect(base_addr, numbytes, flNewProtect, &lpflOldProtect); } + +inline bool flush_file_buffers(void *handle) +{ return 0 != FlushFileBuffers(handle); } + +inline bool get_file_size(void *handle, __int64 &size) +{ return 0 != GetFileSizeEx(handle, (large_integer*)&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) +{ + large_integer d; d.QuadPart = distance; + return 0 != SetFilePointerEx(handle, d, (large_integer*)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 read_file(void *hnd, void *buffer, unsigned long bytes_to_read, unsigned long *bytes_read, interprocess_overlapped* overlapped) +{ return 0 != ReadFile(hnd, buffer, bytes_to_read, bytes_read, overlapped); } + +inline bool get_file_information_by_handle(void *hnd, interprocess_by_handle_file_information *info) +{ return 0 != GetFileInformationByHandle(hnd, info); } + +inline long interlocked_increment(long volatile *addr) +{ return BOOST_INTERLOCKED_INCREMENT(const_cast(addr)); } + +inline long interlocked_decrement(long volatile *addr) +{ return BOOST_INTERLOCKED_DECREMENT(const_cast(addr)); } + +inline long interlocked_compare_exchange(long volatile *addr, long val1, long val2) +{ return BOOST_INTERLOCKED_COMPARE_EXCHANGE(const_cast(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 hmodule load_library(const char *name) +{ return LoadLibraryA(name); } + +inline bool free_library(hmodule module) +{ return 0 != FreeLibrary(module); } + +inline farproc_t get_proc_address(hmodule module, const char *name) +{ return GetProcAddress(module, name); } + +inline void *get_current_process() +{ return GetCurrentProcess(); } + +inline hmodule get_module_handle(const char *name) +{ return GetModuleHandleA(name); } + +inline long reg_open_key_ex(hkey hKey, const char *lpSubKey, unsigned long ulOptions, unsigned long samDesired, hkey *phkResult) +{ return RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult); } + +inline long reg_query_value_ex(hkey 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(hkey hKey) +{ return RegCloseKey(hKey); } + +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 + , NtQuerySemaphore + , NtQuerySection + , NtOpenFile + , NtClose + , NtQueryTimerResolution + , NtSetTimerResolution + , QueryPerformanceCounter + , QueryPerformanceFrequency + , NumFunction + }; + enum { NtDll_dll, Kernel32_dll, NumModule }; + + private: + static const char *FunctionNames[NumFunction]; + static const char *ModuleNames[NumModule]; + static farproc_t FunctionAddresses[NumFunction]; + static unsigned int FunctionModules[NumFunction]; + static volatile long FunctionStates[NumFunction]; + static hmodule ModuleAddresses[NumModule]; + static volatile long ModuleStates[NumModule]; + + static hmodule get_module_from_id(unsigned int id) + { + BOOST_ASSERT(id < (unsigned int)NumModule); + hmodule addr = get_module_handle(ModuleNames[id]); + BOOST_ASSERT(addr); + return addr; + } + + static hmodule get_module(const unsigned int id) + { + BOOST_ASSERT(id < (unsigned int)NumModule); + for(unsigned i = 0; ModuleStates[id] < 2; ++i){ + if(interlocked_compare_exchange(&ModuleStates[id], 1, 0) == 0){ + ModuleAddresses[id] = get_module_from_id(id); + interlocked_increment(&ModuleStates[id]); + break; + } + else if(i & 1){ + sched_yield(); + } + else{ + sleep_tick(); + } + } + return ModuleAddresses[id]; + } + + static farproc_t get_address_from_dll(const unsigned int id) + { + BOOST_ASSERT(id < (unsigned int)NumFunction); + farproc_t addr = get_proc_address(get_module(FunctionModules[id]), FunctionNames[id]); + BOOST_ASSERT(addr); + return addr; + } + + public: + static farproc_t get(const unsigned int id) + { + BOOST_ASSERT(id < (unsigned int)NumFunction); + for(unsigned i = 0; FunctionStates[id] < 2; ++i){ + if(interlocked_compare_exchange(&FunctionStates[id], 1, 0) == 0){ + FunctionAddresses[id] = get_address_from_dll(id); + interlocked_increment(&FunctionStates[id]); + break; + } + else if(i & 1){ + sched_yield(); + } + else{ + sleep_tick(); + } + } + return FunctionAddresses[id]; + } +}; + +template +const char *function_address_holder::FunctionNames[function_address_holder::NumFunction] = +{ + "NtSetInformationFile", + "NtQuerySystemInformation", + "NtQueryObject", + "NtQuerySemaphore", + "NtQuerySection", + "NtOpenFile", + "NtClose", + "NtQueryTimerResolution", + "NtSetTimerResolution", + "QueryPerformanceCounter", + "QueryPerformanceFrequency" +}; + +template +unsigned int function_address_holder::FunctionModules[function_address_holder::NumFunction] = +{ + NtDll_dll, + NtDll_dll, + NtDll_dll, + NtDll_dll, + NtDll_dll, + NtDll_dll, + NtDll_dll, + NtDll_dll, + NtDll_dll, + Kernel32_dll, + Kernel32_dll +}; + +template +const char *function_address_holder::ModuleNames[function_address_holder::NumModule] = +{ + "ntdll.dll", + "kernel32.dll" +}; + + +template +farproc_t function_address_holder::FunctionAddresses[function_address_holder::NumFunction]; + +template +volatile long function_address_holder::FunctionStates[function_address_holder::NumFunction]; + +template +hmodule 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 +{ + hmodule lib_; + library_unloader(hmodule module) : lib_(module){} + ~library_unloader(){ free_library(lib_); } +}; + + +inline bool get_system_time_of_day_information(system_timeofday_information &info) +{ + NtQuerySystemInformation_t pNtQuerySystemInformation = (NtQuerySystemInformation_t) + 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; +} + +//Writes the hexadecimal value of the buffer, in the wide character string. +//str must be twice length +inline void buffer_to_wide_str(const void *buf, std::size_t length, wchar_t *str) +{ + 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; + const char *chbuf = static_cast(buf); + for(std::size_t i = 0; i != length; ++i){ + str[char_counter++] = Characters[(chbuf[i]&0xF0)>>4]; + str[char_counter++] = Characters[(chbuf[i]&0x0F)]; + } +} + +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; + } + + buffer_to_wide_str(&info.Reserved1[0], BootAndSystemstampLength, bootsystemstamp); + s = BootAndSystemstampLength*2; + return true; +} + +class handle_closer +{ + void *handle_; + handle_closer(const handle_closer &); + handle_closer& operator=(const handle_closer &); + public: + explicit handle_closer(void *handle) : handle_(handle){} + ~handle_closer() + { close_handle(handle_); } +}; + +class eventlog_handle_closer +{ + void *handle_; + eventlog_handle_closer(const handle_closer &); + eventlog_handle_closer& operator=(const eventlog_handle_closer &); + public: + explicit eventlog_handle_closer(void *handle) : handle_(handle){} + ~eventlog_handle_closer() + { CloseEventLog(handle_); } +}; + +union ntquery_mem_t +{ + object_name_information_t name; + struct ren_t + { + file_rename_information_t info; + wchar_t buf[1]; + } ren; +}; + +class nt_query_mem_deleter +{ + static const std::size_t rename_offset = offsetof(ntquery_mem_t, ren.info.FileName) - + offsetof(ntquery_mem_t, name.Name.Buffer); + // Timestamp process id atomic count + static const std::size_t rename_suffix = + (SystemTimeOfDayInfoLength + sizeof(unsigned long) + sizeof(boost::uint32_t))*2; + + public: + nt_query_mem_deleter(std::size_t object_name_information_size) + : m_size(object_name_information_size + rename_offset + rename_suffix) + , m_buf(new char [m_size]) + {} + + ~nt_query_mem_deleter() + { + delete[]m_buf; + } + + void realloc_mem(std::size_t num_bytes) + { + num_bytes += rename_suffix + rename_offset; + char *buf = m_buf; + m_buf = new char[num_bytes]; + delete[]buf; + m_size = num_bytes; + } + + ntquery_mem_t *query_mem() const + { return static_cast(static_cast(m_buf)); } + + unsigned long object_name_information_size() const + { + return static_cast(m_size - rename_offset - SystemTimeOfDayInfoLength*2); + } + + std::size_t file_rename_information_size() const + { return static_cast(m_size); } + + private: + std::size_t m_size; + char *m_buf; +}; + +class c_heap_deleter +{ + public: + c_heap_deleter(std::size_t size) + : m_buf(::malloc(size)) + {} + + ~c_heap_deleter() + { + if(m_buf) ::free(m_buf); + } + + void realloc_mem(std::size_t num_bytes) + { + void *buf = ::realloc(m_buf, num_bytes); + if(!buf){ + free(m_buf); + m_buf = 0; + } + } + + void *get() const + { return m_buf; } + + private: + void *m_buf; +}; + +inline bool unlink_file(const char *filename) +{ + //Don't try to optimize doing a DeleteFile first + //as there are interactions with permissions and + //in-use files. + // + //if(!delete_file(filename)){ + // (...) + // + + //This functions tries to emulate UNIX unlink semantics in windows. + // + //- Open the file and mark the handle as delete-on-close + //- Rename the file to an arbitrary name based on a random number + //- Close the handle. If there are no file users, it will be deleted. + // Otherwise it will be used by already connected handles but the + // file name can't be used to open this file again + try{ + NtSetInformationFile_t pNtSetInformationFile = + (NtSetInformationFile_t)dll_func::get(dll_func::NtSetInformationFile); + + NtQueryObject_t pNtQueryObject = (NtQueryObject_t)dll_func::get(dll_func::NtQueryObject); + + //First step: Obtain a handle to the file using Win32 rules. This resolves relative paths + void *fh = create_file(filename, generic_read | delete_access, open_existing, 0, 0); + if(fh == invalid_handle_value){ + return false; + } + + handle_closer h_closer(fh); + { + //Obtain name length + unsigned long size; + const std::size_t initial_string_mem = 512u; + + nt_query_mem_deleter nt_query_mem(sizeof(ntquery_mem_t)+initial_string_mem); + //Obtain file name with guessed length + if(pNtQueryObject(fh, object_name_information, nt_query_mem.query_mem(), nt_query_mem.object_name_information_size(), &size)){ + //Obtain file name with exact length buffer + nt_query_mem.realloc_mem(size); + if(pNtQueryObject(fh, object_name_information, nt_query_mem.query_mem(), nt_query_mem.object_name_information_size(), &size)){ + return false; + } + } + ntquery_mem_t *pmem = nt_query_mem.query_mem(); + file_rename_information_t *pfri = &pmem->ren.info; + const std::size_t RenMaxNumChars = + (((char*)(pmem) + nt_query_mem.file_rename_information_size()) - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t); + + //Copy filename to the rename member + std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length); + std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t); + + //Search '\\' character to replace from 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; + + //Sometimes the precission of the timestamp is not enough and we need to add another random number. + //The process id (to exclude concurrent processes) and an atomic count (to exclude concurrent threads). + //should be enough + const unsigned long pid = get_current_process_id(); + buffer_to_wide_str(&pid, sizeof(pid), &pfri->FileName[filename_string_length]); + filename_string_length += sizeof(pid)*2; + + static volatile boost::uint32_t u32_count = 0; + interlocked_decrement(reinterpret_cast(&u32_count)); + buffer_to_wide_str(const_cast(&u32_count), sizeof(boost::uint32_t), &pfri->FileName[filename_string_length]); + filename_string_length += sizeof(boost::uint32_t)*2; + + //Fill rename information (FileNameLength is in bytes) + pfri->FileNameLength = static_cast(sizeof(wchar_t)*(filename_string_length)); + pfri->Replace = 1; + pfri->RootDir = 0; + + //Cange the name of the in-use file... + io_status_block_t io; + if(0 != pNtSetInformationFile(fh, &io, pfri, nt_query_mem.file_rename_information_size(), file_rename_information)){ + return false; + } + } + //...and mark it as delete-on-close + { + //Don't use pNtSetInformationFile with file_disposition_information as it can return STATUS_CANNOT_DELETE + //if the file is still mapped. Reopen it with NtOpenFile and file_delete_on_close + NtOpenFile_t pNtOpenFile = (NtOpenFile_t)dll_func::get(dll_func::NtOpenFile); + NtClose_t pNtClose = (NtClose_t)dll_func::get(dll_func::NtClose); + const wchar_t empty_str [] = L""; + unicode_string_t ustring = { sizeof(empty_str) - sizeof (wchar_t) //length in bytes without null + , sizeof(empty_str) //total size in bytes of memory allocated for Buffer. + , const_cast(empty_str) + }; + object_attributes_t object_attr; + initialize_object_attributes(&object_attr, &ustring, 0, fh, 0); + void* fh2 = 0; + io_status_block_t io; + pNtOpenFile( &fh2, delete_flag, &object_attr, &io + , file_share_read | file_share_write | file_share_delete, file_delete_on_close); + pNtClose(fh2); + //Even if NtOpenFile fails, the file was renamed and the original no longer exists, so return a success status + return true; + } + } + catch(...){ + return false; + } + return true; +} + +struct reg_closer +{ + hkey key_; + reg_closer(hkey key) : key_(key){} + ~reg_closer(){ reg_close_key(key_); } +}; + +inline void get_shared_documents_folder(std::string &s) +{ + #if 1 //Original registry search code + s.clear(); + hkey 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; + } + } + #else //registry alternative: SHGetFolderPath + const int BIPC_CSIDL_COMMON_APPDATA = 0x0023; // All Users\Application Data + const int BIPC_CSIDL_FLAG_CREATE = 0x8000; // new for Win2K, or this in to force creation of folder + const int BIPC_SHGFP_TYPE_CURRENT = 0; // current value for user, verify it exists + + s.clear(); + char szPath[max_path]; + if(0 == SHGetFolderPathA(0, BIPC_CSIDL_COMMON_APPDATA | BIPC_CSIDL_FLAG_CREATE, 0, BIPC_SHGFP_TYPE_CURRENT, szPath)){ + s = szPath; + } + + #endif +} + +inline void get_registry_value(const char *folder, const char *value_key, std::vector &s) +{ + s.clear(); + hkey 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; + } + } +} + +#if defined(BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME) + +struct co_uninitializer +{ + co_uninitializer(bool b_uninitialize) + : m_b_uninitialize(b_uninitialize) + {} + + ~co_uninitializer() + { + if(m_b_uninitialize){ + CoUninitialize(); + } + } + + private: + const bool m_b_uninitialize; +}; + +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 + // + //See BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL definition if you need to change the + //default value of this macro in your application + long co_init_ret = CoInitializeEx(0, BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL); + if(co_init_ret != S_OK_BIPC && co_init_ret != S_FALSE_BIPC && co_init_ret != RPC_E_CHANGED_MODE_BIPC) + return false; + co_uninitializer co_initialize_end(co_init_ret != RPC_E_CHANGED_MODE_BIPC); + (void)co_initialize_end; + + bool bRet = false; + long sec_init_ret = CoInitializeSecurity + ( 0 //pVoid + ,-1 //cAuthSvc + , 0 //asAuthSvc + , 0 //pReserved1 + , RPC_C_AUTHN_LEVEL_PKT_BIPC //dwAuthnLevel + , RPC_C_IMP_LEVEL_IMPERSONATE_BIPC //dwImpLevel + , 0 //pAuthList + , EOAC_NONE_BIPC //dwCapabilities + , 0 //pReserved3 + ); + 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( + (bstr)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( + (bstr)L"WQL", + (bstr)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( (bstr)L"LastBootUpTime", 0, &vwchar, 0, 0 ) ){ + bRet = true; + strValue = (wchar_t*)vwchar.bstrVal; + VariantClear(&vwchar ); + break; + } + } + } + return bRet; +} + +//Obtains the bootup time from WMI LastBootUpTime. +//This time seems to change with hibernation and clock synchronization so avoid it. +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; +} + +#else + +// Loop through the buffer and obtain the contents of the +// requested record in the buffer. +inline bool find_record_in_buffer( const void* pBuffer, unsigned long dwBytesRead, const char *provider_name + , unsigned int id_to_find, interprocess_eventlogrecord *&pevent_log_record) +{ + const unsigned char * pRecord = static_cast(pBuffer); + const unsigned char * pEndOfRecords = pRecord + dwBytesRead; + + while (pRecord < pEndOfRecords){ + interprocess_eventlogrecord *pTypedRecord = (interprocess_eventlogrecord*)pRecord; + // Check provider, written at the end of the fixed-part of the record + if (0 == std::strcmp(provider_name, (char*)(pRecord + sizeof(interprocess_eventlogrecord)))) + { + // Check event id + if(id_to_find == (pTypedRecord->EventID & 0xFFFF)){ + pevent_log_record = pTypedRecord; + return true; + } + } + + pRecord += pTypedRecord->Length; + } + pevent_log_record = 0; + return false; +} + +//Obtains the bootup time from the System Event Log, +//event ID == 6005 (event log started). +//Adapted from http://msdn.microsoft.com/en-us/library/windows/desktop/bb427356.aspx +inline bool get_last_bootup_time(std::string &stamp) +{ + const char *source_name = "System"; + const char *provider_name = "EventLog"; + const unsigned short event_id = 6005u; + + unsigned long status = 0; + unsigned long dwBytesToRead = 0; + unsigned long dwBytesRead = 0; + unsigned long dwMinimumBytesToRead = 0; + + // The source name (provider) must exist as a subkey of Application. + void *hEventLog = OpenEventLogA(0, source_name); + if (hEventLog){ + eventlog_handle_closer hnd_closer(hEventLog); (void)hnd_closer; + // Allocate an initial block of memory used to read event records. The number + // of records read into the buffer will vary depending on the size of each event. + // The size of each event will vary based on the size of the user-defined + // data included with each event, the number and length of insertion + // strings, and other data appended to the end of the event record. + dwBytesToRead = max_record_buffer_size; + c_heap_deleter heap_deleter(dwBytesToRead); + + // Read blocks of records until you reach the end of the log or an + // error occurs. The records are read from newest to oldest. If the buffer + // is not big enough to hold a complete event record, reallocate the buffer. + if (heap_deleter.get() != 0){ + while (0 == status){ + if (!ReadEventLogA(hEventLog, + eventlog_sequential_read | eventlog_backwards_read, + 0, + heap_deleter.get(), + dwBytesToRead, + &dwBytesRead, + &dwMinimumBytesToRead)) { + status = get_last_error(); + if (error_insufficient_buffer == status) { + status = 0; + dwBytesToRead = dwMinimumBytesToRead; + heap_deleter.realloc_mem(dwMinimumBytesToRead); + if (!heap_deleter.get()){ + return false; + } + } + else{ //Not found or EOF + return false; + } + } + else + { + interprocess_eventlogrecord *pTypedRecord; + // Print the contents of each record in the buffer. + if(find_record_in_buffer(heap_deleter.get(), dwBytesRead, provider_name, event_id, pTypedRecord)){ + char stamp_str[sizeof(unsigned long)*3+1]; + std::sprintf(&stamp_str[0], "%u", ((unsigned int)pTypedRecord->TimeGenerated)); + stamp = stamp_str; + break; + } + } + } + } + } + return true; +} + +#endif + +inline bool is_directory(const char *path) +{ + unsigned long attrib = GetFileAttributesA(path); + + return (attrib != invalid_file_attributes && + (attrib & file_attribute_directory)); +} + +inline bool get_file_mapping_size(void *file_mapping_hnd, __int64 &size) +{ + NtQuerySection_t pNtQuerySection = + (NtQuerySection_t)dll_func::get(dll_func::NtQuerySection); + //Obtain file name + interprocess_section_basic_information info; + unsigned long ntstatus = + pNtQuerySection(file_mapping_hnd, section_basic_information, &info, sizeof(info), 0); + size = info.section_size; + return !ntstatus; +} + +inline bool get_semaphore_info(void *handle, long &count, long &limit) +{ + winapi::interprocess_semaphore_basic_information info; + winapi::NtQuerySemaphore_t pNtQuerySemaphore = + (winapi::NtQuerySemaphore_t)dll_func::get(winapi::dll_func::NtQuerySemaphore); + unsigned int ret_len; + long status = pNtQuerySemaphore(handle, winapi::semaphore_basic_information, &info, sizeof(info), &ret_len); + count = info.count; + limit = info.limit; + return !status; +} + +inline bool query_timer_resolution(unsigned long *lowres, unsigned long *highres, unsigned long *curres) +{ + winapi::NtQueryTimerResolution_t pNtQueryTimerResolution = + (winapi::NtQueryTimerResolution_t)dll_func::get(winapi::dll_func::NtQueryTimerResolution); + return !pNtQueryTimerResolution(lowres, highres, curres); +} + +inline bool set_timer_resolution(unsigned long RequestedResolution, int Set, unsigned long* ActualResolution) +{ + winapi::NtSetTimerResolution_t pNtSetTimerResolution = + (winapi::NtSetTimerResolution_t)dll_func::get(winapi::dll_func::NtSetTimerResolution); + return !pNtSetTimerResolution(RequestedResolution, Set, ActualResolution); +} + +inline bool query_performance_counter(__int64 *lpPerformanceCount) +{ + QueryPerformanceCounter_t pQueryPerformanceCounter = (QueryPerformanceCounter_t) + dll_func::get(dll_func::QueryPerformanceCounter); + return 0 != pQueryPerformanceCounter(lpPerformanceCount); +} + +inline bool query_performance_frequency(__int64 *lpFrequency) +{ + QueryPerformanceCounter_t pQueryPerformanceFrequency = (QueryPerformanceFrequency_t) + dll_func::get(dll_func::QueryPerformanceFrequency); + return 0 != pQueryPerformanceFrequency(lpFrequency); +} + +inline unsigned long get_tick_count() +{ return GetTickCount(); } + +} //namespace winapi +} //namespace interprocess +} //namespace boost + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +# pragma GCC diagnostic pop +#endif + +#include + +#endif //#ifdef BOOST_INTERPROCESS_WIN32_API_HPP diff --git a/libraries/boost/boost/interprocess/detail/windows_intermodule_singleton.hpp b/libraries/boost/boost/interprocess/detail/windows_intermodule_singleton.hpp new file mode 100644 index 000000000..12ad2015e --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/windows_intermodule_singleton.hpp @@ -0,0 +1,314 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP +#define BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include + +#if !defined(BOOST_INTERPROCESS_WINDOWS) + #error "This header can't be included from non-windows operating systems" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +namespace intermodule_singleton_helpers { + +//This global map will be implemented using 3 sync primitives: +// +//1) A named mutex that will implement global mutual exclusion between +// threads from different modules/dlls +// +//2) A semaphore that will act as a global counter for modules attached to the global map +// so that the global map can be destroyed when the last module is detached. +// +//3) A semaphore that will be hacked to hold the address of a heap-allocated map in the +// max and current semaphore count. +class windows_semaphore_based_map +{ + typedef boost::container::map map_type; + + public: + windows_semaphore_based_map() + { + map_type *m = new map_type; + boost::uint32_t initial_count = 0; + boost::uint32_t max_count = 0; + + //Windows user address space sizes: + //32 bit windows: [32 bit processes] 2GB or 3GB (31/32 bits) + //64 bit windows: [32 bit processes] 2GB or 4GB (31/32 bits) + // [64 bit processes] 2GB or 8TB (31/43 bits) + // + //Windows semaphores use 'long' parameters (32 bits in LLP64 data model) and + //those values can't be negative, so we have 31 bits to store something + //in max_count and initial count parameters. + //Also, max count must be bigger than 0 and bigger or equal than initial count. + if(sizeof(void*) == sizeof(boost::uint32_t)){ + //This means that for 32 bit processes, a semaphore count (31 usable bits) is + //enough to store 4 byte aligned memory (4GB -> 32 bits - 2 bits = 30 bits). + //The max count will hold the pointer value and current semaphore count + //will be zero. + // + //Relying in UB with a cast through union, but all known windows compilers + //accept this (C11 also accepts this). + union caster_union + { + void *addr; + boost::uint32_t addr_uint32; + } caster; + caster.addr = m; + //memory is at least 4 byte aligned in windows + BOOST_ASSERT((caster.addr_uint32 & boost::uint32_t(3)) == 0); + max_count = caster.addr_uint32 >> 2; + } + else if(sizeof(void*) == sizeof(boost::uint64_t)){ + //Relying in UB with a cast through union, but all known windows compilers + //accept this (C11 accepts this). + union caster_union + { + void *addr; + boost::uint64_t addr_uint64; + } caster; + caster.addr = m; + //We'll encode the address using 30 bits in each 32 bit high and low parts. + //High part will be the sem max count, low part will be the sem initial count. + //(restrictions: max count > 0, initial count >= 0 and max count >= initial count): + // + // - Low part will be shifted two times (4 byte alignment) so that top + // two bits are cleared (the top one for sign, the next one to + // assure low part value is always less than the high part value. + // - The top bit of the high part will be cleared and the next bit will be 1 + // (so high part is always bigger than low part due to the quasi-top bit). + // + // This means that the addresses we can store must be 4 byte aligned + // and less than 1 ExbiBytes ( 2^60 bytes, ~1 ExaByte). User-level address space in Windows 64 + // is much less than this (8TB, 2^43 bytes): "1 EByte (or it was 640K?) ought to be enough for anybody" ;-). + caster.addr = m; + BOOST_ASSERT((caster.addr_uint64 & boost::uint64_t(3)) == 0); + max_count = boost::uint32_t(caster.addr_uint64 >> 32); + initial_count = boost::uint32_t(caster.addr_uint64); + initial_count = initial_count/4; + //Make sure top two bits are zero + BOOST_ASSERT((max_count & boost::uint32_t(0xC0000000)) == 0); + //Set quasi-top bit + max_count |= boost::uint32_t(0x40000000); + } + bool created = false; + const permissions & perm = permissions(); + std::string pid_creation_time, name; + get_pid_creation_time_str(pid_creation_time); + name = "bipc_gmap_sem_lock_"; + name += pid_creation_time; + bool success = m_mtx_lock.open_or_create(name.c_str(), perm); + name = "bipc_gmap_sem_count_"; + name += pid_creation_time; + scoped_lock lck(m_mtx_lock); + { + success = success && m_sem_count.open_or_create + ( name.c_str(), static_cast(0), winapi_semaphore_wrapper::MaxCount, perm, created); + name = "bipc_gmap_sem_map_"; + name += pid_creation_time; + success = success && m_sem_map.open_or_create + (name.c_str(), initial_count, max_count, perm, created); + if(!success){ + delete m; + //winapi_xxx wrappers do the cleanup... + throw int(0); + } + if(!created){ + delete m; + } + else{ + BOOST_ASSERT(&get_map_unlocked() == m); + } + m_sem_count.post(); + } + } + + map_type &get_map_unlocked() + { + if(sizeof(void*) == sizeof(boost::uint32_t)){ + union caster_union + { + void *addr; + boost::uint32_t addr_uint32; + } caster; + caster.addr = 0; + caster.addr_uint32 = m_sem_map.limit(); + caster.addr_uint32 = caster.addr_uint32 << 2; + return *static_cast(caster.addr); + } + else{ + union caster_union + { + void *addr; + boost::uint64_t addr_uint64; + } caster; + boost::uint32_t max_count(m_sem_map.limit()), initial_count(m_sem_map.value()); + //Clear quasi-top bit + max_count &= boost::uint32_t(0xBFFFFFFF); + caster.addr_uint64 = max_count; + caster.addr_uint64 = caster.addr_uint64 << 32; + caster.addr_uint64 |= boost::uint64_t(initial_count) << 2; + return *static_cast(caster.addr); + } + } + + ref_count_ptr *find(const char *name) + { + scoped_lock lck(m_mtx_lock); + map_type &map = this->get_map_unlocked(); + map_type::iterator it = map.find(boost::container::string(name)); + if(it != map.end()){ + return &it->second; + } + else{ + return 0; + } + } + + ref_count_ptr * insert(const char *name, const ref_count_ptr &ref) + { + scoped_lock lck(m_mtx_lock); + map_type &map = this->get_map_unlocked(); + map_type::iterator it = map.insert(map_type::value_type(boost::container::string(name), ref)).first; + return &it->second; + } + + bool erase(const char *name) + { + scoped_lock lck(m_mtx_lock); + map_type &map = this->get_map_unlocked(); + return map.erase(boost::container::string(name)) != 0; + } + + template + void atomic_func(F &f) + { + scoped_lock lck(m_mtx_lock); + f(); + } + + ~windows_semaphore_based_map() + { + scoped_lock lck(m_mtx_lock); + m_sem_count.wait(); + if(0 == m_sem_count.value()){ + map_type &map = this->get_map_unlocked(); + BOOST_ASSERT(map.empty()); + delete ↦ + } + //First close sems to protect this with the external mutex + m_sem_map.close(); + m_sem_count.close(); + //Once scoped_lock unlocks the mutex, the destructor will close the handle... + } + + private: + winapi_mutex_wrapper m_mtx_lock; + winapi_semaphore_wrapper m_sem_map; + winapi_semaphore_wrapper m_sem_count; +}; + +template<> +struct thread_safe_global_map_dependant +{ + static void apply_gmem_erase_logic(const char *, const char *){} + + static bool remove_old_gmem() + { return true; } + + struct lock_file_logic + { + lock_file_logic(windows_semaphore_based_map &) + : retry_with_new_map(false) + {} + + void operator()(void){} + bool retry() const { return retry_with_new_map; } + private: + const bool retry_with_new_map; + }; + + static void construct_map(void *addr) + { + ::new (addr)windows_semaphore_based_map; + } + + struct unlink_map_logic + { + unlink_map_logic(windows_semaphore_based_map &) + {} + void operator()(){} + }; + + static ref_count_ptr *find(windows_semaphore_based_map &map, const char *name) + { + return map.find(name); + } + + static ref_count_ptr * insert(windows_semaphore_based_map &map, const char *name, const ref_count_ptr &ref) + { + return map.insert(name, ref); + } + + static bool erase(windows_semaphore_based_map &map, const char *name) + { + return map.erase(name); + } + + template + static void atomic_func(windows_semaphore_based_map &map, F &f) + { + map.atomic_func(f); + } +}; + +} //namespace intermodule_singleton_helpers { + +template +class windows_intermodule_singleton + : public intermodule_singleton_impl + < C + , LazyInit + , Phoenix + , intermodule_singleton_helpers::windows_semaphore_based_map + > +{}; + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP diff --git a/libraries/boost/boost/interprocess/detail/workaround.hpp b/libraries/boost/boost/interprocess/detail/workaround.hpp new file mode 100644 index 000000000..5089696fb --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/workaround.hpp @@ -0,0 +1,205 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP +#define BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #define BOOST_INTERPROCESS_WINDOWS + #define BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION + #define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME + //Define this to connect with shared memory created with versions < 1.54 + //#define BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME +#else + #include + + ////////////////////////////////////////////////////// + //Check for XSI shared memory objects. They are available in nearly all UNIX platforms + ////////////////////////////////////////////////////// + #if !defined(__QNXNTO__) && !defined(__ANDROID__) && !defined(__HAIKU__) + #define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + #endif + + ////////////////////////////////////////////////////// + // From SUSv3/UNIX 98, pthread_mutexattr_settype is mandatory + ////////////////////////////////////////////////////// + #if defined(_XOPEN_UNIX) && ((_XOPEN_VERSION + 0) >= 500) + #define BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES + #endif + + ////////////////////////////////////////////////////// + // _POSIX_THREAD_PROCESS_SHARED (POSIX.1b/POSIX.4) + ////////////////////////////////////////////////////// + #if defined(_POSIX_THREAD_PROCESS_SHARED) && ((_POSIX_THREAD_PROCESS_SHARED + 0) > 0) + //Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it. + #if defined(__CYGWIN__) + #define BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED + //Mac Os X < Lion (10.7) might define _POSIX_THREAD_PROCESS_SHARED but there is no real support. + #elif defined(__APPLE__) + #include "TargetConditionals.h" + //Check we're on Mac OS target + #if defined(TARGET_OS_MAC) + #include "AvailabilityMacros.h" + //If minimum target for this compilation is older than Mac Os Lion, then we are out of luck + #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 + #define BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED + #endif + #endif + #endif + + //If buggy _POSIX_THREAD_PROCESS_SHARED is detected avoid using it + #if defined(BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED) + #undef BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED + #else + #define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED + #endif + #endif + + ////////////////////////////////////////////////////// + // _POSIX_SHARED_MEMORY_OBJECTS (POSIX.1b/POSIX.4) + ////////////////////////////////////////////////////// + #if ( defined(_POSIX_SHARED_MEMORY_OBJECTS) && ((_POSIX_SHARED_MEMORY_OBJECTS + 0) > 0) ) ||\ + (defined(__vms) && __CRTL_VER >= 70200000) + #define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + //Some systems have filesystem-based resources, so the + //portable "/shmname" format does not work due to permission issues + //For those systems we need to form a path to a temporary directory: + // hp-ux tru64 vms freebsd + #if defined(__hpux) || defined(__osf__) || defined(__vms) || (defined(__FreeBSD__) && (__FreeBSD__ < 7)) + #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY + //Some systems have "jailed" environments where shm usage is restricted at runtime + //and temporary file based shm is possible in those executions. + #elif defined(__FreeBSD__) + #define BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY + #endif + #endif + + ////////////////////////////////////////////////////// + // _POSIX_MAPPED_FILES (POSIX.1b/POSIX.4) + ////////////////////////////////////////////////////// + #if defined(_POSIX_MAPPED_FILES) && ((_POSIX_MAPPED_FILES + 0) > 0) + #define BOOST_INTERPROCESS_POSIX_MAPPED_FILES + #endif + + ////////////////////////////////////////////////////// + // _POSIX_SEMAPHORES (POSIX.1b/POSIX.4) + ////////////////////////////////////////////////////// + #if ( defined(_POSIX_SEMAPHORES) && ((_POSIX_SEMAPHORES + 0) > 0) ) ||\ + ( defined(__FreeBSD__) && (__FreeBSD__ >= 4)) || \ + defined(__APPLE__) + #define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + //MacOsX declares _POSIX_SEMAPHORES but sem_init returns ENOSYS + #if !defined(__APPLE__) + #define BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES + #endif + #if defined(__osf__) || defined(__vms) + #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES + #endif + #endif + + ////////////////////////////////////////////////////// + // _POSIX_BARRIERS (SUSv3/Unix03) + ////////////////////////////////////////////////////// + #if defined(_POSIX_BARRIERS) && ((_POSIX_BARRIERS + 0) >= 200112L) + #define BOOST_INTERPROCESS_POSIX_BARRIERS + #endif + + ////////////////////////////////////////////////////// + // _POSIX_TIMEOUTS (SUSv3/Unix03) + ////////////////////////////////////////////////////// + #if defined(_POSIX_TIMEOUTS) && ((_POSIX_TIMEOUTS + 0L) >= 200112L) + #define BOOST_INTERPROCESS_POSIX_TIMEOUTS + #endif + + ////////////////////////////////////////////////////// + // Detect BSD derivatives to detect sysctl + ////////////////////////////////////////////////////// + #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) + #define BOOST_INTERPROCESS_BSD_DERIVATIVE + //Some *BSD systems (OpenBSD & NetBSD) need sys/param.h before sys/sysctl.h, whereas + //others (FreeBSD & Darwin) need sys/types.h + #include + #include + #include + #if defined(CTL_KERN) && defined (KERN_BOOTTIME) + //#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME + #endif + #endif + + ////////////////////////////////////////////////////// + //64 bit offset + ////////////////////////////////////////////////////// + #if (defined (_V6_ILP32_OFFBIG) &&(_V6_ILP32_OFFBIG - 0 > 0)) ||\ + (defined (_V6_LP64_OFF64) &&(_V6_LP64_OFF64 - 0 > 0)) ||\ + (defined (_V6_LPBIG_OFFBIG) &&(_V6_LPBIG_OFFBIG - 0 > 0)) ||\ + (defined (_XBS5_ILP32_OFFBIG)&&(_XBS5_ILP32_OFFBIG - 0 > 0)) ||\ + (defined (_XBS5_LP64_OFF64) &&(_XBS5_LP64_OFF64 - 0 > 0)) ||\ + (defined (_XBS5_LPBIG_OFFBIG)&&(_XBS5_LPBIG_OFFBIG - 0 > 0)) ||\ + (defined (_FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64))||\ + (defined (_FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64)) + #define BOOST_INTERPROCESS_UNIX_64_BIT_OR_BIGGER_OFF_T + #endif +#endif //!defined(BOOST_INTERPROCESS_WINDOWS) + +#if defined(BOOST_INTERPROCESS_WINDOWS) || defined(BOOST_INTERPROCESS_POSIX_MAPPED_FILES) +# define BOOST_INTERPROCESS_MAPPED_FILES +#endif + +//Now declare some Boost.Interprocess features depending on the implementation +#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) + #define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES + #define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES +#endif + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + #define BOOST_INTERPROCESS_PERFECT_FORWARDING +#endif + +// Timeout duration use if BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING is set +#ifndef BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS + #define BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS 10000 +#endif + +//Other switches +//BOOST_INTERPROCESS_MSG_QUEUE_USES_CIRC_INDEX +//message queue uses a circular queue as index instead of an array (better performance) +//Boost version < 1.52 uses an array, so undef this if you want to communicate +//with processes compiled with those versions. +#define BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + +//Macros for documentation purposes. For code, expands to the argument +#define BOOST_INTERPROCESS_IMPDEF(TYPE) TYPE +#define BOOST_INTERPROCESS_SEEDOC(TYPE) TYPE +#define BOOST_INTERPROCESS_DOC1ST(TYPE1, TYPE2) TYPE2 +#define BOOST_INTERPROCESS_I , +#define BOOST_INTERPROCESS_DOCIGN(T1) T1 + +//#define BOOST_INTERPROCESS_DISABLE_FORCEINLINE + +#if defined(BOOST_INTERPROCESS_DISABLE_FORCEINLINE) + #define BOOST_INTERPROCESS_FORCEINLINE inline +#elif defined(BOOST_INTERPROCESS_FORCEINLINE_IS_BOOST_FORCELINE) + #define BOOST_INTERPROCESS_FORCEINLINE BOOST_FORCEINLINE +#elif defined(BOOST_MSVC) && defined(_DEBUG) + //"__forceinline" and MSVC seems to have some bugs in debug mode + #define BOOST_INTERPROCESS_FORCEINLINE inline +#else + #define BOOST_INTERPROCESS_FORCEINLINE BOOST_FORCEINLINE +#endif + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP diff --git a/libraries/boost/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp b/libraries/boost/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp new file mode 100644 index 000000000..b1fe44928 --- /dev/null +++ b/libraries/boost/boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp @@ -0,0 +1,88 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP +#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#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 +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + xsi_shared_memory_file_wrapper() : xsi_shared_memory() {} + + xsi_shared_memory_file_wrapper(create_only_t, const xsi_key &key, mode_t , std::size_t size, const permissions& perm = permissions()) + : xsi_shared_memory(create_only_t(), key, size, perm.get_permissions()) + {} + + xsi_shared_memory_file_wrapper(open_or_create_t, const xsi_key &key, mode_t , std::size_t size, const permissions& perm = permissions()) + : xsi_shared_memory(open_or_create_t(), key, size, perm.get_permissions()) + {} + + xsi_shared_memory_file_wrapper(open_only_t, const xsi_key &key, mode_t, const permissions& = permissions()) + : xsi_shared_memory(open_only_t(), key) + {} + + xsi_shared_memory_file_wrapper(BOOST_RV_REF(xsi_shared_memory_file_wrapper) moved) + { this->swap(moved); } + + xsi_shared_memory_file_wrapper &operator=(BOOST_RV_REF(xsi_shared_memory_file_wrapper) moved) + { + xsi_shared_memory_file_wrapper tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps two xsi_shared_memory_file_wrapper. Does not throw + void swap(xsi_shared_memory_file_wrapper &other) + { this->xsi_shared_memory::swap(other); } +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP diff --git a/libraries/boost/boost/interprocess/errors.hpp b/libraries/boost/boost/interprocess/errors.hpp new file mode 100644 index 000000000..46dc417a5 --- /dev/null +++ b/libraries/boost/boost/interprocess/errors.hpp @@ -0,0 +1,241 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +// Parts of this code are taken from boost::filesystem library +// +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 Beman Dawes +// Copyright (C) 2001 Dietmar Kuehl +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy +// at http://www.boost.org/LICENSE_1_0.txt) +// +// See library home page at http://www.boost.org/libs/filesystem +// +////////////////////////////////////////////////////////////////////////////// + + +#ifndef BOOST_INTERPROCESS_ERRORS_HPP +#define BOOST_INTERPROCESS_ERRORS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include + +#if defined (BOOST_INTERPROCESS_WINDOWS) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include //Errors +# include //strerror +# else //ifdef BOOST_HAS_UNISTD_H +# error Unknown platform +# endif //ifdef BOOST_HAS_UNISTD_H +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) + +//!\file +//!Describes the error numbering of interprocess classes + +namespace boost { +namespace interprocess { +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +inline int system_error_code() // artifact of POSIX and WINDOWS error reporting +{ + #if defined (BOOST_INTERPROCESS_WINDOWS) + return winapi::get_last_error(); + #else + return errno; // GCC 3.1 won't accept ::errno + #endif +} + + +#if defined (BOOST_INTERPROCESS_WINDOWS) +inline void fill_system_message(int sys_err_code, std::string &str) +{ + void *lpMsgBuf; + winapi::format_message( + winapi::format_message_allocate_buffer | + winapi::format_message_from_system | + winapi::format_message_ignore_inserts, + 0, + sys_err_code, + winapi::make_lang_id(winapi::lang_neutral, winapi::sublang_default), // Default language + reinterpret_cast(&lpMsgBuf), + 0, + 0 + ); + str += static_cast(lpMsgBuf); + winapi::local_free( lpMsgBuf ); // free the buffer + while ( str.size() + && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') ) + str.erase( str.size()-1 ); +} +# else +inline void fill_system_message( int system_error, std::string &str) +{ str = std::strerror(system_error); } +# endif +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +enum error_code_t +{ + no_error = 0, + system_error, // system generated error; if possible, is translated + // to one of the more specific errors below. + other_error, // library generated error + security_error, // includes access rights, permissions failures + read_only_error, + io_error, + path_error, + not_found_error, +// not_directory_error, + busy_error, // implies trying again might succeed + already_exists_error, + not_empty_error, + is_directory_error, + out_of_space_error, + out_of_memory_error, + out_of_resource_error, + lock_error, + sem_error, + mode_error, + size_error, + corrupted_error, + not_such_file_or_directory, + invalid_argument, + timeout_when_locking_error, + timeout_when_waiting_error, + owner_dead_error +}; + +typedef int native_error_t; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +struct ec_xlate +{ + native_error_t sys_ec; + error_code_t ec; +}; + +static const ec_xlate ec_table[] = +{ + #if defined (BOOST_INTERPROCESS_WINDOWS) + { /*ERROR_ACCESS_DENIED*/5L, security_error }, + { /*ERROR_INVALID_ACCESS*/12L, security_error }, + { /*ERROR_SHARING_VIOLATION*/32L, security_error }, + { /*ERROR_LOCK_VIOLATION*/33L, security_error }, + { /*ERROR_LOCKED*/212L, security_error }, + { /*ERROR_NOACCESS*/998L, security_error }, + { /*ERROR_WRITE_PROTECT*/19L, read_only_error }, + { /*ERROR_NOT_READY*/21L, io_error }, + { /*ERROR_SEEK*/25L, io_error }, + { /*ERROR_READ_FAULT*/30L, io_error }, + { /*ERROR_WRITE_FAULT*/29L, io_error }, + { /*ERROR_CANTOPEN*/1011L, io_error }, + { /*ERROR_CANTREAD*/1012L, io_error }, + { /*ERROR_CANTWRITE*/1013L, io_error }, + { /*ERROR_DIRECTORY*/267L, path_error }, + { /*ERROR_INVALID_NAME*/123L, path_error }, + { /*ERROR_FILE_NOT_FOUND*/2L, not_found_error }, + { /*ERROR_PATH_NOT_FOUND*/3L, not_found_error }, + { /*ERROR_DEV_NOT_EXIST*/55L, not_found_error }, + { /*ERROR_DEVICE_IN_USE*/2404L, busy_error }, + { /*ERROR_OPEN_FILES*/2401L, busy_error }, + { /*ERROR_BUSY_DRIVE*/142L, busy_error }, + { /*ERROR_BUSY*/170L, busy_error }, + { /*ERROR_FILE_EXISTS*/80L, already_exists_error }, + { /*ERROR_ALREADY_EXISTS*/183L, already_exists_error }, + { /*ERROR_DIR_NOT_EMPTY*/145L, not_empty_error }, + { /*ERROR_HANDLE_DISK_FULL*/39L, out_of_space_error }, + { /*ERROR_DISK_FULL*/112L, out_of_space_error }, + { /*ERROR_OUTOFMEMORY*/14L, out_of_memory_error }, + { /*ERROR_NOT_ENOUGH_MEMORY*/8L, out_of_memory_error }, + { /*ERROR_TOO_MANY_OPEN_FILES*/4L, out_of_resource_error }, + { /*ERROR_INVALID_ADDRESS*/487L, busy_error } + #else //#if defined (BOOST_INTERPROCESS_WINDOWS) + { EACCES, security_error }, + { EROFS, read_only_error }, + { EIO, io_error }, + { ENAMETOOLONG, path_error }, + { ENOENT, not_found_error }, + // { ENOTDIR, not_directory_error }, + { EAGAIN, busy_error }, + { EBUSY, busy_error }, + { ETXTBSY, busy_error }, + { EEXIST, already_exists_error }, + { ENOTEMPTY, not_empty_error }, + { EISDIR, is_directory_error }, + { ENOSPC, out_of_space_error }, + { ENOMEM, out_of_memory_error }, + { EMFILE, out_of_resource_error }, + { ENOENT, not_such_file_or_directory }, + { EINVAL, invalid_argument } + #endif //#if defined (BOOST_INTERPROCESS_WINDOWS) +}; + +inline error_code_t lookup_error(native_error_t err) +{ + const ec_xlate *cur = &ec_table[0], + *end = cur + sizeof(ec_table)/sizeof(ec_xlate); + for (;cur != end; ++cur ){ + if ( err == cur->sys_ec ) return cur->ec; + } + return system_error; // general system error code +} + +struct error_info +{ + error_info(error_code_t ec = other_error ) + : m_nat(0), m_ec(ec) + {} + + error_info(native_error_t sys_err_code) + : m_nat(sys_err_code), m_ec(lookup_error(sys_err_code)) + {} + + error_info & operator =(error_code_t ec) + { + m_nat = 0; + m_ec = ec; + return *this; + } + + error_info & operator =(native_error_t sys_err_code) + { + m_nat = sys_err_code; + m_ec = lookup_error(sys_err_code); + return *this; + } + + native_error_t get_native_error()const + { return m_nat; } + + error_code_t get_error_code()const + { return m_ec; } + + private: + native_error_t m_nat; + error_code_t m_ec; +}; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} // namespace interprocess { +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_ERRORS_HPP diff --git a/libraries/boost/boost/interprocess/exceptions.hpp b/libraries/boost/boost/interprocess/exceptions.hpp new file mode 100644 index 000000000..700c4c503 --- /dev/null +++ b/libraries/boost/boost/interprocess/exceptions.hpp @@ -0,0 +1,110 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_EXCEPTIONS_HPP +#define BOOST_INTERPROCESS_EXCEPTIONS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include + +//!\file +//!Describes exceptions thrown by interprocess classes + +namespace boost { + +namespace interprocess { + +//!This class is the base class of all exceptions +//!thrown by boost::interprocess +class BOOST_SYMBOL_VISIBLE interprocess_exception : public std::exception +{ + public: + interprocess_exception(const char *err) + : m_err(other_error) + { + try { m_str = err; } + catch (...) {} + } + + interprocess_exception(const error_info &err_info, const char *str = 0) + : m_err(err_info) + { + try{ + if(m_err.get_native_error() != 0){ + fill_system_message(m_err.get_native_error(), m_str); + } + else if(str){ + m_str = str; + } + else{ + m_str = "boost::interprocess_exception::library_error"; + } + } + catch(...){} + } + + virtual ~interprocess_exception() throw(){} + + virtual const char * what() const throw() + { return m_str.c_str(); } + + native_error_t get_native_error()const { return m_err.get_native_error(); } + + // Note: a value of other_error implies a library (rather than system) error + error_code_t get_error_code() const { return m_err.get_error_code(); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + error_info m_err; + std::string m_str; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!This is the exception thrown by shared interprocess_mutex family when a deadlock situation +//!is detected or when using a interprocess_condition the interprocess_mutex is not locked +class BOOST_SYMBOL_VISIBLE lock_exception : public interprocess_exception +{ + public: + lock_exception() + : interprocess_exception(lock_error) + {} + + virtual const char* what() const throw() + { return "boost::interprocess::lock_exception"; } +}; + + +//!This exception is thrown when a memory request can't be +//!fulfilled. +class BOOST_SYMBOL_VISIBLE bad_alloc : public interprocess_exception +{ + public: + bad_alloc() : interprocess_exception("::boost::interprocess::bad_alloc"){} + virtual const char* what() const throw() + { return "boost::interprocess::bad_alloc"; } +}; + +} // namespace interprocess { + +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_EXCEPTIONS_HPP diff --git a/libraries/boost/boost/interprocess/file_mapping.hpp b/libraries/boost/boost/interprocess/file_mapping.hpp new file mode 100644 index 000000000..0d1cf1fe4 --- /dev/null +++ b/libraries/boost/boost/interprocess/file_mapping.hpp @@ -0,0 +1,199 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_FILE_MAPPING_HPP +#define BOOST_INTERPROCESS_FILE_MAPPING_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#if !defined(BOOST_INTERPROCESS_MAPPED_FILES) +#error "Boost.Interprocess: This platform does not support memory mapped files!" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include //std::string + +//!\file +//!Describes file_mapping and mapped region classes + +namespace boost { +namespace interprocess { + +//!A class that wraps a file-mapping that can be used to +//!create mapped regions from the mapped files +class file_mapping +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + BOOST_MOVABLE_BUT_NOT_COPYABLE(file_mapping) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructs an empty file mapping. + //!Does not throw + file_mapping(); + + //!Opens a file mapping of file "filename", starting in offset + //!"file_offset", and the mapping's size will be "size". The mapping + //!can be opened for read-only "read_only" or read-write "read_write" + //!modes. Throws interprocess_exception on error. + file_mapping(const char *filename, mode_t mode); + + //!Moves the ownership of "moved"'s file mapping object to *this. + //!After the call, "moved" does not represent any file mapping object. + //!Does not throw + file_mapping(BOOST_RV_REF(file_mapping) moved) + : m_handle(file_handle_t(ipcdetail::invalid_file())) + , m_mode(read_only) + { this->swap(moved); } + + //!Moves the ownership of "moved"'s file mapping to *this. + //!After the call, "moved" does not represent any file mapping. + //!Does not throw + file_mapping &operator=(BOOST_RV_REF(file_mapping) moved) + { + file_mapping tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps to file_mappings. + //!Does not throw. + void swap(file_mapping &other); + + //!Returns access mode + //!used in the constructor + mode_t get_mode() const; + + //!Obtains the mapping handle + //!to be used with mapped_region + mapping_handle_t get_mapping_handle() const; + + //!Destroys the file mapping. All mapped regions created from this are still + //!valid. Does not throw + ~file_mapping(); + + //!Returns the name of the file + //!used in the constructor. + const char *get_name() const; + + //!Removes the file named "filename" even if it's been memory mapped. + //!Returns true on success. + //!The function might fail in some operating systems if the file is + //!being used other processes and no deletion permission was shared. + static bool remove(const char *filename); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + //!Closes a previously opened file mapping. Never throws. + void priv_close(); + file_handle_t m_handle; + mode_t m_mode; + std::string m_filename; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +inline file_mapping::file_mapping() + : m_handle(file_handle_t(ipcdetail::invalid_file())) + , m_mode(read_only) +{} + +inline file_mapping::~file_mapping() +{ this->priv_close(); } + +inline const char *file_mapping::get_name() const +{ return m_filename.c_str(); } + +inline void file_mapping::swap(file_mapping &other) +{ + (simple_swap)(m_handle, other.m_handle); + (simple_swap)(m_mode, other.m_mode); + m_filename.swap(other.m_filename); +} + +inline mapping_handle_t file_mapping::get_mapping_handle() const +{ return ipcdetail::mapping_handle_from_file_handle(m_handle); } + +inline mode_t file_mapping::get_mode() const +{ return m_mode; } + +inline file_mapping::file_mapping + (const char *filename, mode_t mode) + : m_filename(filename) +{ + //Check accesses + if (mode != read_write && mode != read_only){ + error_info err = other_error; + throw interprocess_exception(err); + } + + //Open file + m_handle = ipcdetail::open_existing_file(filename, mode); + + //Check for error + if(m_handle == ipcdetail::invalid_file()){ + error_info err = system_error_code(); + this->priv_close(); + throw interprocess_exception(err); + } + m_mode = mode; +} + +inline bool file_mapping::remove(const char *filename) +{ return ipcdetail::delete_file(filename); } + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline void file_mapping::priv_close() +{ + if(m_handle != ipcdetail::invalid_file()){ + ipcdetail::close_file(m_handle); + m_handle = ipcdetail::invalid_file(); + } +} + +//!A class that stores the name of a file +//!and tries to remove it in its destructor +//!Useful to remove temporary files in the presence +//!of exceptions +class remove_file_on_destroy +{ + const char * m_name; + public: + remove_file_on_destroy(const char *name) + : m_name(name) + {} + + ~remove_file_on_destroy() + { ipcdetail::delete_file(m_name); } +}; + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_FILE_MAPPING_HPP diff --git a/libraries/boost/boost/interprocess/indexes/flat_map_index.hpp b/libraries/boost/boost/interprocess/indexes/flat_map_index.hpp new file mode 100644 index 000000000..027b75be4 --- /dev/null +++ b/libraries/boost/boost/interprocess/indexes/flat_map_index.hpp @@ -0,0 +1,93 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_FLAT_MAP_INDEX_HPP +#define BOOST_INTERPROCESS_FLAT_MAP_INDEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +// interprocess +#include +#include +// intrusive/detail +#include //std::pair +#include //std::less + + +//!\file +//!Describes index adaptor of boost::map container, to use it +//!as name/shared memory index + +//[flat_map_index +namespace boost { namespace interprocess { + +#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Helper class to define typedefs from IndexTraits +template +struct flat_map_index_aux +{ + typedef typename MapConfig::key_type key_type; + typedef typename MapConfig::mapped_type mapped_type; + typedef typename MapConfig:: + segment_manager_base segment_manager_base; + typedef std::less key_less; + typedef std::pair value_type; + typedef allocator allocator_type; + typedef flat_map index_t; +}; + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Index type based in flat_map. Just derives from flat_map and +//!defines the interface needed by managed memory segments. +template +class flat_map_index + //Derive class from flat_map specialization + : public flat_map_index_aux::index_t +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef flat_map_index_aux index_aux; + typedef typename index_aux::index_t base_type; + typedef typename index_aux:: + segment_manager_base segment_manager_base; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. Takes a pointer to the segment manager. Can throw + flat_map_index(segment_manager_base *segment_mngr) + : base_type(typename index_aux::key_less(), + typename index_aux::allocator_type(segment_mngr)) + {} + + //!This reserves memory to optimize the insertion of n elements in the index + void reserve(typename segment_manager_base::size_type n) + { base_type::reserve(n); } + + //!This frees all unnecessary memory + void shrink_to_fit() + { base_type::shrink_to_fit(); } +}; + +}} //namespace boost { namespace interprocess +//] +#include + +#endif //#ifndef BOOST_INTERPROCESS_FLAT_MAP_INDEX_HPP diff --git a/libraries/boost/boost/interprocess/indexes/iset_index.hpp b/libraries/boost/boost/interprocess/indexes/iset_index.hpp new file mode 100644 index 000000000..ffaa24fa7 --- /dev/null +++ b/libraries/boost/boost/interprocess/indexes/iset_index.hpp @@ -0,0 +1,158 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_ISET_INDEX_HPP +#define BOOST_INTERPROCESS_ISET_INDEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include //std::pair +#include //std::less +#include //std::char_traits +#include + +//!\file +//!Describes index adaptor of boost::intrusive::set container, to use it +//!as name/shared memory index + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +//!Helper class to define typedefs from IndexTraits +template +struct iset_index_aux +{ + typedef typename + MapConfig::segment_manager_base segment_manager_base; + + typedef typename + segment_manager_base::void_pointer void_pointer; + typedef typename bi::make_set_base_hook + < bi::void_pointer + , bi::optimize_size + >::type derivation_hook; + + typedef typename MapConfig::template + intrusive_value_type::type value_type; + typedef std::less value_compare; + typedef typename bi::make_set + < value_type + , bi::base_hook + >::type index_t; +}; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Index type based in boost::intrusive::set. +//!Just derives from boost::intrusive::set +//!and defines the interface needed by managed memory segments*/ +template +class iset_index + //Derive class from map specialization + : public iset_index_aux::index_t +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef iset_index_aux index_aux; + typedef typename index_aux::index_t index_type; + typedef typename MapConfig:: + intrusive_compare_key_type intrusive_compare_key_type; + typedef typename MapConfig::char_type char_type; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef typename index_type::iterator iterator; + typedef typename index_type::const_iterator const_iterator; + typedef typename index_type::insert_commit_data insert_commit_data; + typedef typename index_type::value_type value_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + + struct intrusive_key_value_less + { + bool operator()(const intrusive_compare_key_type &i, const value_type &b) const + { + std::size_t blen = b.name_length(); + return (i.m_len < blen) || + (i.m_len == blen && + std::char_traits::compare + (i.mp_str, b.name(), i.m_len) < 0); + } + + bool operator()(const value_type &b, const intrusive_compare_key_type &i) const + { + std::size_t blen = b.name_length(); + return (blen < i.m_len) || + (blen == i.m_len && + std::char_traits::compare + (b.name(), i.mp_str, i.m_len) < 0); + } + }; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + + //!Constructor. Takes a pointer to the + //!segment manager. Can throw + iset_index(typename MapConfig::segment_manager_base *) + : index_type(/*typename index_aux::value_compare()*/) + {} + + //!This reserves memory to optimize the insertion of n + //!elements in the index + void reserve(typename MapConfig::segment_manager_base::size_type) + { /*Does nothing, map has not reserve or rehash*/ } + + //!This frees all unnecessary memory + void shrink_to_fit() + { /*Does nothing, this intrusive index does not allocate memory;*/ } + + iterator find(const intrusive_compare_key_type &key) + { return index_type::find(key, intrusive_key_value_less()); } + + const_iterator find(const intrusive_compare_key_type &key) const + { return index_type::find(key, intrusive_key_value_less()); } + + std::pairinsert_check + (const intrusive_compare_key_type &key, insert_commit_data &commit_data) + { return index_type::insert_check(key, intrusive_key_value_less(), commit_data); } +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +//!Trait class to detect if an index is an intrusive +//!index. +template +struct is_intrusive_index + > +{ + static const bool value = true; +}; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost + +#include + +#endif //#ifndef BOOST_INTERPROCESS_ISET_INDEX_HPP diff --git a/libraries/boost/boost/interprocess/indexes/iunordered_set_index.hpp b/libraries/boost/boost/interprocess/indexes/iunordered_set_index.hpp new file mode 100644 index 000000000..6cd1452f6 --- /dev/null +++ b/libraries/boost/boost/interprocess/indexes/iunordered_set_index.hpp @@ -0,0 +1,376 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP +#define BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include //std::less +#include //std::char_traits +#include + +//!\file +//!Describes index adaptor of boost::intrusive::unordered_set container, to use it +//!as name/shared memory index + +namespace boost { namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +//!Helper class to define typedefs +//!from IndexTraits +template +struct iunordered_set_index_aux +{ + typedef typename + MapConfig::segment_manager_base segment_manager_base; + + typedef typename + segment_manager_base::void_pointer void_pointer; + + typedef typename bi::make_unordered_set_base_hook + < bi::void_pointer + >::type derivation_hook; + + typedef typename MapConfig::template + intrusive_value_type::type value_type; + + typedef typename MapConfig:: + intrusive_compare_key_type intrusive_compare_key_type; + + typedef std::equal_to value_equal; + + typedef typename MapConfig::char_type char_type; + + struct equal_function + { + bool operator()(const intrusive_compare_key_type &i, const value_type &b) const + { + return (i.m_len == b.name_length()) && + (std::char_traits::compare + (i.mp_str, b.name(), i.m_len) == 0); + } + + bool operator()(const value_type &b, const intrusive_compare_key_type &i) const + { + return (i.m_len == b.name_length()) && + (std::char_traits::compare + (i.mp_str, b.name(), i.m_len) == 0); + } + + bool operator()(const value_type &b1, const value_type &b2) const + { + return (b1.name_length() == b2.name_length()) && + (std::char_traits::compare + (b1.name(), b2.name(), b1.name_length()) == 0); + } + }; + + struct hash_function + : std::unary_function + { + std::size_t operator()(const value_type &val) const + { + const char_type *beg = ipcdetail::to_raw_pointer(val.name()), + *end = beg + val.name_length(); + return boost::hash_range(beg, end); + } + + std::size_t operator()(const intrusive_compare_key_type &i) const + { + const char_type *beg = i.mp_str, + *end = beg + i.m_len; + return boost::hash_range(beg, end); + } + }; + + typedef typename bi::make_unordered_set + < value_type + , bi::hash + , bi::equal + , bi::size_type + >::type index_t; + typedef typename index_t::bucket_type bucket_type; + typedef allocator + allocator_type; + + struct allocator_holder + { + allocator_holder(segment_manager_base *mngr) + : alloc(mngr) + {} + allocator_type alloc; + bucket_type init_bucket; + }; +}; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Index type based in boost::intrusive::set. +//!Just derives from boost::intrusive::set +//!and defines the interface needed by managed memory segments +template +class iunordered_set_index + //Derive class from map specialization + : private iunordered_set_index_aux::allocator_holder + , public iunordered_set_index_aux::index_t +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef iunordered_set_index_aux index_aux; + typedef typename index_aux::index_t index_type; + typedef typename MapConfig:: + intrusive_compare_key_type intrusive_compare_key_type; + typedef typename index_aux::equal_function equal_function; + typedef typename index_aux::hash_function hash_function; + typedef typename MapConfig::char_type char_type; + typedef typename + iunordered_set_index_aux::allocator_type allocator_type; + typedef typename + iunordered_set_index_aux::allocator_holder allocator_holder; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef typename index_type::iterator iterator; + typedef typename index_type::const_iterator const_iterator; + typedef typename index_type::insert_commit_data insert_commit_data; + typedef typename index_type::value_type value_type; + typedef typename index_type::bucket_ptr bucket_ptr; + typedef typename index_type::bucket_type bucket_type; + typedef typename index_type::bucket_traits bucket_traits; + typedef typename index_type::size_type size_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef typename index_aux:: + segment_manager_base segment_manager_base; + + static const std::size_t InitBufferSize = 64; + + static bucket_ptr create_buckets(allocator_type &alloc, size_type num) + { + num = index_type::suggested_upper_bucket_count(num); + bucket_ptr buckets = alloc.allocate(num); + bucket_ptr buckets_init = buckets; + for(size_type i = 0; i < num; ++i){ + ::new(to_raw_pointer(buckets_init++), boost_container_new_t())bucket_type(); + } + return buckets; + } + + static size_type shrink_buckets + ( bucket_ptr buckets, size_type old_size + , allocator_type &alloc, size_type new_size) + { + if(old_size <= new_size ) + return old_size; + size_type received_size = new_size; + if(!alloc.allocation_command + (boost::interprocess::try_shrink_in_place | boost::interprocess::nothrow_allocation, old_size, received_size, buckets)){ + return old_size; + } + + for( bucket_type *p = ipcdetail::to_raw_pointer(buckets) + received_size + , *pend = ipcdetail::to_raw_pointer(buckets) + old_size + ; p != pend + ; ++p){ + p->~bucket_type(); + } + + bucket_ptr shunk_p = alloc.allocation_command + (boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_size, received_size, buckets); + BOOST_ASSERT(buckets == shunk_p); (void)shunk_p; + + bucket_ptr buckets_init = buckets + received_size; + for(size_type i = 0; i < (old_size - received_size); ++i){ + to_raw_pointer(buckets_init++)->~bucket_type(); + } + return received_size; + } + + static bucket_ptr expand_or_create_buckets + ( bucket_ptr old_buckets, const size_type old_num + , allocator_type &alloc, const size_type new_num) + { + size_type received_size = new_num; + bucket_ptr reuse(old_buckets); + bucket_ptr ret = alloc.allocation_command + (boost::interprocess::expand_fwd | boost::interprocess::allocate_new, new_num, received_size, reuse); + if(ret == old_buckets){ + bucket_ptr buckets_init = old_buckets + old_num; + for(size_type i = 0; i < (new_num - old_num); ++i){ + ::new(to_raw_pointer(buckets_init++), boost_container_new_t())bucket_type(); + } + } + else{ + bucket_ptr buckets_init = ret; + for(size_type i = 0; i < new_num; ++i){ + ::new(to_raw_pointer(buckets_init++), boost_container_new_t())bucket_type(); + } + } + return ret; + } + + static void destroy_buckets + (allocator_type &alloc, bucket_ptr buckets, size_type num) + { + bucket_ptr buckets_destroy = buckets; + for(size_type i = 0; i < num; ++i){ + to_raw_pointer(buckets_destroy++)->~bucket_type(); + } + alloc.deallocate(buckets, num); + } + + iunordered_set_index* get_this_pointer() + { return this; } + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. Takes a pointer to the + //!segment manager. Can throw + iunordered_set_index(segment_manager_base *mngr) + : allocator_holder(mngr) + , index_type(bucket_traits(&get_this_pointer()->init_bucket, 1)) + {} + + ~iunordered_set_index() + { + index_type::clear(); + if(index_type::bucket_pointer() != bucket_ptr(&this->init_bucket)){ + destroy_buckets(this->alloc, index_type::bucket_pointer(), index_type::bucket_count()); + } + } + + //!This reserves memory to optimize the insertion of n + //!elements in the index + void reserve(size_type new_n) + { + //Let's maintain a 1.0f load factor + size_type old_n = this->bucket_count(); + if(new_n <= old_n) + return; + bucket_ptr old_p = this->bucket_pointer(); + new_n = index_type::suggested_upper_bucket_count(new_n); + bucket_ptr new_p; + //This can throw + try{ + if(old_p != bucket_ptr(&this->init_bucket)) + new_p = expand_or_create_buckets(old_p, old_n, this->alloc, new_n); + else + new_p = create_buckets(this->alloc, new_n); + } + catch(...){ + return; + } + //Rehashing does not throw, since neither the hash nor the + //comparison function can throw + this->rehash(bucket_traits(new_p, new_n)); + if(new_p != old_p && old_p != bucket_ptr(&this->init_bucket)){ + destroy_buckets(this->alloc, old_p, old_n); + } + } + + //!This tries to free unused memory + //!previously allocated. + void shrink_to_fit() + { + size_type cur_size = this->size(); + size_type cur_count = this->bucket_count(); + bucket_ptr old_p = this->bucket_pointer(); + + if(!this->size() && old_p != bucket_ptr(&this->init_bucket)){ + this->rehash(bucket_traits(bucket_ptr(&this->init_bucket), 1)); + destroy_buckets(this->alloc, old_p, cur_count); + } + else{ + size_type sug_count = 0; //gcc warning + sug_count = index_type::suggested_upper_bucket_count(cur_size); + + if(sug_count >= cur_count) + return; + + try{ + shrink_buckets(old_p, cur_count, this->alloc, sug_count); + } + catch(...){ + return; + } + + //Rehashing does not throw, since neither the hash nor the + //comparison function can throw + this->rehash(bucket_traits(old_p, sug_count)); + } + } + + iterator find(const intrusive_compare_key_type &key) + { return index_type::find(key, hash_function(), equal_function()); } + + const_iterator find(const intrusive_compare_key_type &key) const + { return index_type::find(key, hash_function(), equal_function()); } + + std::pairinsert_check + (const intrusive_compare_key_type &key, insert_commit_data &commit_data) + { return index_type::insert_check(key, hash_function(), equal_function(), commit_data); } + + iterator insert_commit(value_type &val, insert_commit_data &commit_data) + { + iterator it = index_type::insert_commit(val, commit_data); + size_type cur_size = this->size(); + if(cur_size > this->bucket_count()){ + try{ + this->reserve(cur_size); + } + catch(...){ + //Strong guarantee: if something goes wrong + //we should remove the insertion. + // + //We can use the iterator because the hash function + //can't throw and this means that "reserve" will + //throw only because of the memory allocation: + //the iterator has not been invalidated. + index_type::erase(it); + throw; + } + } + return it; + } +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +//!Trait class to detect if an index is an intrusive +//!index +template +struct is_intrusive_index + > +{ + static const bool value = true; +}; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP diff --git a/libraries/boost/boost/interprocess/indexes/map_index.hpp b/libraries/boost/boost/interprocess/indexes/map_index.hpp new file mode 100644 index 000000000..c7c3c865d --- /dev/null +++ b/libraries/boost/boost/interprocess/indexes/map_index.hpp @@ -0,0 +1,109 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MAP_INDEX_HPP +#define BOOST_INTERPROCESS_MAP_INDEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include //std::pair +#include //std::less + +//!\file +//!Describes index adaptor of boost::map container, to use it +//!as name/shared memory index + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +//!Helper class to define typedefs from IndexTraits +template +struct map_index_aux +{ + typedef typename MapConfig::key_type key_type; + typedef typename MapConfig::mapped_type mapped_type; + typedef std::less key_less; + typedef std::pair value_type; + + typedef private_adaptive_pool + allocator_type; + + typedef boost::interprocess::map + index_t; +}; + +} //namespace ipcdetail { + +//!Index type based in boost::interprocess::map. Just derives from boost::interprocess::map +//!and defines the interface needed by managed memory segments +template +class map_index + //Derive class from map specialization + : public ipcdetail::map_index_aux::index_t +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef ipcdetail::map_index_aux index_aux; + typedef typename index_aux::index_t base_type; + typedef typename MapConfig:: + segment_manager_base segment_manager_base; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. Takes a pointer to the + //!segment manager. Can throw + map_index(segment_manager_base *segment_mngr) + : base_type(typename index_aux::key_less(), + segment_mngr){} + + //!This reserves memory to optimize the insertion of n + //!elements in the index + void reserve(typename segment_manager_base::size_type) + { /*Does nothing, map has not reserve or rehash*/ } + + //!This tries to free previously allocate + //!unused memory. + void shrink_to_fit() + { base_type::get_stored_allocator().deallocate_free_blocks(); } +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +//!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 = true; +}; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MAP_INDEX_HPP diff --git a/libraries/boost/boost/interprocess/indexes/null_index.hpp b/libraries/boost/boost/interprocess/indexes/null_index.hpp new file mode 100644 index 000000000..ed4797f8f --- /dev/null +++ b/libraries/boost/boost/interprocess/indexes/null_index.hpp @@ -0,0 +1,76 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_NULL_INDEX_HPP +#define BOOST_INTERPROCESS_NULL_INDEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +//!\file +//!Describes a null index adaptor, so that if we don't want to construct +//!named objects, we can use this null index type to save resources. + +namespace boost { +namespace interprocess { + +//!Null index type +//!used to save compilation time when +//!named indexes are not needed. +template +class null_index +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef typename MapConfig:: + segment_manager_base segment_manager_base; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef int * iterator; + typedef const int * const_iterator; + + //!begin() is equal + //!to end() + const_iterator begin() const + { return const_iterator(0); } + + //!begin() is equal + //!to end() + iterator begin() + { return iterator(0); } + + //!begin() is equal + //!to end() + const_iterator end() const + { return const_iterator(0); } + + //!begin() is equal + //!to end() + iterator end() + { return iterator(0); } + + //!Empty constructor + null_index(segment_manager_base *){} +}; + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_NULL_INDEX_HPP diff --git a/libraries/boost/boost/interprocess/indexes/unordered_map_index.hpp b/libraries/boost/boost/interprocess/indexes/unordered_map_index.hpp new file mode 100644 index 000000000..6a5ad5ddb --- /dev/null +++ b/libraries/boost/boost/interprocess/indexes/unordered_map_index.hpp @@ -0,0 +1,124 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_UNORDERED_MAP_INDEX_HPP +#define BOOST_INTERPROCESS_UNORDERED_MAP_INDEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#include //std::pair +#include //std::less + +//!\file +//!Describes index adaptor of boost::unordered_map container, to use it +//!as name/shared memory index + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +//!Helper class to define typedefs from +//!IndexTraits +template +struct unordered_map_index_aux +{ + typedef typename MapConfig::key_type key_type; + typedef typename MapConfig::mapped_type mapped_type; + typedef std::equal_to key_equal; + typedef std::pair value_type; + typedef private_adaptive_pool + allocator_type; + struct hasher + : std::unary_function + { + std::size_t operator()(const key_type &val) const + { + typedef typename key_type::char_type char_type; + const char_type *beg = ipcdetail::to_raw_pointer(val.mp_str), + *end = beg + val.m_len; + return boost::hash_range(beg, end); + } + }; + typedef unordered_map index_t; +}; + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Index type based in unordered_map. Just derives from unordered_map and +//!defines the interface needed by managed memory segments +template +class unordered_map_index + //Derive class from unordered_map specialization + : public unordered_map_index_aux::index_t +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef unordered_map_index_aux index_aux; + typedef typename index_aux::index_t base_type; + typedef typename + MapConfig::segment_manager_base segment_manager_base; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. Takes a pointer to the + //!segment manager. Can throw + unordered_map_index(segment_manager_base *segment_mngr) + : base_type(0, + typename index_aux::hasher(), + typename index_aux::key_equal(), + segment_mngr){} + + //!This reserves memory to optimize the insertion of n + //!elements in the index + void reserve(typename segment_manager_base::size_type n) + { base_type::rehash(n); } + + //!This tries to free previously allocate + //!unused memory. + void shrink_to_fit() + { base_type::rehash(base_type::size()); } +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +//!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 = true; +}; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_UNORDERED_MAP_INDEX_HPP diff --git a/libraries/boost/boost/interprocess/interprocess_fwd.hpp b/libraries/boost/boost/interprocess/interprocess_fwd.hpp new file mode 100644 index 000000000..882256e93 --- /dev/null +++ b/libraries/boost/boost/interprocess/interprocess_fwd.hpp @@ -0,0 +1,516 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_FWD_HPP +#define BOOST_INTERPROCESS_FWD_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +#ifndef BOOST_CSTDINT_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include + +//! \file +//! This header file forward declares the basic interprocess types: +//! - boost::interprocess::offset_ptr; +//! - boost::interprocess::permissions; +//! - boost::interprocess::mapped_region; +//! - boost::interprocess::file_mapping; +//! - boost::interprocess::shared_memory_object; +//! - boost::interprocess::windows_shared_memory; +//! - boost::interprocess::xsi_shared_memory; +//! +//! The following synchronization mechanisms and locks: +//! - boost::interprocess::null_mutex; +//! - boost::interprocess::interprocess_mutex; +//! - boost::interprocess::interprocess_recursive_mutex; +//! - boost::interprocess::interprocess_semaphore; +//! - boost::interprocess::named_mutex; +//! - boost::interprocess::named_recursive_mutex; +//! - boost::interprocess::named_semaphore; +//! - boost::interprocess::interprocess_sharable_mutex; +//! - boost::interprocess::interprocess_condition; +//! - boost::interprocess::scoped_lock; +//! - boost::interprocess::sharable_lock; +//! - boost::interprocess::upgradable_lock; +//! +//! The following mutex families: +//! - boost::interprocess::mutex_family; +//! - boost::interprocess::null_mutex_family; +//! +//! The following allocators: +//! - boost::interprocess::allocator; +//! - boost::interprocess::node_allocator; +//! - boost::interprocess::private_node_allocator; +//! - boost::interprocess::cached_node_allocator; +//! - boost::interprocess::adaptive_pool; +//! - boost::interprocess::private_adaptive_pool; +//! - boost::interprocess::cached_adaptive_pool; +//! +//! The following allocation algorithms: +//! - boost::interprocess::simple_seq_fit; +//! - boost::interprocess::rbtree_best_fit; +//! +//! The following index types: +//! - boost::interprocess::flat_map_index; +//! - boost::interprocess::iset_index; +//! - boost::interprocess::iunordered_set_index; +//! - boost::interprocess::map_index; +//! - boost::interprocess::null_index; +//! - boost::interprocess::unordered_map_index; +//! +//! The following managed memory types: +//! - boost::interprocess::segment_manager; +//! - boost::interprocess::basic_managed_external_buffer +//! - boost::interprocess::managed_external_buffer +//! - boost::interprocess::wmanaged_external_buffer +//! - boost::interprocess::basic_managed_shared_memory +//! - boost::interprocess::managed_shared_memory +//! - boost::interprocess::wmanaged_shared_memory +//! - boost::interprocess::basic_managed_windows_shared_memory +//! - boost::interprocess::managed_windows_shared_memory +//! - boost::interprocess::wmanaged_windows_shared_memory +//! - boost::interprocess::basic_managed_xsi_shared_memory +//! - boost::interprocess::managed_xsi_shared_memory +//! - boost::interprocess::wmanaged_xsi_shared_memory +//! - boost::interprocess::fixed_managed_shared_memory +//! - boost::interprocess::wfixed_managed_shared_memory +//! - boost::interprocess::basic_managed_heap_memory +//! - boost::interprocess::managed_heap_memory +//! - boost::interprocess::wmanaged_heap_memory +//! - boost::interprocess::basic_managed_mapped_file +//! - boost::interprocess::managed_mapped_file +//! - boost::interprocess::wmanaged_mapped_file +//! +//! The following exception types: +//! - boost::interprocess::interprocess_exception +//! - boost::interprocess::lock_exception +//! - boost::interprocess::bad_alloc +//! +//! The following stream types: +//! - boost::interprocess::basic_bufferbuf +//! - boost::interprocess::basic_ibufferstream +//! - boost::interprocess::basic_obufferstream +//! - boost::interprocess::basic_bufferstream +//! - boost::interprocess::basic_vectorbuf +//! - boost::interprocess::basic_ivectorstream +//! - boost::interprocess::basic_ovectorstream +//! - boost::interprocess::basic_vectorstream +//! +//! The following smart pointer types: +//! - boost::interprocess::scoped_ptr +//! - boost::interprocess::intrusive_ptr +//! - boost::interprocess::shared_ptr +//! - boost::interprocess::weak_ptr +//! +//! The following interprocess communication types: +//! - boost::interprocess::message_queue_t; +//! - boost::interprocess::message_queue; + +#include +#include + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#include + +////////////////////////////////////////////////////////////////////////////// +// Standard predeclarations +////////////////////////////////////////////////////////////////////////////// + +namespace boost{ namespace intrusive{ } } +namespace boost{ namespace interprocess{ namespace bi = boost::intrusive; } } + +namespace boost { namespace interprocess { + +////////////////////////////////////////////////////////////////////////////// +// permissions +////////////////////////////////////////////////////////////////////////////// + +class permissions; + +////////////////////////////////////////////////////////////////////////////// +// shared_memory +////////////////////////////////////////////////////////////////////////////// + +class shared_memory_object; + +#if defined (BOOST_INTERPROCESS_WINDOWS) +class windows_shared_memory; +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) + +#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) +class xsi_shared_memory; +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) + +////////////////////////////////////////////////////////////////////////////// +// file mapping / mapped region +////////////////////////////////////////////////////////////////////////////// + +class file_mapping; +class mapped_region; + +////////////////////////////////////////////////////////////////////////////// +// Mutexes +////////////////////////////////////////////////////////////////////////////// + +class null_mutex; + +class interprocess_mutex; +class interprocess_recursive_mutex; + +class named_mutex; +class named_recursive_mutex; + +class interprocess_semaphore; +class named_semaphore; + +////////////////////////////////////////////////////////////////////////////// +// Mutex families +////////////////////////////////////////////////////////////////////////////// + +struct mutex_family; +struct null_mutex_family; + +////////////////////////////////////////////////////////////////////////////// +// Other synchronization classes +////////////////////////////////////////////////////////////////////////////// + +class interprocess_sharable_mutex; +class interprocess_condition; + +////////////////////////////////////////////////////////////////////////////// +// Locks +////////////////////////////////////////////////////////////////////////////// + +template +class scoped_lock; + +template +class sharable_lock; + +template +class upgradable_lock; + +////////////////////////////////////////////////////////////////////////////// +// STL compatible allocators +////////////////////////////////////////////////////////////////////////////// + +template +class allocator; + +template +class node_allocator; + +template +class private_node_allocator; + +template +class cached_node_allocator; + +template< class T, class SegmentManager, std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2, unsigned char OverheadPercent = 5 > +class adaptive_pool; + +template< class T, class SegmentManager, std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2, unsigned char OverheadPercent = 5 > +class private_adaptive_pool; + +template< class T, class SegmentManager, std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2, unsigned char OverheadPercent = 5 > +class cached_adaptive_pool; + + +////////////////////////////////////////////////////////////////////////////// +// offset_ptr +////////////////////////////////////////////////////////////////////////////// + +static const std::size_t offset_type_alignment = 0; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +# ifdef BOOST_HAS_INTPTR_T + using ::boost::uintptr_t; +# else + typedef std::size_t uintptr_t; +# endif +#endif + +template < class T, class DifferenceType = std::ptrdiff_t + , class OffsetType = uintptr_t, std::size_t Alignment = offset_type_alignment> +class offset_ptr; + +////////////////////////////////////////////////////////////////////////////// +// Memory allocation algorithms +////////////////////////////////////////////////////////////////////////////// + +//Single segment memory allocation algorithms +template > +class simple_seq_fit; + +template, std::size_t MemAlignment = 0> +class rbtree_best_fit; + +////////////////////////////////////////////////////////////////////////////// +// Index Types +////////////////////////////////////////////////////////////////////////////// + +template class flat_map_index; +template class iset_index; +template class iunordered_set_index; +template class map_index; +template class null_index; +template class unordered_map_index; + +////////////////////////////////////////////////////////////////////////////// +// Segment manager +////////////////////////////////////////////////////////////////////////////// + +template class IndexType> +class segment_manager; + +////////////////////////////////////////////////////////////////////////////// +// External buffer managed memory classes +////////////////////////////////////////////////////////////////////////////// + +template class IndexType> +class basic_managed_external_buffer; + +typedef basic_managed_external_buffer + + ,iset_index> +managed_external_buffer; + +typedef basic_managed_external_buffer + + ,iset_index> +wmanaged_external_buffer; + +////////////////////////////////////////////////////////////////////////////// +// managed memory classes +////////////////////////////////////////////////////////////////////////////// + +template class IndexType> +class basic_managed_shared_memory; + +typedef basic_managed_shared_memory + + ,iset_index> +managed_shared_memory; + +typedef basic_managed_shared_memory + + ,iset_index> +wmanaged_shared_memory; + + +////////////////////////////////////////////////////////////////////////////// +// Windows shared memory managed memory classes +////////////////////////////////////////////////////////////////////////////// + +#if defined (BOOST_INTERPROCESS_WINDOWS) + +template class IndexType> +class basic_managed_windows_shared_memory; + +typedef basic_managed_windows_shared_memory + + ,iset_index> +managed_windows_shared_memory; + +typedef basic_managed_windows_shared_memory + + ,iset_index> +wmanaged_windows_shared_memory; + +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) + +#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) + +template class IndexType> +class basic_managed_xsi_shared_memory; + +typedef basic_managed_xsi_shared_memory + + ,iset_index> +managed_xsi_shared_memory; + +typedef basic_managed_xsi_shared_memory + + ,iset_index> +wmanaged_xsi_shared_memory; + +#endif //#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) + +////////////////////////////////////////////////////////////////////////////// +// Fixed address shared memory +////////////////////////////////////////////////////////////////////////////// + +typedef basic_managed_shared_memory + + ,iset_index> +fixed_managed_shared_memory; + +typedef basic_managed_shared_memory + + ,iset_index> +wfixed_managed_shared_memory; + +////////////////////////////////////////////////////////////////////////////// +// Heap memory managed memory classes +////////////////////////////////////////////////////////////////////////////// + +template + class IndexType> +class basic_managed_heap_memory; + +typedef basic_managed_heap_memory + + ,iset_index> +managed_heap_memory; + +typedef basic_managed_heap_memory + + ,iset_index> +wmanaged_heap_memory; + +////////////////////////////////////////////////////////////////////////////// +// Mapped file managed memory classes +////////////////////////////////////////////////////////////////////////////// + +template + class IndexType> +class basic_managed_mapped_file; + +typedef basic_managed_mapped_file + + ,iset_index> +managed_mapped_file; + +typedef basic_managed_mapped_file + + ,iset_index> +wmanaged_mapped_file; + +////////////////////////////////////////////////////////////////////////////// +// Exceptions +////////////////////////////////////////////////////////////////////////////// + +class interprocess_exception; +class lock_exception; +class bad_alloc; + +////////////////////////////////////////////////////////////////////////////// +// Bufferstream +////////////////////////////////////////////////////////////////////////////// + +//bufferstream +template > +class basic_bufferbuf; + +template > +class basic_ibufferstream; + +template > +class basic_obufferstream; + +template > +class basic_bufferstream; + +////////////////////////////////////////////////////////////////////////////// +// Vectorstream +////////////////////////////////////////////////////////////////////////////// + +template > +class basic_vectorbuf; + +template > +class basic_ivectorstream; + +template > +class basic_ovectorstream; + +template > +class basic_vectorstream; + +////////////////////////////////////////////////////////////////////////////// +// Smart pointers +////////////////////////////////////////////////////////////////////////////// + +template +class scoped_ptr; + +template +class intrusive_ptr; + +template +class shared_ptr; + +template +class weak_ptr; + +////////////////////////////////////////////////////////////////////////////// +// IPC +////////////////////////////////////////////////////////////////////////////// + +template +class message_queue_t; + +typedef message_queue_t > message_queue; + +}} //namespace boost { namespace interprocess { + +#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#include + +#endif //#ifndef BOOST_INTERPROCESS_FWD_HPP diff --git a/libraries/boost/boost/interprocess/ipc/message_queue.hpp b/libraries/boost/boost/interprocess/ipc/message_queue.hpp new file mode 100644 index 000000000..db422cc9d --- /dev/null +++ b/libraries/boost/boost/interprocess/ipc/message_queue.hpp @@ -0,0 +1,996 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP +#define BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //make_unsigned, alignment_of +#include +#include +#include //std::lower_bound +#include //std::size_t +#include //memcpy + + +//!\file +//!Describes an inter-process message queue. This class allows sending +//!messages between processes and allows blocking, non-blocking and timed +//!sending and receiving. + +namespace boost{ namespace interprocess{ + +namespace ipcdetail +{ + template + class msg_queue_initialization_func_t; +} + +//!A class that allows sending messages +//!between processes. +template +class message_queue_t +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Blocking modes + enum block_t { blocking, timed, non_blocking }; + + message_queue_t(); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef VoidPointer void_pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type char_ptr; + typedef typename boost::intrusive::pointer_traits::difference_type difference_type; + typedef typename boost::container::container_detail::make_unsigned::type size_type; + + //!Creates a process shared message queue with name "name". For this message queue, + //!the maximum number of messages will be "max_num_msg" and the maximum message size + //!will be "max_msg_size". Throws on error and if the queue was previously created. + message_queue_t(create_only_t create_only, + const char *name, + size_type max_num_msg, + size_type max_msg_size, + const permissions &perm = permissions()); + + //!Opens or creates a process shared message queue with name "name". + //!If the queue is created, the maximum number of messages will be "max_num_msg" + //!and the maximum message size will be "max_msg_size". If queue was previously + //!created the queue will be opened and "max_num_msg" and "max_msg_size" parameters + //!are ignored. Throws on error. + message_queue_t(open_or_create_t open_or_create, + const char *name, + size_type max_num_msg, + size_type max_msg_size, + const permissions &perm = permissions()); + + //!Opens a previously created process shared message queue with name "name". + //!If the queue was not previously created or there are no free resources, + //!throws an error. + message_queue_t(open_only_t open_only, + const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. All opened message queues are still + //!valid after destruction. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the message queue from the system + //!use remove(). + ~message_queue_t(); + + //!Sends a message stored in buffer "buffer" with size "buffer_size" in the + //!message queue with priority "priority". If the message queue is full + //!the sender is blocked. Throws interprocess_error on error. + void send (const void *buffer, size_type buffer_size, + unsigned int priority); + + //!Sends a message stored in buffer "buffer" with size "buffer_size" through the + //!message queue with priority "priority". If the message queue is full + //!the sender is not blocked and returns false, otherwise returns true. + //!Throws interprocess_error on error. + bool try_send (const void *buffer, size_type buffer_size, + unsigned int priority); + + //!Sends a message stored in buffer "buffer" with size "buffer_size" in the + //!message queue with priority "priority". If the message queue is full + //!the sender retries until time "abs_time" is reached. Returns true if + //!the message has been successfully sent. Returns false if timeout is reached. + //!Throws interprocess_error on error. + bool timed_send (const void *buffer, size_type buffer_size, + unsigned int priority, const boost::posix_time::ptime& abs_time); + + //!Receives a message from the message queue. The message is stored in buffer + //!"buffer", which has size "buffer_size". The received message has size + //!"recvd_size" and priority "priority". If the message queue is empty + //!the receiver is blocked. Throws interprocess_error on error. + void receive (void *buffer, size_type buffer_size, + size_type &recvd_size,unsigned int &priority); + + //!Receives a message from the message queue. The message is stored in buffer + //!"buffer", which has size "buffer_size". The received message has size + //!"recvd_size" and priority "priority". If the message queue is empty + //!the receiver is not blocked and returns false, otherwise returns true. + //!Throws interprocess_error on error. + bool try_receive (void *buffer, size_type buffer_size, + size_type &recvd_size,unsigned int &priority); + + //!Receives a message from the message queue. The message is stored in buffer + //!"buffer", which has size "buffer_size". The received message has size + //!"recvd_size" and priority "priority". If the message queue is empty + //!the receiver retries until time "abs_time" is reached. Returns true if + //!the message has been successfully sent. Returns false if timeout is reached. + //!Throws interprocess_error on error. + bool timed_receive (void *buffer, size_type buffer_size, + size_type &recvd_size,unsigned int &priority, + const boost::posix_time::ptime &abs_time); + + //!Returns the maximum number of messages allowed by the queue. The message + //!queue must be opened or created previously. Otherwise, returns 0. + //!Never throws + size_type get_max_msg() const; + + //!Returns the maximum size of message allowed by the queue. The message + //!queue must be opened or created previously. Otherwise, returns 0. + //!Never throws + size_type get_max_msg_size() const; + + //!Returns the number of messages currently stored. + //!Never throws + size_type get_num_msg() const; + + //!Removes the message queue from the system. + //!Returns false on error. Never throws + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef boost::posix_time::ptime ptime; + + friend class ipcdetail::msg_queue_initialization_func_t; + + bool do_receive(block_t block, + void *buffer, size_type buffer_size, + size_type &recvd_size, unsigned int &priority, + const ptime &abs_time); + + bool do_send(block_t block, + const void *buffer, size_type buffer_size, + unsigned int priority, const ptime &abs_time); + + //!Returns the needed memory size for the shared message queue. + //!Never throws + static size_type get_mem_size(size_type max_msg_size, size_type max_num_msg); + typedef ipcdetail::managed_open_or_create_impl open_create_impl_t; + open_create_impl_t m_shmem; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace ipcdetail { + +//!This header is the prefix of each message in the queue +template +class msg_hdr_t +{ + typedef VoidPointer void_pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type char_ptr; + typedef typename boost::intrusive::pointer_traits::difference_type difference_type; + typedef typename boost::container::container_detail::make_unsigned::type size_type; + + public: + size_type len; // Message length + unsigned int priority;// Message priority + //!Returns the data buffer associated with this this message + void * data(){ return this+1; } // +}; + +//!This functor is the predicate to order stored messages by priority +template +class priority_functor +{ + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer >::type msg_hdr_ptr_t; + + public: + bool operator()(const msg_hdr_ptr_t &msg1, + const msg_hdr_ptr_t &msg2) const + { return msg1->priority < msg2->priority; } +}; + +//!This header is placed in the beginning of the shared memory and contains +//!the data to control the queue. This class initializes the shared memory +//!in the following way: in ascending memory address with proper alignment +//!fillings: +//! +//!-> mq_hdr_t: +//! Main control block that controls the rest of the elements +//! +//!-> offset_ptr index [max_num_msg] +//! An array of pointers with size "max_num_msg" called index. Each pointer +//! points to a preallocated message. Elements of this array are +//! reordered in runtime in the following way: +//! +//! IF BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX is defined: +//! +//! When the current number of messages is "cur_num_msg", the array +//! is treated like a circular buffer. Starting from position "cur_first_msg" +//! "cur_num_msg" in a circular way, pointers point to inserted messages and the rest +//! point to free messages. Those "cur_num_msg" pointers are +//! ordered by the priority of the pointed message and by insertion order +//! if two messages have the same priority. So the next message to be +//! used in a "receive" is pointed by index [(cur_first_msg + cur_num_msg-1)%max_num_msg] +//! and the first free message ready to be used in a "send" operation is +//! [cur_first_msg] if circular buffer is extended from front, +//! [(cur_first_msg + cur_num_msg)%max_num_msg] otherwise. +//! +//! This transforms the index in a circular buffer with an embedded free +//! message queue. +//! +//! ELSE (BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX is NOT defined): +//! +//! When the current number of messages is "cur_num_msg", the first +//! "cur_num_msg" pointers point to inserted messages and the rest +//! point to free messages. The first "cur_num_msg" pointers are +//! ordered by the priority of the pointed message and by insertion order +//! if two messages have the same priority. So the next message to be +//! used in a "receive" is pointed by index [cur_num_msg-1] and the first free +//! message ready to be used in a "send" operation is index [cur_num_msg]. +//! +//! This transforms the index in a fixed size priority queue with an embedded free +//! message queue. +//! +//!-> struct message_t +//! { +//! msg_hdr_t header; +//! char[max_msg_size] data; +//! } messages [max_num_msg]; +//! +//! An array of buffers of preallocated messages, each one prefixed with the +//! msg_hdr_t structure. Each of this message is pointed by one pointer of +//! the index structure. +template +class mq_hdr_t + : public ipcdetail::priority_functor +{ + typedef VoidPointer void_pointer; + typedef msg_hdr_t msg_header; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type msg_hdr_ptr_t; + typedef typename boost::intrusive::pointer_traits + ::difference_type difference_type; + typedef typename boost::container:: + container_detail::make_unsigned::type size_type; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type msg_hdr_ptr_ptr_t; + typedef ipcdetail::managed_open_or_create_impl open_create_impl_t; + + public: + //!Constructor. This object must be constructed in the beginning of the + //!shared memory of the size returned by the function "get_mem_size". + //!This constructor initializes the needed resources and creates + //!the internal structures like the priority index. This can throw. + mq_hdr_t(size_type max_num_msg, size_type max_msg_size) + : m_max_num_msg(max_num_msg), + m_max_msg_size(max_msg_size), + m_cur_num_msg(0) + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + ,m_cur_first_msg(0u) + ,m_blocked_senders(0u) + ,m_blocked_receivers(0u) + #endif + { this->initialize_memory(); } + + //!Returns true if the message queue is full + bool is_full() const + { return m_cur_num_msg == m_max_num_msg; } + + //!Returns true if the message queue is empty + bool is_empty() const + { return !m_cur_num_msg; } + + //!Frees the top priority message and saves it in the free message list + void free_top_msg() + { --m_cur_num_msg; } + + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + + typedef msg_hdr_ptr_t *iterator; + + size_type end_pos() const + { + const size_type space_until_bufend = m_max_num_msg - m_cur_first_msg; + return space_until_bufend > m_cur_num_msg + ? m_cur_first_msg + m_cur_num_msg : m_cur_num_msg - space_until_bufend; + } + + //!Returns the inserted message with top priority + msg_header &top_msg() + { + size_type pos = this->end_pos(); + return *mp_index[pos ? --pos : m_max_num_msg - 1]; + } + + //!Returns the inserted message with bottom priority + msg_header &bottom_msg() + { return *mp_index[m_cur_first_msg]; } + + iterator inserted_ptr_begin() const + { return &mp_index[m_cur_first_msg]; } + + iterator inserted_ptr_end() const + { return &mp_index[this->end_pos()]; } + + iterator lower_bound(const msg_hdr_ptr_t & value, priority_functor func) + { + iterator begin(this->inserted_ptr_begin()), end(this->inserted_ptr_end()); + if(end < begin){ + iterator idx_end = &mp_index[m_max_num_msg]; + iterator ret = std::lower_bound(begin, idx_end, value, func); + if(idx_end == ret){ + iterator idx_beg = &mp_index[0]; + ret = std::lower_bound(idx_beg, end, value, func); + //sanity check, these cases should not call lower_bound (optimized out) + BOOST_ASSERT(ret != end); + BOOST_ASSERT(ret != begin); + return ret; + } + else{ + return ret; + } + } + else{ + return std::lower_bound(begin, end, value, func); + } + } + + msg_header & insert_at(iterator where) + { + iterator it_inserted_ptr_end = this->inserted_ptr_end(); + iterator it_inserted_ptr_beg = this->inserted_ptr_begin(); + if(where == it_inserted_ptr_beg){ + //unsigned integer guarantees underflow + m_cur_first_msg = m_cur_first_msg ? m_cur_first_msg : m_max_num_msg; + --m_cur_first_msg; + ++m_cur_num_msg; + return *mp_index[m_cur_first_msg]; + } + else if(where == it_inserted_ptr_end){ + ++m_cur_num_msg; + return **it_inserted_ptr_end; + } + else{ + size_type pos = where - &mp_index[0]; + size_type circ_pos = pos >= m_cur_first_msg ? pos - m_cur_first_msg : pos + (m_max_num_msg - m_cur_first_msg); + //Check if it's more efficient to move back or move front + if(circ_pos < m_cur_num_msg/2){ + //The queue can't be full so m_cur_num_msg == 0 or m_cur_num_msg <= pos + //indicates two step insertion + if(!pos){ + pos = m_max_num_msg; + where = &mp_index[m_max_num_msg-1]; + } + else{ + --where; + } + const bool unique_segment = m_cur_first_msg && m_cur_first_msg <= pos; + const size_type first_segment_beg = unique_segment ? m_cur_first_msg : 1u; + const size_type first_segment_end = pos; + const size_type second_segment_beg = unique_segment || !m_cur_first_msg ? m_max_num_msg : m_cur_first_msg; + const size_type second_segment_end = m_max_num_msg; + const msg_hdr_ptr_t backup = *(&mp_index[0] + (unique_segment ? first_segment_beg : second_segment_beg) - 1); + + //First segment + if(!unique_segment){ + std::copy( &mp_index[0] + second_segment_beg + , &mp_index[0] + second_segment_end + , &mp_index[0] + second_segment_beg - 1); + mp_index[m_max_num_msg-1] = mp_index[0]; + } + std::copy( &mp_index[0] + first_segment_beg + , &mp_index[0] + first_segment_end + , &mp_index[0] + first_segment_beg - 1); + *where = backup; + m_cur_first_msg = m_cur_first_msg ? m_cur_first_msg : m_max_num_msg; + --m_cur_first_msg; + ++m_cur_num_msg; + return **where; + } + else{ + //The queue can't be full so end_pos < m_cur_first_msg + //indicates two step insertion + const size_type pos_end = this->end_pos(); + const bool unique_segment = pos < pos_end; + const size_type first_segment_beg = pos; + const size_type first_segment_end = unique_segment ? pos_end : m_max_num_msg-1; + const size_type second_segment_beg = 0u; + const size_type second_segment_end = unique_segment ? 0u : pos_end; + const msg_hdr_ptr_t backup = *it_inserted_ptr_end; + + //First segment + if(!unique_segment){ + std::copy_backward( &mp_index[0] + second_segment_beg + , &mp_index[0] + second_segment_end + , &mp_index[0] + second_segment_end + 1); + mp_index[0] = mp_index[m_max_num_msg-1]; + } + std::copy_backward( &mp_index[0] + first_segment_beg + , &mp_index[0] + first_segment_end + , &mp_index[0] + first_segment_end + 1); + *where = backup; + ++m_cur_num_msg; + return **where; + } + } + } + + #else //BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + + typedef msg_hdr_ptr_t *iterator; + + //!Returns the inserted message with top priority + msg_header &top_msg() + { return *mp_index[m_cur_num_msg-1]; } + + //!Returns the inserted message with bottom priority + msg_header &bottom_msg() + { return *mp_index[0]; } + + iterator inserted_ptr_begin() const + { return &mp_index[0]; } + + iterator inserted_ptr_end() const + { return &mp_index[m_cur_num_msg]; } + + iterator lower_bound(const msg_hdr_ptr_t & value, priority_functor func) + { return std::lower_bound(this->inserted_ptr_begin(), this->inserted_ptr_end(), value, func); } + + msg_header & insert_at(iterator pos) + { + const msg_hdr_ptr_t backup = *inserted_ptr_end(); + std::copy_backward(pos, inserted_ptr_end(), inserted_ptr_end()+1); + *pos = backup; + ++m_cur_num_msg; + return **pos; + } + + #endif //BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + + //!Inserts the first free message in the priority queue + msg_header & queue_free_msg(unsigned int priority) + { + //Get priority queue's range + iterator it (inserted_ptr_begin()), it_end(inserted_ptr_end()); + //Optimize for non-priority usage + if(m_cur_num_msg && priority > this->bottom_msg().priority){ + //Check for higher priority than all stored messages + if(priority > this->top_msg().priority){ + it = it_end; + } + else{ + //Since we don't now which free message we will pick + //build a dummy header for searches + msg_header dummy_hdr; + dummy_hdr.priority = priority; + + //Get free msg + msg_hdr_ptr_t dummy_ptr(&dummy_hdr); + + //Check where the free message should be placed + it = this->lower_bound(dummy_ptr, static_cast&>(*this)); + } + } + //Insert the free message in the correct position + return this->insert_at(it); + } + + //!Returns the number of bytes needed to construct a message queue with + //!"max_num_size" maximum number of messages and "max_msg_size" maximum + //!message size. Never throws. + static size_type get_mem_size + (size_type max_msg_size, size_type max_num_msg) + { + const size_type + msg_hdr_align = ::boost::container::container_detail::alignment_of::value, + index_align = ::boost::container::container_detail::alignment_of::value, + r_hdr_size = ipcdetail::ct_rounded_size::value, + r_index_size = ipcdetail::get_rounded_size(max_num_msg*sizeof(msg_hdr_ptr_t), msg_hdr_align), + r_max_msg_size = ipcdetail::get_rounded_size(max_msg_size, msg_hdr_align) + sizeof(msg_header); + return r_hdr_size + r_index_size + (max_num_msg*r_max_msg_size) + + open_create_impl_t::ManagedOpenOrCreateUserOffset; + } + + //!Initializes the memory structures to preallocate messages and constructs the + //!message index. Never throws. + void initialize_memory() + { + const size_type + msg_hdr_align = ::boost::container::container_detail::alignment_of::value, + index_align = ::boost::container::container_detail::alignment_of::value, + r_hdr_size = ipcdetail::ct_rounded_size::value, + r_index_size = ipcdetail::get_rounded_size(m_max_num_msg*sizeof(msg_hdr_ptr_t), msg_hdr_align), + r_max_msg_size = ipcdetail::get_rounded_size(m_max_msg_size, msg_hdr_align) + sizeof(msg_header); + + //Pointer to the index + msg_hdr_ptr_t *index = reinterpret_cast + (reinterpret_cast(this)+r_hdr_size); + + //Pointer to the first message header + msg_header *msg_hdr = reinterpret_cast + (reinterpret_cast(this)+r_hdr_size+r_index_size); + + //Initialize the pointer to the index + mp_index = index; + + //Initialize the index so each slot points to a preallocated message + for(size_type i = 0; i < m_max_num_msg; ++i){ + index[i] = msg_hdr; + msg_hdr = reinterpret_cast + (reinterpret_cast(msg_hdr)+r_max_msg_size); + } + } + + public: + //Pointer to the index + msg_hdr_ptr_ptr_t mp_index; + //Maximum number of messages of the queue + const size_type m_max_num_msg; + //Maximum size of messages of the queue + const size_type m_max_msg_size; + //Current number of messages + size_type m_cur_num_msg; + //Mutex to protect data structures + interprocess_mutex m_mutex; + //Condition block receivers when there are no messages + interprocess_condition m_cond_recv; + //Condition block senders when the queue is full + interprocess_condition m_cond_send; + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + //Current start offset in the circular index + size_type m_cur_first_msg; + size_type m_blocked_senders; + size_type m_blocked_receivers; + #endif +}; + + +//!This is the atomic functor to be executed when creating or opening +//!shared memory. Never throws +template +class msg_queue_initialization_func_t +{ + public: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type char_ptr; + typedef typename boost::intrusive::pointer_traits:: + difference_type difference_type; + typedef typename boost::container::container_detail:: + make_unsigned::type size_type; + + msg_queue_initialization_func_t(size_type maxmsg = 0, + size_type maxmsgsize = 0) + : m_maxmsg (maxmsg), m_maxmsgsize(maxmsgsize) {} + + bool operator()(void *address, size_type, bool created) + { + char *mptr; + + if(created){ + mptr = reinterpret_cast(address); + //Construct the message queue header at the beginning + BOOST_TRY{ + new (mptr) mq_hdr_t(m_maxmsg, m_maxmsgsize); + } + BOOST_CATCH(...){ + return false; + } + BOOST_CATCH_END + } + return true; + } + + std::size_t get_min_size() const + { + return mq_hdr_t::get_mem_size(m_maxmsgsize, m_maxmsg) + - message_queue_t::open_create_impl_t::ManagedOpenOrCreateUserOffset; + } + + const size_type m_maxmsg; + const size_type m_maxmsgsize; +}; + +} //namespace ipcdetail { + +template +inline message_queue_t::~message_queue_t() +{} + +template +inline typename message_queue_t::size_type message_queue_t::get_mem_size + (size_type max_msg_size, size_type max_num_msg) +{ return ipcdetail::mq_hdr_t::get_mem_size(max_msg_size, max_num_msg); } + +template +inline message_queue_t::message_queue_t(create_only_t, + const char *name, + size_type max_num_msg, + size_type max_msg_size, + const permissions &perm) + //Create shared memory and execute functor atomically + : m_shmem(create_only, + name, + get_mem_size(max_msg_size, max_num_msg), + read_write, + static_cast(0), + //Prepare initialization functor + ipcdetail::msg_queue_initialization_func_t (max_num_msg, max_msg_size), + perm) +{} + +template +inline message_queue_t::message_queue_t(open_or_create_t, + const char *name, + size_type max_num_msg, + size_type max_msg_size, + const permissions &perm) + //Create shared memory and execute functor atomically + : m_shmem(open_or_create, + name, + get_mem_size(max_msg_size, max_num_msg), + read_write, + static_cast(0), + //Prepare initialization functor + ipcdetail::msg_queue_initialization_func_t (max_num_msg, max_msg_size), + perm) +{} + +template +inline message_queue_t::message_queue_t(open_only_t, const char *name) + //Create shared memory and execute functor atomically + : m_shmem(open_only, + name, + read_write, + static_cast(0), + //Prepare initialization functor + ipcdetail::msg_queue_initialization_func_t ()) +{} + +template +inline void message_queue_t::send + (const void *buffer, size_type buffer_size, unsigned int priority) +{ this->do_send(blocking, buffer, buffer_size, priority, ptime()); } + +template +inline bool message_queue_t::try_send + (const void *buffer, size_type buffer_size, unsigned int priority) +{ return this->do_send(non_blocking, buffer, buffer_size, priority, ptime()); } + +template +inline bool message_queue_t::timed_send + (const void *buffer, size_type buffer_size + ,unsigned int priority, const boost::posix_time::ptime &abs_time) +{ + if(abs_time == boost::posix_time::pos_infin){ + this->send(buffer, buffer_size, priority); + return true; + } + return this->do_send(timed, buffer, buffer_size, priority, abs_time); +} + +template +inline bool message_queue_t::do_send(block_t block, + const void *buffer, size_type buffer_size, + unsigned int priority, const boost::posix_time::ptime &abs_time) +{ + ipcdetail::mq_hdr_t *p_hdr = static_cast*>(m_shmem.get_user_address()); + //Check if buffer is smaller than maximum allowed + if (buffer_size > p_hdr->m_max_msg_size) { + throw interprocess_exception(size_error); + } + + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + bool notify_blocked_receivers = false; + #endif + //--------------------------------------------- + scoped_lock lock(p_hdr->m_mutex); + //--------------------------------------------- + { + //If the queue is full execute blocking logic + if (p_hdr->is_full()) { + BOOST_TRY{ + #ifdef BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + ++p_hdr->m_blocked_senders; + #endif + switch(block){ + case non_blocking : + #ifdef BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + --p_hdr->m_blocked_senders; + #endif + return false; + break; + + case blocking : + do{ + p_hdr->m_cond_send.wait(lock); + } + while (p_hdr->is_full()); + break; + + case timed : + do{ + if(!p_hdr->m_cond_send.timed_wait(lock, abs_time)){ + if(p_hdr->is_full()){ + #ifdef BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + --p_hdr->m_blocked_senders; + #endif + return false; + } + break; + } + } + while (p_hdr->is_full()); + break; + default: + break; + } + #ifdef BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + --p_hdr->m_blocked_senders; + #endif + } + BOOST_CATCH(...){ + #ifdef BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + --p_hdr->m_blocked_senders; + #endif + BOOST_RETHROW; + } + BOOST_CATCH_END + } + + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + notify_blocked_receivers = 0 != p_hdr->m_blocked_receivers; + #endif + //Insert the first free message in the priority queue + ipcdetail::msg_hdr_t &free_msg_hdr = p_hdr->queue_free_msg(priority); + + //Sanity check, free msgs are always cleaned when received + BOOST_ASSERT(free_msg_hdr.priority == 0); + BOOST_ASSERT(free_msg_hdr.len == 0); + + //Copy control data to the free message + free_msg_hdr.priority = priority; + free_msg_hdr.len = buffer_size; + + //Copy user buffer to the message + std::memcpy(free_msg_hdr.data(), buffer, buffer_size); + } // Lock end + + //Notify outside lock to avoid contention. This might produce some + //spurious wakeups, but it's usually far better than notifying inside. + //If this message changes the queue empty state, notify it to receivers + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + if (notify_blocked_receivers){ + p_hdr->m_cond_recv.notify_one(); + } + #else + p_hdr->m_cond_recv.notify_one(); + #endif + + return true; +} + +template +inline void message_queue_t::receive(void *buffer, size_type buffer_size, + size_type &recvd_size, unsigned int &priority) +{ this->do_receive(blocking, buffer, buffer_size, recvd_size, priority, ptime()); } + +template +inline bool + message_queue_t::try_receive(void *buffer, size_type buffer_size, + size_type &recvd_size, unsigned int &priority) +{ return this->do_receive(non_blocking, buffer, buffer_size, recvd_size, priority, ptime()); } + +template +inline bool + message_queue_t::timed_receive(void *buffer, size_type buffer_size, + size_type &recvd_size, unsigned int &priority, + const boost::posix_time::ptime &abs_time) +{ + if(abs_time == boost::posix_time::pos_infin){ + this->receive(buffer, buffer_size, recvd_size, priority); + return true; + } + return this->do_receive(timed, buffer, buffer_size, recvd_size, priority, abs_time); +} + +template +inline bool + message_queue_t::do_receive(block_t block, + void *buffer, size_type buffer_size, + size_type &recvd_size, unsigned int &priority, + const boost::posix_time::ptime &abs_time) +{ + ipcdetail::mq_hdr_t *p_hdr = static_cast*>(m_shmem.get_user_address()); + //Check if buffer is big enough for any message + if (buffer_size < p_hdr->m_max_msg_size) { + throw interprocess_exception(size_error); + } + + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + bool notify_blocked_senders = false; + #endif + //--------------------------------------------- + scoped_lock lock(p_hdr->m_mutex); + //--------------------------------------------- + { + //If there are no messages execute blocking logic + if (p_hdr->is_empty()) { + BOOST_TRY{ + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + ++p_hdr->m_blocked_receivers; + #endif + switch(block){ + case non_blocking : + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + --p_hdr->m_blocked_receivers; + #endif + return false; + break; + + case blocking : + do{ + p_hdr->m_cond_recv.wait(lock); + } + while (p_hdr->is_empty()); + break; + + case timed : + do{ + if(!p_hdr->m_cond_recv.timed_wait(lock, abs_time)){ + if(p_hdr->is_empty()){ + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + --p_hdr->m_blocked_receivers; + #endif + return false; + } + break; + } + } + while (p_hdr->is_empty()); + break; + + //Paranoia check + default: + break; + } + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + --p_hdr->m_blocked_receivers; + #endif + } + BOOST_CATCH(...){ + #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX) + --p_hdr->m_blocked_receivers; + #endif + BOOST_RETHROW; + } + BOOST_CATCH_END + } + + #ifdef BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + notify_blocked_senders = 0 != p_hdr->m_blocked_senders; + #endif + + //There is at least one message ready to pick, get the top one + ipcdetail::msg_hdr_t &top_msg = p_hdr->top_msg(); + + //Get data from the message + recvd_size = top_msg.len; + priority = top_msg.priority; + + //Some cleanup to ease debugging + top_msg.len = 0; + top_msg.priority = 0; + + //Copy data to receiver's bufers + std::memcpy(buffer, top_msg.data(), recvd_size); + + //Free top message and put it in the free message list + p_hdr->free_top_msg(); + } //Lock end + + //Notify outside lock to avoid contention. This might produce some + //spurious wakeups, but it's usually far better than notifying inside. + //If this reception changes the queue full state, notify senders + #ifdef BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + if (notify_blocked_senders){ + p_hdr->m_cond_send.notify_one(); + } + #else + p_hdr->m_cond_send.notify_one(); + #endif + + return true; +} + +template +inline typename message_queue_t::size_type message_queue_t::get_max_msg() const +{ + ipcdetail::mq_hdr_t *p_hdr = static_cast*>(m_shmem.get_user_address()); + return p_hdr ? p_hdr->m_max_num_msg : 0; } + +template +inline typename message_queue_t::size_type message_queue_t::get_max_msg_size() const +{ + ipcdetail::mq_hdr_t *p_hdr = static_cast*>(m_shmem.get_user_address()); + return p_hdr ? p_hdr->m_max_msg_size : 0; +} + +template +inline typename message_queue_t::size_type message_queue_t::get_num_msg() const +{ + ipcdetail::mq_hdr_t *p_hdr = static_cast*>(m_shmem.get_user_address()); + if(p_hdr){ + //--------------------------------------------- + scoped_lock lock(p_hdr->m_mutex); + //--------------------------------------------- + return p_hdr->m_cur_num_msg; + } + + return 0; +} + +template +inline bool message_queue_t::remove(const char *name) +{ return shared_memory_object::remove(name); } + +#else + +//!Typedef for a default message queue +//!to be used between processes +typedef message_queue_t > message_queue; + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +}} //namespace boost{ namespace interprocess{ + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP diff --git a/libraries/boost/boost/interprocess/managed_external_buffer.hpp b/libraries/boost/boost/interprocess/managed_external_buffer.hpp new file mode 100644 index 000000000..1e8f1cca4 --- /dev/null +++ b/libraries/boost/boost/interprocess/managed_external_buffer.hpp @@ -0,0 +1,137 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_EXTERNAL_BUFFER_HPP +#define BOOST_INTERPROCESS_MANAGED_EXTERNAL_BUFFER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +//These includes needed to fulfill default template parameters of +//predeclarations in interprocess_fwd.hpp +#include +#include +#include + +//!\file +//!Describes a named user memory allocation user class. + +namespace boost { +namespace interprocess { + +//!A basic user memory named object creation class. Inherits all +//!basic functionality from +//!basic_managed_memory_impl*/ +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +class basic_managed_external_buffer + : public ipcdetail::basic_managed_memory_impl +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef ipcdetail::basic_managed_memory_impl + base_t; + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_external_buffer) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef typename base_t::size_type size_type; + + //!Default constructor. Does nothing. + //!Useful in combination with move semantics + basic_managed_external_buffer() + {} + + //!Creates and places the segment manager. This can throw + basic_managed_external_buffer + (create_only_t, void *addr, size_type size) + { + //Check if alignment is correct + BOOST_ASSERT((0 == (((std::size_t)addr) & (AllocationAlgorithm::Alignment - size_type(1u))))); + if(!base_t::create_impl(addr, size)){ + throw interprocess_exception("Could not initialize buffer in basic_managed_external_buffer constructor"); + } + } + + //!Creates and places the segment manager. This can throw + basic_managed_external_buffer + (open_only_t, void *addr, size_type size) + { + //Check if alignment is correct + BOOST_ASSERT((0 == (((std::size_t)addr) & (AllocationAlgorithm::Alignment - size_type(1u))))); + if(!base_t::open_impl(addr, size)){ + throw interprocess_exception("Could not initialize buffer in basic_managed_external_buffer constructor"); + } + } + + //!Moves the ownership of "moved"'s managed memory to *this. Does not throw + basic_managed_external_buffer(BOOST_RV_REF(basic_managed_external_buffer) moved) + { + this->swap(moved); + } + + //!Moves the ownership of "moved"'s managed memory to *this. Does not throw + basic_managed_external_buffer &operator=(BOOST_RV_REF(basic_managed_external_buffer) moved) + { + basic_managed_external_buffer tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + void grow(size_type extra_bytes) + { base_t::grow(extra_bytes); } + + //!Swaps the ownership of the managed heap memories managed by *this and other. + //!Never throws. + void swap(basic_managed_external_buffer &other) + { base_t::swap(other); } +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Typedef for a default basic_managed_external_buffer +//!of narrow characters +typedef basic_managed_external_buffer + + ,iset_index> +managed_external_buffer; + +//!Typedef for a default basic_managed_external_buffer +//!of wide characters +typedef basic_managed_external_buffer + + ,iset_index> +wmanaged_external_buffer; + +#endif //#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_EXTERNAL_BUFFER_HPP + diff --git a/libraries/boost/boost/interprocess/managed_heap_memory.hpp b/libraries/boost/boost/interprocess/managed_heap_memory.hpp new file mode 100644 index 000000000..c4503281e --- /dev/null +++ b/libraries/boost/boost/interprocess/managed_heap_memory.hpp @@ -0,0 +1,171 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_HEAP_MEMORY_HPP +#define BOOST_INTERPROCESS_MANAGED_HEAP_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +//These includes needed to fulfill default template parameters of +//predeclarations in interprocess_fwd.hpp +#include +#include +#include + +//!\file +//!Describes a named heap memory allocation user class. + +namespace boost { +namespace interprocess { + +//!A basic heap memory named object creation class. Initializes the +//!heap memory segment. Inherits all basic functionality from +//!basic_managed_memory_impl*/ +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +class basic_managed_heap_memory + : public ipcdetail::basic_managed_memory_impl +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + + typedef ipcdetail::basic_managed_memory_impl + base_t; + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_heap_memory) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: //functions + typedef typename base_t::size_type size_type; + + //!Default constructor. Does nothing. + //!Useful in combination with move semantics + basic_managed_heap_memory(){} + + //!Destructor. Liberates the heap memory holding the managed data. + //!Never throws. + ~basic_managed_heap_memory() + { this->priv_close(); } + + //!Creates heap memory and initializes the segment manager. + //!This can throw. + basic_managed_heap_memory(size_type size) + : m_heapmem(size, char(0)) + { + if(!base_t::create_impl(&m_heapmem[0], size)){ + this->priv_close(); + throw interprocess_exception("Could not initialize heap in basic_managed_heap_memory constructor"); + } + } + + //!Moves the ownership of "moved"'s managed memory to *this. Does not throw + basic_managed_heap_memory(BOOST_RV_REF(basic_managed_heap_memory) moved) + { this->swap(moved); } + + //!Moves the ownership of "moved"'s managed memory to *this. Does not throw + basic_managed_heap_memory &operator=(BOOST_RV_REF(basic_managed_heap_memory) moved) + { + basic_managed_heap_memory tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Tries to resize internal heap memory so that + //!we have room for more objects. + //!WARNING: If memory is reallocated, all the objects will + //!be binary-copied to the new buffer. To be able to use + //!this function, all pointers constructed in this buffer + //!must be offset pointers. Otherwise, the result is undefined. + //!Returns true if the growth has been successful, so you will + //!have some extra bytes to allocate new objects. If returns + //!false, the heap allocation has failed. + bool grow(size_type extra_bytes) + { + //If memory is reallocated, data will + //be automatically copied + BOOST_TRY{ + m_heapmem.resize(m_heapmem.size()+extra_bytes); + } + BOOST_CATCH(...){ + return false; + } + BOOST_CATCH_END + + //Grow always works + base_t::close_impl(); + base_t::open_impl(&m_heapmem[0], m_heapmem.size()); + base_t::grow(extra_bytes); + return true; + } + + //!Swaps the ownership of the managed heap memories managed by *this and other. + //!Never throws. + void swap(basic_managed_heap_memory &other) + { + base_t::swap(other); + m_heapmem.swap(other.m_heapmem); + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + //!Frees resources. Never throws. + void priv_close() + { + base_t::destroy_impl(); + std::vector().swap(m_heapmem); + } + + std::vector m_heapmem; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Typedef for a default basic_managed_heap_memory +//!of narrow characters +typedef basic_managed_heap_memory + + ,iset_index> +managed_heap_memory; + +//!Typedef for a default basic_managed_heap_memory +//!of wide characters +typedef basic_managed_heap_memory + + ,iset_index> +wmanaged_heap_memory; + +#endif //#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_HEAP_MEMORY_HPP + diff --git a/libraries/boost/boost/interprocess/managed_mapped_file.hpp b/libraries/boost/boost/interprocess/managed_mapped_file.hpp new file mode 100644 index 000000000..14ec16061 --- /dev/null +++ b/libraries/boost/boost/interprocess/managed_mapped_file.hpp @@ -0,0 +1,250 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP +#define BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +//These includes needed to fulfill default template parameters of +//predeclarations in interprocess_fwd.hpp +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +struct mfile_open_or_create +{ + typedef ipcdetail::managed_open_or_create_impl + < file_wrapper, AllocationAlgorithm::Alignment, true, false> type; +}; + +} //namespace ipcdetail { + +//!A basic mapped file named object creation class. Initializes the +//!mapped file. Inherits all basic functionality from +//!basic_managed_memory_impl +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +class basic_managed_mapped_file + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + : public ipcdetail::basic_managed_memory_impl + ::type::ManagedOpenOrCreateUserOffset> + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + public: + typedef ipcdetail::basic_managed_memory_impl + ::type::ManagedOpenOrCreateUserOffset> base_t; + typedef ipcdetail::file_wrapper device_type; + + private: + + typedef ipcdetail::create_open_func create_open_func_t; + + basic_managed_mapped_file *get_this_pointer() + { return this; } + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_mapped_file) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: //functions + + //!Unsigned integral type enough to represent + //!the size of a basic_managed_mapped_file. + typedef typename BOOST_INTERPROCESS_IMPDEF(base_t::size_type) size_type; + + //!Creates mapped file and creates and places the segment manager. + //!This can throw. + basic_managed_mapped_file() + {} + + //!Creates mapped file and creates and places the segment manager. + //!This can throw. + basic_managed_mapped_file(create_only_t, const char *name, + size_type size, const void *addr = 0, const permissions &perm = permissions()) + : m_mfile(create_only, name, size, read_write, addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm) + {} + + //!Creates mapped file and creates and places the segment manager if + //!segment was not created. If segment was created it connects to the + //!segment. + //!This can throw. + basic_managed_mapped_file (open_or_create_t, + const char *name, size_type size, + const void *addr = 0, const permissions &perm = permissions()) + : m_mfile(open_or_create, name, size, read_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpenOrCreate), perm) + {} + + //!Connects to a created mapped file and its segment manager. + //!This can throw. + basic_managed_mapped_file (open_only_t, const char* name, + const void *addr = 0) + : m_mfile(open_only, name, read_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpen)) + {} + + //!Connects to a created mapped file and its segment manager + //!in copy_on_write mode. + //!This can throw. + basic_managed_mapped_file (open_copy_on_write_t, const char* name, + const void *addr = 0) + : m_mfile(open_only, name, copy_on_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpen)) + {} + + //!Connects to a created mapped file and its segment manager + //!in read-only mode. + //!This can throw. + basic_managed_mapped_file (open_read_only_t, const char* name, + const void *addr = 0) + : m_mfile(open_only, name, read_only, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpen)) + {} + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_mapped_file(BOOST_RV_REF(basic_managed_mapped_file) moved) + { + this->swap(moved); + } + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_mapped_file &operator=(BOOST_RV_REF(basic_managed_mapped_file) moved) + { + basic_managed_mapped_file tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~basic_managed_mapped_file() + {} + + //!Swaps the ownership of the managed mapped memories managed by *this and other. + //!Never throws. + void swap(basic_managed_mapped_file &other) + { + base_t::swap(other); + m_mfile.swap(other.m_mfile); + } + + //!Flushes cached data to file. + //!Never throws + bool flush() + { return m_mfile.flush(); } + + //!Tries to resize mapped file so that we have room for + //!more objects. + //! + //!This function is not synchronized so no other thread or process should + //!be reading or writing the file + static bool grow(const char *filename, size_type extra_bytes) + { + return base_t::template grow + (filename, extra_bytes); + } + + //!Tries to resize mapped file to minimized the size of the file. + //! + //!This function is not synchronized so no other thread or process should + //!be reading or writing the file + static bool shrink_to_fit(const char *filename) + { + return base_t::template shrink_to_fit + (filename); + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find (char_ptr_holder_t name) + { + if(m_mfile.get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + + private: + typename ipcdetail::mfile_open_or_create::type m_mfile; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Typedef for a default basic_managed_mapped_file +//!of narrow characters +typedef basic_managed_mapped_file + + ,iset_index> +managed_mapped_file; + +//!Typedef for a default basic_managed_mapped_file +//!of wide characters +typedef basic_managed_mapped_file + + ,iset_index> +wmanaged_mapped_file; + +#endif //#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP diff --git a/libraries/boost/boost/interprocess/managed_shared_memory.hpp b/libraries/boost/boost/interprocess/managed_shared_memory.hpp new file mode 100644 index 000000000..fadc19a71 --- /dev/null +++ b/libraries/boost/boost/interprocess/managed_shared_memory.hpp @@ -0,0 +1,262 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +//These includes needed to fulfill default template parameters of +//predeclarations in interprocess_fwd.hpp +#include +#include + +namespace boost { +namespace interprocess { + +namespace ipcdetail { + +template +struct shmem_open_or_create +{ + typedef ipcdetail::managed_open_or_create_impl + < shared_memory_object, AllocationAlgorithm::Alignment, true, false> type; +}; + +} //namespace ipcdetail { + +//!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 AllocationAlgorithm, + template class IndexType + > +class basic_managed_shared_memory + : public ipcdetail::basic_managed_memory_impl + ::type::ManagedOpenOrCreateUserOffset> + , private ipcdetail::shmem_open_or_create::type +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef ipcdetail::basic_managed_memory_impl + ::type::ManagedOpenOrCreateUserOffset> base_t; + typedef typename ipcdetail::shmem_open_or_create::type base2_t; + + typedef ipcdetail::create_open_func create_open_func_t; + + basic_managed_shared_memory *get_this_pointer() + { return this; } + + public: + typedef shared_memory_object device_type; + 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_shared_memory) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: //functions + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~basic_managed_shared_memory() + {} + + //!Default constructor. Does nothing. + //!Useful in combination with move semantics + basic_managed_shared_memory() + {} + + //!Creates shared memory and creates and places the segment manager. + //!This can throw. + basic_managed_shared_memory(create_only_t, 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(), ipcdetail::DoCreate), perm) + {} + + //!Creates shared memory and creates and places the segment manager if + //!segment was not created. If segment was created it connects to the + //!segment. + //!This can throw. + basic_managed_shared_memory (open_or_create_t, + 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(), + ipcdetail::DoOpenOrCreate), perm) + {} + + //!Connects to a created shared memory and its segment manager. + //!in copy_on_write mode. + //!This can throw. + basic_managed_shared_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(), + ipcdetail::DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager. + //!in read-only mode. + //!This can throw. + basic_managed_shared_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(), + ipcdetail::DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager. + //!This can throw. + basic_managed_shared_memory (open_only_t, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, read_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpen)) + {} + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_shared_memory(BOOST_RV_REF(basic_managed_shared_memory) moved) + { + basic_managed_shared_memory tmp; + this->swap(moved); + tmp.swap(moved); + } + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_shared_memory &operator=(BOOST_RV_REF(basic_managed_shared_memory) moved) + { + basic_managed_shared_memory tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps the ownership of the managed shared memories managed by *this and other. + //!Never throws. + void swap(basic_managed_shared_memory &other) + { + base_t::swap(other); + base2_t::swap(other); + } + + //!Tries to resize the managed shared memory object so that we have + //!room for more objects. + //! + //!This function is not synchronized so no other thread or process should + //!be reading or writing the file + static bool grow(const char *shmname, size_type extra_bytes) + { + return base_t::template grow + (shmname, extra_bytes); + } + + //!Tries to resize the managed shared memory to minimized the size of the file. + //! + //!This function is not synchronized so no other thread or process should + //!be reading or writing the file + static bool shrink_to_fit(const char *shmname) + { + return base_t::template shrink_to_fit + (shmname); + } + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find (char_ptr_holder_t name) + { + if(base2_t::get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Typedef for a default basic_managed_shared_memory +//!of narrow characters +typedef basic_managed_shared_memory + + ,iset_index> +managed_shared_memory; + +//!Typedef for a default basic_managed_shared_memory +//!of wide characters +typedef basic_managed_shared_memory + + ,iset_index> +wmanaged_shared_memory; + +//!Typedef for a default basic_managed_shared_memory +//!of narrow characters to be placed in a fixed address +typedef basic_managed_shared_memory + + ,iset_index> +fixed_managed_shared_memory; + +//!Typedef for a default basic_managed_shared_memory +//!of narrow characters to be placed in a fixed address +typedef basic_managed_shared_memory + + ,iset_index> +wfixed_managed_shared_memory; + + +#endif //#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP + diff --git a/libraries/boost/boost/interprocess/managed_windows_shared_memory.hpp b/libraries/boost/boost/interprocess/managed_windows_shared_memory.hpp new file mode 100644 index 000000000..2ff30c922 --- /dev/null +++ b/libraries/boost/boost/interprocess/managed_windows_shared_memory.hpp @@ -0,0 +1,224 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_WINDOWS_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_MANAGED_WINDOWS_SHARED_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +//These includes needed to fulfill default template parameters of +//predeclarations in interprocess_fwd.hpp +#include +#include +#include + +namespace boost { +namespace interprocess { + +namespace ipcdetail { + +template +struct wshmem_open_or_create +{ + typedef ipcdetail::managed_open_or_create_impl + < windows_shared_memory, AllocationAlgorithm::Alignment, false, false> type; +}; + +} //namespace ipcdetail { + +//!A basic managed windows shared memory creation class. Initializes the +//!shared memory segment. Inherits all basic functionality from +//!basic_managed_memory_impl +//!Unlike basic_managed_shared_memory, it has +//!no kernel persistence and the shared memory is destroyed +//!when all processes destroy all their windows_shared_memory +//!objects and mapped regions for the same shared memory +//!or the processes end/crash. +//! +//!Warning: basic_managed_windows_shared_memory and +//!basic_managed_shared_memory can't communicate between them. +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +class basic_managed_windows_shared_memory + : public ipcdetail::basic_managed_memory_impl + < CharType, AllocationAlgorithm, IndexType + , ipcdetail::wshmem_open_or_create::type::ManagedOpenOrCreateUserOffset> +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef ipcdetail::basic_managed_memory_impl + ::type::ManagedOpenOrCreateUserOffset> base_t; + typedef ipcdetail::create_open_func create_open_func_t; + + basic_managed_windows_shared_memory *get_this_pointer() + { return this; } + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_windows_shared_memory) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: //functions + typedef typename base_t::size_type size_type; + + //!Default constructor. Does nothing. + //!Useful in combination with move semantics + basic_managed_windows_shared_memory() + {} + + //!Creates shared memory and creates and places the segment manager. + //!This can throw. + basic_managed_windows_shared_memory + (create_only_t, const char *name, + size_type size, const void *addr = 0, const permissions &perm = permissions()) + : m_wshm(create_only, name, size, read_write, addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm) + {} + + //!Creates shared memory and creates and places the segment manager if + //!segment was not created. If segment was created it connects to the + //!segment. + //!This can throw. + basic_managed_windows_shared_memory + (open_or_create_t, + const char *name, size_type size, + const void *addr = 0, + const permissions &perm = permissions()) + : m_wshm(open_or_create, name, size, read_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpenOrCreate), perm) + {} + + //!Connects to a created shared memory and its segment manager. + //!This can throw. + basic_managed_windows_shared_memory + (open_only_t, const char* name, const void *addr = 0) + : m_wshm(open_only, name, read_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager + //!in copy_on_write mode. + //!This can throw. + basic_managed_windows_shared_memory + (open_copy_on_write_t, const char* name, const void *addr = 0) + : m_wshm(open_only, name, copy_on_write, addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager + //!in read-only mode. + //!This can throw. + basic_managed_windows_shared_memory + (open_read_only_t, const char* name, const void *addr = 0) + : base_t() + , m_wshm(open_only, name, read_only, addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoOpen)) + {} + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_windows_shared_memory + (BOOST_RV_REF(basic_managed_windows_shared_memory) moved) + { this->swap(moved); } + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_windows_shared_memory &operator=(BOOST_RV_REF(basic_managed_windows_shared_memory) moved) + { + basic_managed_windows_shared_memory tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. All mapped regions are still valid after + //!destruction. When all mapped regions and basic_managed_windows_shared_memory + //!objects referring the shared memory are destroyed, the + //!operating system will destroy the shared memory. + ~basic_managed_windows_shared_memory() + {} + + //!Swaps the ownership of the managed mapped memories managed by *this and other. + //!Never throws. + void swap(basic_managed_windows_shared_memory &other) + { + base_t::swap(other); + m_wshm.swap(other.m_wshm); + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find (char_ptr_holder_t name) + { + if(m_wshm.get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + + private: + typename ipcdetail::wshmem_open_or_create::type m_wshm; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Typedef for a default basic_managed_windows_shared_memory +//!of narrow characters +typedef basic_managed_windows_shared_memory + + ,iset_index> +managed_windows_shared_memory; + +//!Typedef for a default basic_managed_windows_shared_memory +//!of wide characters +typedef basic_managed_windows_shared_memory + + ,iset_index> +wmanaged_windows_shared_memory; + +#endif //#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_WINDOWS_SHARED_MEMORY_HPP diff --git a/libraries/boost/boost/interprocess/managed_xsi_shared_memory.hpp b/libraries/boost/boost/interprocess/managed_xsi_shared_memory.hpp new file mode 100644 index 000000000..096a6d255 --- /dev/null +++ b/libraries/boost/boost/interprocess/managed_xsi_shared_memory.hpp @@ -0,0 +1,229 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_XSI_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_MANAGED_XSI_SHARED_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#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 +//These includes needed to fulfill default template parameters of +//predeclarations in interprocess_fwd.hpp +#include +#include +#include + +namespace boost { + +namespace interprocess { + +namespace ipcdetail { + +template +struct xsishmem_open_or_create +{ + typedef ipcdetail::managed_open_or_create_impl //!FileBased, StoreDevice + < xsi_shared_memory_file_wrapper, AllocationAlgorithm::Alignment, false, true> type; +}; + +} //namespace ipcdetail { + +//!A basic X/Open System Interface (XSI) shared memory named object creation class. Initializes the +//!shared memory segment. Inherits all basic functionality from +//!basic_managed_memory_impl +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +class basic_managed_xsi_shared_memory + : public ipcdetail::basic_managed_memory_impl + ::type::ManagedOpenOrCreateUserOffset> + , private ipcdetail::xsishmem_open_or_create::type +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + public: + typedef xsi_shared_memory_file_wrapper device_type; + + public: + typedef typename ipcdetail::xsishmem_open_or_create::type base2_t; + typedef ipcdetail::basic_managed_memory_impl + base_t; + + typedef ipcdetail::create_open_func create_open_func_t; + + basic_managed_xsi_shared_memory *get_this_pointer() + { return this; } + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_xsi_shared_memory) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: //functions + typedef typename base_t::size_type size_type; + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~basic_managed_xsi_shared_memory() + {} + + //!Default constructor. Does nothing. + //!Useful in combination with move semantics + basic_managed_xsi_shared_memory() + {} + + //!Creates shared memory and creates and places the segment manager. + //!This can throw. + basic_managed_xsi_shared_memory(create_only_t, const xsi_key &key, + std::size_t size, const void *addr = 0, const permissions& perm = permissions()) + : base_t() + , base2_t(create_only, key, size, read_write, addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm) + {} + + //!Creates shared memory and creates and places the segment manager if + //!segment was not created. If segment was created it connects to the + //!segment. + //!This can throw. + basic_managed_xsi_shared_memory (open_or_create_t, + const xsi_key &key, std::size_t size, + const void *addr = 0, const permissions& perm = permissions()) + : base_t() + , base2_t(open_or_create, key, size, read_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpenOrCreate), perm) + {} + + //!Connects to a created shared memory and its segment manager. + //!in read-only mode. + //!This can throw. + basic_managed_xsi_shared_memory (open_read_only_t, const xsi_key &key, + const void *addr = 0) + : base_t() + , base2_t(open_only, key, read_only, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager. + //!This can throw. + basic_managed_xsi_shared_memory (open_only_t, const xsi_key &key, + const void *addr = 0) + : base_t() + , base2_t(open_only, key, read_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpen)) + {} + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_xsi_shared_memory(BOOST_RV_REF(basic_managed_xsi_shared_memory) moved) + { + basic_managed_xsi_shared_memory tmp; + this->swap(moved); + tmp.swap(moved); + } + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_xsi_shared_memory &operator=(BOOST_RV_REF(basic_managed_xsi_shared_memory) moved) + { + basic_managed_xsi_shared_memory tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps the ownership of the managed shared memories managed by *this and other. + //!Never throws. + void swap(basic_managed_xsi_shared_memory &other) + { + base_t::swap(other); + base2_t::swap(other); + } + + //!Erases a XSI shared memory object identified by shmid + //!from the system. + //!Returns false on error. Never throws + static bool remove(int shmid) + { return device_type::remove(shmid); } + + int get_shmid() const + { return base2_t::get_device().get_shmid(); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find (char_ptr_holder_t name) + { + if(base2_t::get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Typedef for a default basic_managed_xsi_shared_memory +//!of narrow characters +typedef basic_managed_xsi_shared_memory + + ,iset_index> +managed_xsi_shared_memory; + +//!Typedef for a default basic_managed_xsi_shared_memory +//!of wide characters +typedef basic_managed_xsi_shared_memory + + ,iset_index> +wmanaged_xsi_shared_memory; + +#endif //#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_XSI_SHARED_MEMORY_HPP + diff --git a/libraries/boost/boost/interprocess/mapped_region.hpp b/libraries/boost/boost/interprocess/mapped_region.hpp new file mode 100644 index 000000000..4037a919d --- /dev/null +++ b/libraries/boost/boost/interprocess/mapped_region.hpp @@ -0,0 +1,920 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MAPPED_REGION_HPP +#define BOOST_INTERPROCESS_MAPPED_REGION_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//Some Unixes use caddr_t instead of void * in madvise +// SunOS Tru64 HP-UX AIX +#if defined(sun) || defined(__sun) || defined(__osf__) || defined(__osf) || defined(_hpux) || defined(hpux) || defined(_AIX) +#define BOOST_INTERPROCESS_MADVISE_USES_CADDR_T +#include +#endif + +//A lot of UNIXes have destructive semantics for MADV_DONTNEED, so +//we need to be careful to allow it. +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) +#define BOOST_INTERPROCESS_MADV_DONTNEED_HAS_NONDESTRUCTIVE_SEMANTICS +#endif + +#if defined (BOOST_INTERPROCESS_WINDOWS) +# include +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include +# include //mmap +# include +# include +# include +# if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) +# include //System V shared memory... +# endif +# include +# else +# error Unknown platform +# endif + +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) + +//!\file +//!Describes mapped region class + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +//Solaris declares madvise only in some configurations but defines MADV_XXX, a bit confusing. +//Predeclare it here to avoid any compilation error +#if (defined(sun) || defined(__sun)) && defined(MADV_NORMAL) +extern "C" int madvise(caddr_t, size_t, int); +#endif + +namespace ipcdetail{ class interprocess_tester; } +namespace ipcdetail{ class raw_mapped_region_creator; } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!The mapped_region class represents a portion or region created from a +//!memory_mappable object. +//! +//!The OS can map a region bigger than the requested one, as region must +//!be multiple of the page size, but mapped_region will always refer to +//!the region specified by the user. +class mapped_region +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + BOOST_MOVABLE_BUT_NOT_COPYABLE(mapped_region) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + + //!Creates a mapping region of the mapped memory "mapping", starting in + //!offset "offset", and the mapping's size will be "size". The mapping + //!can be opened for read only, read-write or copy-on-write. + //! + //!If an address is specified, both the offset and the address must be + //!multiples of the page size. + //! + //!The map is created using "default_map_options". This flag is OS + //!dependant and it should not be changed unless the user needs to + //!specify special options. + //! + //!In Windows systems "map_options" is a DWORD value passed as + //!"dwDesiredAccess" to "MapViewOfFileEx". If "default_map_options" is passed + //!it's initialized to zero. "map_options" is XORed with FILE_MAP_[COPY|READ|WRITE]. + //! + //!In UNIX systems and POSIX mappings "map_options" is an int value passed as "flags" + //!to "mmap". If "default_map_options" is specified it's initialized to MAP_NOSYNC + //!if that option exists and to zero otherwise. "map_options" XORed with MAP_PRIVATE or MAP_SHARED. + //! + //!In UNIX systems and XSI mappings "map_options" is an int value passed as "shmflg" + //!to "shmat". If "default_map_options" is specified it's initialized to zero. + //!"map_options" is XORed with SHM_RDONLY if needed. + //! + //!The OS could allocate more pages than size/page_size(), but get_address() + //!will always return the address passed in this function (if not null) and + //!get_size() will return the specified size. + template + mapped_region(const MemoryMappable& mapping + ,mode_t mode + ,offset_t offset = 0 + ,std::size_t size = 0 + ,const void *address = 0 + ,map_options_t map_options = default_map_options); + + //!Default constructor. Address will be 0 (nullptr). + //!Size will be 0. + //!Does not throw + mapped_region(); + + //!Move constructor. *this will be constructed taking ownership of "other"'s + //!region and "other" will be left in default constructor state. + mapped_region(BOOST_RV_REF(mapped_region) other) + #if defined (BOOST_INTERPROCESS_WINDOWS) + : m_base(0), m_size(0) + , m_page_offset(0) + , m_mode(read_only) + , m_file_or_mapping_hnd(ipcdetail::invalid_file()) + #else + : m_base(0), m_size(0), m_page_offset(0), m_mode(read_only), m_is_xsi(false) + #endif + { this->swap(other); } + + //!Destroys the mapped region. + //!Does not throw + ~mapped_region(); + + //!Move assignment. If *this owns a memory mapped region, it will be + //!destroyed and it will take ownership of "other"'s memory mapped region. + mapped_region &operator=(BOOST_RV_REF(mapped_region) other) + { + mapped_region tmp(boost::move(other)); + this->swap(tmp); + return *this; + } + + //!Swaps the mapped_region with another + //!mapped region + void swap(mapped_region &other); + + //!Returns the size of the mapping. Never throws. + std::size_t get_size() const; + + //!Returns the base address of the mapping. + //!Never throws. + void* get_address() const; + + //!Returns the mode of the mapping used to construct the mapped region. + //!Never throws. + mode_t get_mode() const; + + //!Flushes to the disk a byte range within the mapped memory. + //!If 'async' is true, the function will return before flushing operation is completed + //!If 'async' is false, function will return once data has been written into the underlying + //!device (i.e., in mapped files OS cached information is written to disk). + //!Never throws. Returns false if operation could not be performed. + bool flush(std::size_t mapping_offset = 0, std::size_t numbytes = 0, bool async = true); + + //!Shrinks current mapped region. If after shrinking there is no longer need for a previously + //!mapped memory page, accessing that page can trigger a segmentation fault. + //!Depending on the OS, this operation might fail (XSI shared memory), it can decommit storage + //!and free a portion of the virtual address space (e.g.POSIX) or this + //!function can release some physical memory wihout freeing any virtual address space(Windows). + //!Returns true on success. Never throws. + bool shrink_by(std::size_t bytes, bool from_back = true); + + //!This enum specifies region usage behaviors that an application can specify + //!to the mapped region implementation. + enum advice_types{ + //!Specifies that the application has no advice to give on its behavior with respect to + //!the region. It is the default characteristic if no advice is given for a range of memory. + advice_normal, + //!Specifies that the application expects to access the region sequentially from + //!lower addresses to higher addresses. The implementation can lower the priority of + //!preceding pages within the region once a page have been accessed. + advice_sequential, + //!Specifies that the application expects to access the region in a random order, + //!and prefetching is likely not advantageous. + advice_random, + //!Specifies that the application expects to access the region in the near future. + //!The implementation can prefetch pages of the region. + advice_willneed, + //!Specifies that the application expects that it will not access the region in the near future. + //!The implementation can unload pages within the range to save system resources. + advice_dontneed + }; + + //!Advises the implementation on the expected behavior of the application with respect to the data + //!in the region. The implementation may use this information to optimize handling of the region data. + //!This function has no effect on the semantics of access to memory in the region, although it may affect + //!the performance of access. + //!If the advise type is not known to the implementation, the function returns false. True otherwise. + bool advise(advice_types advise); + + //!Returns the size of the page. This size is the minimum memory that + //!will be used by the system when mapping a memory mappable source and + //!will restrict the address and the offset to map. + static std::size_t get_page_size(); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + //!Closes a previously opened memory mapping. Never throws + void priv_close(); + + void* priv_map_address() const; + std::size_t priv_map_size() const; + bool priv_flush_param_check(std::size_t mapping_offset, void *&addr, std::size_t &numbytes) const; + bool priv_shrink_param_check(std::size_t bytes, bool from_back, void *&shrink_page_start, std::size_t &shrink_page_bytes); + static void priv_size_from_mapping_size + (offset_t mapping_size, offset_t offset, offset_t page_offset, std::size_t &size); + static offset_t priv_page_offset_addr_fixup(offset_t page_offset, const void *&addr); + + template + struct page_size_holder + { + static const std::size_t PageSize; + static std::size_t get_page_size(); + }; + + void* m_base; + std::size_t m_size; + std::size_t m_page_offset; + mode_t m_mode; + #if defined(BOOST_INTERPROCESS_WINDOWS) + file_handle_t m_file_or_mapping_hnd; + #else + bool m_is_xsi; + #endif + + friend class ipcdetail::interprocess_tester; + friend class ipcdetail::raw_mapped_region_creator; + void dont_close_on_destruction(); + #if defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) + template + static void destroy_syncs_in_range(const void *addr, std::size_t size); + #endif + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline void swap(mapped_region &x, mapped_region &y) +{ x.swap(y); } + +inline mapped_region::~mapped_region() +{ this->priv_close(); } + +inline std::size_t mapped_region::get_size() const +{ return m_size; } + +inline mode_t mapped_region::get_mode() const +{ return m_mode; } + +inline void* mapped_region::get_address() const +{ return m_base; } + +inline void* mapped_region::priv_map_address() const +{ return static_cast(m_base) - m_page_offset; } + +inline std::size_t mapped_region::priv_map_size() const +{ return m_size + m_page_offset; } + +inline bool mapped_region::priv_flush_param_check + (std::size_t mapping_offset, void *&addr, std::size_t &numbytes) const +{ + //Check some errors + if(m_base == 0) + return false; + + if(mapping_offset >= m_size || (mapping_offset + numbytes) > m_size){ + return false; + } + + //Update flush size if the user does not provide it + if(numbytes == 0){ + numbytes = m_size - mapping_offset; + } + addr = (char*)this->priv_map_address() + mapping_offset; + numbytes += m_page_offset; + return true; +} + +inline bool mapped_region::priv_shrink_param_check + (std::size_t bytes, bool from_back, void *&shrink_page_start, std::size_t &shrink_page_bytes) +{ + //Check some errors + if(m_base == 0 || bytes > m_size){ + return false; + } + else if(bytes == m_size){ + this->priv_close(); + return true; + } + else{ + const std::size_t page_size = mapped_region::get_page_size(); + if(from_back){ + const std::size_t new_pages = (m_size + m_page_offset - bytes - 1)/page_size + 1; + shrink_page_start = static_cast(this->priv_map_address()) + new_pages*page_size; + shrink_page_bytes = m_page_offset + m_size - new_pages*page_size; + m_size -= bytes; + } + else{ + shrink_page_start = this->priv_map_address(); + m_page_offset += bytes; + shrink_page_bytes = (m_page_offset/page_size)*page_size; + m_page_offset = m_page_offset % page_size; + m_size -= bytes; + m_base = static_cast(m_base) + bytes; + BOOST_ASSERT(shrink_page_bytes%page_size == 0); + } + return true; + } +} + +inline void mapped_region::priv_size_from_mapping_size + (offset_t mapping_size, offset_t offset, offset_t page_offset, std::size_t &size) +{ + //Check if mapping size fits in the user address space + //as offset_t is the maximum file size and its signed. + if(mapping_size < offset || + boost::uintmax_t(mapping_size - (offset - page_offset)) > + boost::uintmax_t(std::size_t(-1))){ + error_info err(size_error); + throw interprocess_exception(err); + } + size = static_cast(mapping_size - (offset - page_offset)); +} + +inline offset_t mapped_region::priv_page_offset_addr_fixup(offset_t offset, const void *&address) +{ + //We can't map any offset so we have to obtain system's + //memory granularity + const std::size_t page_size = mapped_region::get_page_size(); + + //We calculate the difference between demanded and valid offset + //(always less than a page in std::size_t, thus, representable by std::size_t) + const std::size_t page_offset = + static_cast(offset - (offset / page_size) * page_size); + //Update the mapping address + if(address){ + address = static_cast(address) - page_offset; + } + return page_offset; +} + +#if defined (BOOST_INTERPROCESS_WINDOWS) + +inline mapped_region::mapped_region() + : m_base(0), m_size(0), m_page_offset(0), m_mode(read_only) + , m_file_or_mapping_hnd(ipcdetail::invalid_file()) +{} + +template +inline std::size_t mapped_region::page_size_holder::get_page_size() +{ + winapi::system_info info; + winapi::get_system_info(&info); + return std::size_t(info.dwAllocationGranularity); +} + +template +inline mapped_region::mapped_region + (const MemoryMappable &mapping + ,mode_t mode + ,offset_t offset + ,std::size_t size + ,const void *address + ,map_options_t map_options) + : m_base(0), m_size(0), m_page_offset(0), m_mode(mode) + , m_file_or_mapping_hnd(ipcdetail::invalid_file()) +{ + mapping_handle_t mhandle = mapping.get_mapping_handle(); + { + file_handle_t native_mapping_handle = 0; + + //Set accesses + //For "create_file_mapping" + unsigned long protection = 0; + //For "mapviewoffile" + unsigned long map_access = map_options == default_map_options ? 0 : map_options; + + switch(mode) + { + case read_only: + case read_private: + protection |= winapi::page_readonly; + map_access |= winapi::file_map_read; + break; + case read_write: + protection |= winapi::page_readwrite; + map_access |= winapi::file_map_write; + break; + case copy_on_write: + protection |= winapi::page_writecopy; + map_access |= winapi::file_map_copy; + break; + default: + { + error_info err(mode_error); + throw interprocess_exception(err); + } + break; + } + + //For file mapping (including emulated shared memory through temporary files), + //the device is a file handle so we need to obtain file's size and call create_file_mapping + //to obtain the mapping handle. + //For files we don't need the file mapping after mapping the memory, as the file is there + //so we'll program the handle close + void * handle_to_close = winapi::invalid_handle_value; + if(!mhandle.is_shm){ + //Create mapping handle + native_mapping_handle = winapi::create_file_mapping + ( ipcdetail::file_handle_from_mapping_handle(mapping.get_mapping_handle()) + , protection, 0, 0, 0); + + //Check if all is correct + if(!native_mapping_handle){ + error_info err = winapi::get_last_error(); + throw interprocess_exception(err); + } + handle_to_close = native_mapping_handle; + } + else{ + //For windows_shared_memory the device handle is already a mapping handle + //and we need to maintain it + native_mapping_handle = mhandle.handle; + } + //RAII handle close on scope exit + const winapi::handle_closer close_handle(handle_to_close); + (void)close_handle; + + const offset_t page_offset = priv_page_offset_addr_fixup(offset, address); + + //Obtain mapping size if user provides 0 size + if(size == 0){ + offset_t mapping_size; + if(!winapi::get_file_mapping_size(native_mapping_handle, mapping_size)){ + error_info err = winapi::get_last_error(); + throw interprocess_exception(err); + } + //This can throw + priv_size_from_mapping_size(mapping_size, offset, page_offset, size); + } + + //Map with new offsets and size + void *base = winapi::map_view_of_file_ex + (native_mapping_handle, + map_access, + offset - page_offset, + static_cast(page_offset + size), + const_cast(address)); + //Check error + if(!base){ + error_info err = winapi::get_last_error(); + throw interprocess_exception(err); + } + + //Calculate new base for the user + m_base = static_cast(base) + page_offset; + m_page_offset = page_offset; + m_size = size; + } + //Windows shared memory needs the duplication of the handle if we want to + //make mapped_region independent from the mappable device + // + //For mapped files, we duplicate the file handle to be able to FlushFileBuffers + if(!winapi::duplicate_current_process_handle(mhandle.handle, &m_file_or_mapping_hnd)){ + error_info err = winapi::get_last_error(); + this->priv_close(); + throw interprocess_exception(err); + } +} + +inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes, bool async) +{ + void *addr; + if(!this->priv_flush_param_check(mapping_offset, addr, numbytes)){ + return false; + } + //Flush it all + if(!winapi::flush_view_of_file(addr, numbytes)){ + return false; + } + //m_file_or_mapping_hnd can be a file handle or a mapping handle. + //so flushing file buffers has only sense for files... + else if(!async && m_file_or_mapping_hnd != winapi::invalid_handle_value && + winapi::get_file_type(m_file_or_mapping_hnd) == winapi::file_type_disk){ + return winapi::flush_file_buffers(m_file_or_mapping_hnd); + } + return true; +} + +inline bool mapped_region::shrink_by(std::size_t bytes, bool from_back) +{ + void *shrink_page_start = 0; + std::size_t shrink_page_bytes = 0; + if(!this->priv_shrink_param_check(bytes, from_back, shrink_page_start, shrink_page_bytes)){ + return false; + } + else if(shrink_page_bytes){ + //In Windows, we can't decommit the storage or release the virtual address space, + //the best we can do is try to remove some memory from the process working set. + //With a bit of luck we can free some physical memory. + unsigned long old_protect_ignored; + bool b_ret = winapi::virtual_unlock(shrink_page_start, shrink_page_bytes) + || (winapi::get_last_error() == winapi::error_not_locked); + (void)old_protect_ignored; + //Change page protection to forbid any further access + b_ret = b_ret && winapi::virtual_protect + (shrink_page_start, shrink_page_bytes, winapi::page_noaccess, old_protect_ignored); + return b_ret; + } + else{ + return true; + } +} + +inline bool mapped_region::advise(advice_types) +{ + //Windows has no madvise/posix_madvise equivalent + return false; +} + +inline void mapped_region::priv_close() +{ + if(m_base){ + void *addr = this->priv_map_address(); + #if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) + mapped_region::destroy_syncs_in_range<0>(addr, m_size); + #endif + winapi::unmap_view_of_file(addr); + m_base = 0; + } + if(m_file_or_mapping_hnd != ipcdetail::invalid_file()){ + winapi::close_handle(m_file_or_mapping_hnd); + m_file_or_mapping_hnd = ipcdetail::invalid_file(); + } +} + +inline void mapped_region::dont_close_on_destruction() +{} + +#else //#if defined (BOOST_INTERPROCESS_WINDOWS) + +inline mapped_region::mapped_region() + : m_base(0), m_size(0), m_page_offset(0), m_mode(read_only), m_is_xsi(false) +{} + +template +inline std::size_t mapped_region::page_size_holder::get_page_size() +{ return std::size_t(sysconf(_SC_PAGESIZE)); } + +template +inline mapped_region::mapped_region + ( const MemoryMappable &mapping + , mode_t mode + , offset_t offset + , std::size_t size + , const void *address + , map_options_t map_options) + : m_base(0), m_size(0), m_page_offset(0), m_mode(mode), m_is_xsi(false) +{ + mapping_handle_t map_hnd = mapping.get_mapping_handle(); + + //Some systems dont' support XSI shared memory + #ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + if(map_hnd.is_xsi){ + //Get the size + ::shmid_ds xsi_ds; + int ret = ::shmctl(map_hnd.handle, IPC_STAT, &xsi_ds); + if(ret == -1){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //Compare sizess + if(size == 0){ + size = (std::size_t)xsi_ds.shm_segsz; + } + else if(size != (std::size_t)xsi_ds.shm_segsz){ + error_info err(size_error); + throw interprocess_exception(err); + } + //Calculate flag + int flag = map_options == default_map_options ? 0 : map_options; + if(m_mode == read_only){ + flag |= SHM_RDONLY; + } + else if(m_mode != read_write){ + error_info err(mode_error); + throw interprocess_exception(err); + } + //Attach memory + void *base = ::shmat(map_hnd.handle, (void*)address, flag); + if(base == (void*)-1){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //Update members + m_base = base; + m_size = size; + m_mode = mode; + m_page_offset = 0; + m_is_xsi = true; + return; + } + #endif //ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + + //We calculate the difference between demanded and valid offset + const offset_t page_offset = priv_page_offset_addr_fixup(offset, address); + + if(size == 0){ + struct ::stat buf; + if(0 != fstat(map_hnd.handle, &buf)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //This can throw + priv_size_from_mapping_size(buf.st_size, offset, page_offset, size); + } + + #ifdef MAP_NOSYNC + #define BOOST_INTERPROCESS_MAP_NOSYNC MAP_NOSYNC + #else + #define BOOST_INTERPROCESS_MAP_NOSYNC 0 + #endif //MAP_NOSYNC + + //Create new mapping + int prot = 0; + int flags = map_options == default_map_options ? BOOST_INTERPROCESS_MAP_NOSYNC : map_options; + + #undef BOOST_INTERPROCESS_MAP_NOSYNC + + switch(mode) + { + case read_only: + prot |= PROT_READ; + flags |= MAP_SHARED; + break; + + case read_private: + prot |= (PROT_READ); + flags |= MAP_PRIVATE; + break; + + case read_write: + prot |= (PROT_WRITE | PROT_READ); + flags |= MAP_SHARED; + break; + + case copy_on_write: + prot |= (PROT_WRITE | PROT_READ); + flags |= MAP_PRIVATE; + break; + + default: + { + error_info err(mode_error); + throw interprocess_exception(err); + } + break; + } + + //Map it to the address space + void* base = mmap ( const_cast(address) + , static_cast(page_offset + size) + , prot + , flags + , mapping.get_mapping_handle().handle + , offset - page_offset); + + //Check if mapping was successful + if(base == MAP_FAILED){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + + //Calculate new base for the user + m_base = static_cast(base) + page_offset; + m_page_offset = page_offset; + m_size = size; + + //Check for fixed mapping error + if(address && (base != address)){ + error_info err(busy_error); + this->priv_close(); + throw interprocess_exception(err); + } +} + +inline bool mapped_region::shrink_by(std::size_t bytes, bool from_back) +{ + void *shrink_page_start = 0; + std::size_t shrink_page_bytes = 0; + if(m_is_xsi || !this->priv_shrink_param_check(bytes, from_back, shrink_page_start, shrink_page_bytes)){ + return false; + } + else if(shrink_page_bytes){ + //In UNIX we can decommit and free virtual address space. + return 0 == munmap(shrink_page_start, shrink_page_bytes); + } + else{ + return true; + } +} + +inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes, bool async) +{ + void *addr; + if(m_is_xsi || !this->priv_flush_param_check(mapping_offset, addr, numbytes)){ + return false; + } + //Flush it all + return msync(addr, numbytes, async ? MS_ASYNC : MS_SYNC) == 0; +} + +inline bool mapped_region::advise(advice_types advice) +{ + int unix_advice = 0; + //Modes; 0: none, 2: posix, 1: madvise + const unsigned int mode_none = 0; + const unsigned int mode_padv = 1; + const unsigned int mode_madv = 2; + // Suppress "unused variable" warnings + (void)mode_padv; + (void)mode_madv; + unsigned int mode = mode_none; + //Choose advice either from POSIX (preferred) or native Unix + switch(advice){ + case advice_normal: + #if defined(POSIX_MADV_NORMAL) + unix_advice = POSIX_MADV_NORMAL; + mode = mode_padv; + #elif defined(MADV_NORMAL) + unix_advice = MADV_NORMAL; + mode = mode_madv; + #endif + break; + case advice_sequential: + #if defined(POSIX_MADV_SEQUENTIAL) + unix_advice = POSIX_MADV_SEQUENTIAL; + mode = mode_padv; + #elif defined(MADV_SEQUENTIAL) + unix_advice = MADV_SEQUENTIAL; + mode = mode_madv; + #endif + break; + case advice_random: + #if defined(POSIX_MADV_RANDOM) + unix_advice = POSIX_MADV_RANDOM; + mode = mode_padv; + #elif defined(MADV_RANDOM) + unix_advice = MADV_RANDOM; + mode = mode_madv; + #endif + break; + case advice_willneed: + #if defined(POSIX_MADV_WILLNEED) + unix_advice = POSIX_MADV_WILLNEED; + mode = mode_padv; + #elif defined(MADV_WILLNEED) + unix_advice = MADV_WILLNEED; + mode = mode_madv; + #endif + break; + case advice_dontneed: + #if defined(POSIX_MADV_DONTNEED) + unix_advice = POSIX_MADV_DONTNEED; + mode = mode_padv; + #elif defined(MADV_DONTNEED) && defined(BOOST_INTERPROCESS_MADV_DONTNEED_HAS_NONDESTRUCTIVE_SEMANTICS) + unix_advice = MADV_DONTNEED; + mode = mode_madv; + #endif + break; + default: + return false; + } + switch(mode){ + #if defined(POSIX_MADV_NORMAL) + case mode_padv: + return 0 == posix_madvise(this->priv_map_address(), this->priv_map_size(), unix_advice); + #endif + #if defined(MADV_NORMAL) + case mode_madv: + return 0 == madvise( + #if defined(BOOST_INTERPROCESS_MADVISE_USES_CADDR_T) + (caddr_t) + #endif + this->priv_map_address(), this->priv_map_size(), unix_advice); + #endif + default: + return false; + + } +} + +inline void mapped_region::priv_close() +{ + if(m_base != 0){ + #ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + if(m_is_xsi){ + int ret = ::shmdt(m_base); + BOOST_ASSERT(ret == 0); + (void)ret; + return; + } + #endif //#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + munmap(this->priv_map_address(), this->priv_map_size()); + m_base = 0; + } +} + +inline void mapped_region::dont_close_on_destruction() +{ m_base = 0; } + +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) + +template +const std::size_t mapped_region::page_size_holder::PageSize + = mapped_region::page_size_holder::get_page_size(); + +inline std::size_t mapped_region::get_page_size() +{ + if(!page_size_holder<0>::PageSize) + return page_size_holder<0>::get_page_size(); + else + return page_size_holder<0>::PageSize; +} + +inline void mapped_region::swap(mapped_region &other) +{ + ::boost::adl_move_swap(this->m_base, other.m_base); + ::boost::adl_move_swap(this->m_size, other.m_size); + ::boost::adl_move_swap(this->m_page_offset, other.m_page_offset); + ::boost::adl_move_swap(this->m_mode, other.m_mode); + #if defined (BOOST_INTERPROCESS_WINDOWS) + ::boost::adl_move_swap(this->m_file_or_mapping_hnd, other.m_file_or_mapping_hnd); + #else + ::boost::adl_move_swap(this->m_is_xsi, other.m_is_xsi); + #endif +} + +//!No-op functor +struct null_mapped_region_function +{ + bool operator()(void *, std::size_t , bool) const + { return true; } + + static std::size_t get_min_size() + { return 0; } +}; + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MAPPED_REGION_HPP + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#ifndef BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP +#define BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP + +#if defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) +# include +# include + +namespace boost { +namespace interprocess { + +template +inline void mapped_region::destroy_syncs_in_range(const void *addr, std::size_t size) +{ + ipcdetail::sync_handles &handles = + ipcdetail::windows_intermodule_singleton::get(); + handles.destroy_syncs_in_range(addr, size); +} + +} //namespace interprocess { +} //namespace boost { + +#endif //defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) + +#endif //#ifdef BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP + +#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + diff --git a/libraries/boost/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/libraries/boost/boost/interprocess/mem_algo/detail/mem_algo_common.hpp new file mode 100644 index 000000000..87293d18f --- /dev/null +++ b/libraries/boost/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -0,0 +1,596 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP +#define BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +// interprocess +#include +#include +// interprocess/detail +#include +#include +#include +#include +// container/detail +#include +#include +// move +#include +// other boost +#include +#include + +//!\file +//!Implements common operations for memory algorithms. + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +class basic_multiallocation_chain + : public boost::container::container_detail:: + basic_multiallocation_chain +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_multiallocation_chain) + typedef boost::container::container_detail:: + basic_multiallocation_chain base_t; + public: + + basic_multiallocation_chain() + : base_t() + {} + + basic_multiallocation_chain(BOOST_RV_REF(basic_multiallocation_chain) other) + : base_t(::boost::move(static_cast(other))) + {} + + basic_multiallocation_chain& operator=(BOOST_RV_REF(basic_multiallocation_chain) other) + { + this->base_t::operator=(::boost::move(static_cast(other))); + return *this; + } + + void *pop_front() + { + return boost::interprocess::ipcdetail::to_raw_pointer(this->base_t::pop_front()); + } +}; + + +//!This class implements several allocation functions shared by different algorithms +//!(aligned allocation, multiple allocation...). +template +class memory_algorithm_common +{ + public: + typedef typename MemoryAlgorithm::void_pointer void_pointer; + typedef typename MemoryAlgorithm::block_ctrl block_ctrl; + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; + typedef memory_algorithm_common this_type; + typedef typename MemoryAlgorithm::size_type size_type; + + static const size_type Alignment = MemoryAlgorithm::Alignment; + static const size_type MinBlockUnits = MemoryAlgorithm::MinBlockUnits; + static const size_type AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes; + static const size_type AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits; + static const size_type BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes; + static const size_type BlockCtrlUnits = MemoryAlgorithm::BlockCtrlUnits; + static const size_type UsableByPreviousChunk = MemoryAlgorithm::UsableByPreviousChunk; + + static void assert_alignment(const void *ptr) + { assert_alignment((std::size_t)ptr); } + + static void assert_alignment(size_type uint_ptr) + { + (void)uint_ptr; + BOOST_ASSERT(uint_ptr % Alignment == 0); + } + + static bool check_alignment(const void *ptr) + { return (((std::size_t)ptr) % Alignment == 0); } + + static size_type ceil_units(size_type size) + { return get_rounded_size(size, Alignment)/Alignment; } + + static size_type floor_units(size_type size) + { return size/Alignment; } + + static size_type multiple_of_units(size_type size) + { return get_rounded_size(size, Alignment); } + + static void allocate_many + (MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + { + return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0, chain); + } + + static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain) + { + return this_type::priv_deallocate_many(memory_algo, chain); + } + + static bool calculate_lcm_and_needs_backwards_lcmed + (size_type backwards_multiple, size_type received_size, size_type size_to_achieve, + size_type &lcm_out, size_type &needs_backwards_lcmed_out) + { + // Now calculate lcm_val + size_type max = backwards_multiple; + size_type min = Alignment; + size_type needs_backwards; + size_type needs_backwards_lcmed; + size_type lcm_val; + size_type current_forward; + //Swap if necessary + if(max < min){ + size_type tmp = min; + min = max; + max = tmp; + } + //Check if it's power of two + if((backwards_multiple & (backwards_multiple-1)) == 0){ + if(0 != (size_to_achieve & ((backwards_multiple-1)))){ + return false; + } + + lcm_val = max; + //If we want to use minbytes data to get a buffer between maxbytes + //and minbytes if maxbytes can't be achieved, calculate the + //biggest of all possibilities + current_forward = get_truncated_size_po2(received_size, backwards_multiple); + needs_backwards = size_to_achieve - current_forward; + BOOST_ASSERT((needs_backwards % backwards_multiple) == 0); + needs_backwards_lcmed = get_rounded_size_po2(needs_backwards, lcm_val); + lcm_out = lcm_val; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of alignment + else if((backwards_multiple & (Alignment - 1u)) == 0){ + lcm_val = backwards_multiple; + current_forward = get_truncated_size(received_size, backwards_multiple); + //No need to round needs_backwards because backwards_multiple == lcm_val + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + BOOST_ASSERT((needs_backwards_lcmed & (Alignment - 1u)) == 0); + lcm_out = lcm_val; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of the half of the alignmment + else if((backwards_multiple & ((Alignment/2u) - 1u)) == 0){ + lcm_val = backwards_multiple*2u; + current_forward = get_truncated_size(received_size, backwards_multiple); + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + if(0 != (needs_backwards_lcmed & (Alignment-1))) + //while(0 != (needs_backwards_lcmed & (Alignment-1))) + needs_backwards_lcmed += backwards_multiple; + BOOST_ASSERT((needs_backwards_lcmed % lcm_val) == 0); + lcm_out = lcm_val; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of the quarter of the alignmment + else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){ + size_type remainder; + lcm_val = backwards_multiple*4u; + current_forward = get_truncated_size(received_size, backwards_multiple); + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + //while(0 != (needs_backwards_lcmed & (Alignment-1))) + //needs_backwards_lcmed += backwards_multiple; + if(0 != (remainder = ((needs_backwards_lcmed & (Alignment-1))>>(Alignment/8u)))){ + if(backwards_multiple & Alignment/2u){ + needs_backwards_lcmed += (remainder)*backwards_multiple; + } + else{ + needs_backwards_lcmed += (4-remainder)*backwards_multiple; + } + } + BOOST_ASSERT((needs_backwards_lcmed % lcm_val) == 0); + lcm_out = lcm_val; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + else{ + lcm_val = lcm(max, min); + } + //If we want to use minbytes data to get a buffer between maxbytes + //and minbytes if maxbytes can't be achieved, calculate the + //biggest of all possibilities + current_forward = get_truncated_size(received_size, backwards_multiple); + needs_backwards = size_to_achieve - current_forward; + BOOST_ASSERT((needs_backwards % backwards_multiple) == 0); + needs_backwards_lcmed = get_rounded_size(needs_backwards, lcm_val); + lcm_out = lcm_val; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + + static void allocate_many + ( MemoryAlgorithm *memory_algo + , const size_type *elem_sizes + , size_type n_elements + , size_type sizeof_element + , multiallocation_chain &chain) + { + this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, chain); + } + + static void* allocate_aligned + (MemoryAlgorithm *memory_algo, size_type nbytes, size_type alignment) + { + + //Ensure power of 2 + if ((alignment & (alignment - size_type(1u))) != 0){ + //Alignment is not power of two + BOOST_ASSERT((alignment & (alignment - size_type(1u))) == 0); + return 0; + } + + size_type real_size = nbytes; + if(alignment <= Alignment){ + void *ignore_reuse = 0; + return memory_algo->priv_allocate + (boost::interprocess::allocate_new, nbytes, real_size, ignore_reuse); + } + + if(nbytes > UsableByPreviousChunk) + nbytes -= UsableByPreviousChunk; + + //We can find a aligned portion if we allocate a block that has alignment + //nbytes + alignment bytes or more. + size_type minimum_allocation = max_value + (nbytes + alignment, size_type(MinBlockUnits*Alignment)); + //Since we will split that block, we must request a bit more memory + //if the alignment is near the beginning of the buffer, because otherwise, + //there is no space for a new block before the alignment. + // + // ____ Aligned here + // | + // ----------------------------------------------------- + // | MBU | + // ----------------------------------------------------- + size_type request = + minimum_allocation + (2*MinBlockUnits*Alignment - AllocatedCtrlBytes + //prevsize - UsableByPreviousChunk + ); + + //Now allocate the buffer + real_size = request; + void *ignore_reuse = 0; + void *buffer = memory_algo->priv_allocate(boost::interprocess::allocate_new, request, real_size, ignore_reuse); + if(!buffer){ + return 0; + } + else if ((((std::size_t)(buffer)) % alignment) == 0){ + //If we are lucky and the buffer is aligned, just split it and + //return the high part + block_ctrl *first = memory_algo->priv_get_block(buffer); + size_type old_size = first->m_size; + const size_type first_min_units = + max_value(ceil_units(nbytes) + AllocatedCtrlUnits, size_type(MinBlockUnits)); + //We can create a new block in the end of the segment + if(old_size >= (first_min_units + MinBlockUnits)){ + block_ctrl *second = reinterpret_cast + (reinterpret_cast(first) + Alignment*first_min_units); + first->m_size = first_min_units; + second->m_size = old_size - first->m_size; + BOOST_ASSERT(second->m_size >= MinBlockUnits); + memory_algo->priv_mark_new_allocated_block(first); + memory_algo->priv_mark_new_allocated_block(second); + memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(second)); + } + return buffer; + } + + //Buffer not aligned, find the aligned part. + // + // ____ Aligned here + // | + // ----------------------------------------------------- + // | MBU +more | ACB | + // ----------------------------------------------------- + char *pos = reinterpret_cast + (reinterpret_cast(static_cast(buffer) + + //This is the minimum size of (2) + (MinBlockUnits*Alignment - AllocatedCtrlBytes) + + //This is the next MBU for the aligned memory + AllocatedCtrlBytes + + //This is the alignment trick + alignment - 1) & -alignment); + + //Now obtain the address of the blocks + block_ctrl *first = memory_algo->priv_get_block(buffer); + block_ctrl *second = memory_algo->priv_get_block(pos); + BOOST_ASSERT(pos <= (reinterpret_cast(first) + first->m_size*Alignment)); + BOOST_ASSERT(first->m_size >= 2*MinBlockUnits); + BOOST_ASSERT((pos + MinBlockUnits*Alignment - AllocatedCtrlBytes + nbytes*Alignment/Alignment) <= + (reinterpret_cast(first) + first->m_size*Alignment)); + //Set the new size of the first block + size_type old_size = first->m_size; + first->m_size = (size_type)(reinterpret_cast(second) - reinterpret_cast(first))/Alignment; + memory_algo->priv_mark_new_allocated_block(first); + + //Now check if we can create a new buffer in the end + // + // __"second" block + // | __Aligned here + // | | __"third" block + // -----------|-----|-----|------------------------------ + // | MBU +more | ACB | (3) | BCU | + // ----------------------------------------------------- + //This size will be the minimum size to be able to create a + //new block in the end. + const size_type second_min_units = max_value(size_type(MinBlockUnits), + ceil_units(nbytes) + AllocatedCtrlUnits ); + + //Check if we can create a new block (of size MinBlockUnits) in the end of the segment + if((old_size - first->m_size) >= (second_min_units + MinBlockUnits)){ + //Now obtain the address of the end block + block_ctrl *third = new (reinterpret_cast(second) + Alignment*second_min_units)block_ctrl; + second->m_size = second_min_units; + third->m_size = old_size - first->m_size - second->m_size; + BOOST_ASSERT(third->m_size >= MinBlockUnits); + memory_algo->priv_mark_new_allocated_block(second); + memory_algo->priv_mark_new_allocated_block(third); + memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(third)); + } + else{ + second->m_size = old_size - first->m_size; + BOOST_ASSERT(second->m_size >= MinBlockUnits); + memory_algo->priv_mark_new_allocated_block(second); + } + + memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(first)); + return memory_algo->priv_get_user_buffer(second); + } + + static bool try_shrink + (MemoryAlgorithm *memory_algo, void *ptr + ,const size_type max_size, size_type &received_size) + { + size_type const preferred_size = received_size; + (void)memory_algo; + //Obtain the real block + block_ctrl *block = memory_algo->priv_get_block(ptr); + size_type old_block_units = (size_type)block->m_size; + + //The block must be marked as allocated + BOOST_ASSERT(memory_algo->priv_is_allocated_block(block)); + + //Check if alignment and block size are right + assert_alignment(ptr); + + //Put this to a safe value + received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; + + //Now translate it to Alignment units + const size_type max_user_units = floor_units(max_size - UsableByPreviousChunk); + const size_type preferred_user_units = ceil_units(preferred_size - UsableByPreviousChunk); + + //Check if rounded max and preferred are possible correct + if(max_user_units < preferred_user_units) + return false; + + //Check if the block is smaller than the requested minimum + size_type old_user_units = old_block_units - AllocatedCtrlUnits; + + if(old_user_units < preferred_user_units) + return false; + + //If the block is smaller than the requested minimum + if(old_user_units == preferred_user_units) + return true; + + size_type shrunk_user_units = + ((BlockCtrlUnits - AllocatedCtrlUnits) >= preferred_user_units) + ? (BlockCtrlUnits - AllocatedCtrlUnits) + : preferred_user_units; + + //Some parameter checks + if(max_user_units < shrunk_user_units) + return false; + + //We must be able to create at least a new empty block + if((old_user_units - shrunk_user_units) < BlockCtrlUnits ){ + return false; + } + + //Update new size + received_size = shrunk_user_units*Alignment + UsableByPreviousChunk; + return true; + } + + static bool shrink + (MemoryAlgorithm *memory_algo, void *ptr + ,const size_type max_size, size_type &received_size) + { + size_type const preferred_size = received_size; + //Obtain the real block + block_ctrl *block = memory_algo->priv_get_block(ptr); + size_type old_block_units = (size_type)block->m_size; + + if(!try_shrink(memory_algo, ptr, max_size, received_size)){ + return false; + } + + //Check if the old size was just the shrunk size (no splitting) + if((old_block_units - AllocatedCtrlUnits) == ceil_units(preferred_size - UsableByPreviousChunk)) + return true; + + //Now we can just rewrite the size of the old buffer + block->m_size = (received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits; + BOOST_ASSERT(block->m_size >= BlockCtrlUnits); + + //We create the new block + block_ctrl *new_block = reinterpret_cast + (reinterpret_cast(block) + block->m_size*Alignment); + //Write control data to simulate this new block was previously allocated + //and deallocate it + new_block->m_size = old_block_units - block->m_size; + BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits); + memory_algo->priv_mark_new_allocated_block(block); + memory_algo->priv_mark_new_allocated_block(new_block); + memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(new_block)); + return true; + } + + private: + static void priv_allocate_many + ( MemoryAlgorithm *memory_algo + , const size_type *elem_sizes + , size_type n_elements + , size_type sizeof_element + , multiallocation_chain &chain) + { + //Note: sizeof_element == 0 indicates that we want to + //allocate n_elements of the same size "*elem_sizes" + + //Calculate the total size of all requests + size_type total_request_units = 0; + size_type elem_units = 0; + const size_type ptr_size_units = memory_algo->priv_get_total_units(sizeof(void_pointer)); + if(!sizeof_element){ + elem_units = memory_algo->priv_get_total_units(*elem_sizes); + elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; + total_request_units = n_elements*elem_units; + } + else{ + for(size_type i = 0; i < n_elements; ++i){ + if(multiplication_overflows(elem_sizes[i], sizeof_element)){ + total_request_units = 0; + break; + } + elem_units = memory_algo->priv_get_total_units(elem_sizes[i]*sizeof_element); + elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; + if(sum_overflows(total_request_units, elem_units)){ + total_request_units = 0; + break; + } + total_request_units += elem_units; + } + } + + if(total_request_units && !multiplication_overflows(total_request_units, Alignment)){ + size_type low_idx = 0; + while(low_idx < n_elements){ + size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; + size_type min_allocation = (!sizeof_element) + ? elem_units + : memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element); + min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; + + size_type received_size = total_bytes; + void *ignore_reuse = 0; + void *ret = memory_algo->priv_allocate + (boost::interprocess::allocate_new, min_allocation, received_size, ignore_reuse); + if(!ret){ + break; + } + + block_ctrl *block = memory_algo->priv_get_block(ret); + size_type received_units = (size_type)block->m_size; + char *block_address = reinterpret_cast(block); + + size_type total_used_units = 0; + while(total_used_units < received_units){ + if(sizeof_element){ + elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element); + elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; + } + if(total_used_units + elem_units > received_units) + break; + total_request_units -= elem_units; + //This is the position where the new block must be created + block_ctrl *new_block = reinterpret_cast(block_address); + assert_alignment(new_block); + + //The last block should take all the remaining space + if((low_idx + 1) == n_elements || + (total_used_units + elem_units + + ((!sizeof_element) + ? elem_units + : max_value(memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element), ptr_size_units)) + > received_units)){ + //By default, the new block will use the rest of the buffer + new_block->m_size = received_units - total_used_units; + memory_algo->priv_mark_new_allocated_block(new_block); + + //If the remaining units are bigger than needed and we can + //split it obtaining a new free memory block do it. + if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){ + size_type shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; + size_type shrunk_received = shrunk_request; + bool shrink_ok = shrink + (memory_algo + ,memory_algo->priv_get_user_buffer(new_block) + ,shrunk_request + ,shrunk_received); + (void)shrink_ok; + //Shrink must always succeed with passed parameters + BOOST_ASSERT(shrink_ok); + //Some sanity checks + BOOST_ASSERT(shrunk_request == shrunk_received); + BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits)); + //"new_block->m_size" must have been reduced to elem_units by "shrink" + BOOST_ASSERT(new_block->m_size == elem_units); + //Now update the total received units with the reduction + received_units = elem_units + total_used_units; + } + } + else{ + new_block->m_size = elem_units; + memory_algo->priv_mark_new_allocated_block(new_block); + } + + block_address += new_block->m_size*Alignment; + total_used_units += (size_type)new_block->m_size; + //Check we have enough room to overwrite the intrusive pointer + BOOST_ASSERT((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer)); + void_pointer p = ::new(memory_algo->priv_get_user_buffer(new_block), boost_container_new_t())void_pointer(0); + chain.push_back(p); + ++low_idx; + } + //Sanity check + BOOST_ASSERT(total_used_units == received_units); + } + + if(low_idx != n_elements){ + priv_deallocate_many(memory_algo, chain); + } + } + } + + static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain) + { + while(!chain.empty()){ + memory_algo->priv_deallocate(to_raw_pointer(chain.pop_front())); + } + } +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP diff --git a/libraries/boost/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/libraries/boost/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp new file mode 100644 index 000000000..5c7a420b4 --- /dev/null +++ b/libraries/boost/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp @@ -0,0 +1,1105 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP +#define BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //make_unsigned, alignment_of +#include +#include +#include + +//!\file +//!Describes sequential fit algorithm used to allocate objects in shared memory. +//!This class is intended as a base class for single segment and multi-segment +//!implementations. + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +//!This class implements the simple sequential fit algorithm with a simply +//!linked list of free buffers. +//!This class is intended as a base class for single segment and multi-segment +//!implementations. +template +class simple_seq_fit_impl +{ + //Non-copyable + simple_seq_fit_impl(); + simple_seq_fit_impl(const simple_seq_fit_impl &); + simple_seq_fit_impl &operator=(const simple_seq_fit_impl &); + + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type char_ptr; + + public: + + //!Shared interprocess_mutex family used for the rest of the Interprocess framework + typedef MutexFamily mutex_family; + //!Pointer type to be used with the rest of the Interprocess framework + typedef VoidPointer void_pointer; + typedef boost::container::container_detail:: + basic_multiallocation_chain multiallocation_chain; + + typedef typename boost::intrusive::pointer_traits::difference_type difference_type; + typedef typename boost::container::container_detail::make_unsigned::type size_type; + + + private: + class block_ctrl; + friend class block_ctrl; + + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type block_ctrl_ptr; + + //!Block control structure + class block_ctrl + { + public: + //!Offset pointer to the next block. + block_ctrl_ptr m_next; + //!This block's memory size (including block_ctrl + //!header) in BasicSize units + size_type m_size; + + size_type get_user_bytes() const + { return this->m_size*Alignment - BlockCtrlBytes; } + + size_type get_total_bytes() const + { return this->m_size*Alignment; } + }; + + //!Shared interprocess_mutex to protect memory allocate/deallocate + typedef typename MutexFamily::mutex_type interprocess_mutex; + + //!This struct includes needed data and derives from + //!interprocess_mutex to allow EBO when using null interprocess_mutex + struct header_t : public interprocess_mutex + { + //!Pointer to the first free block + block_ctrl m_root; + //!Allocated bytes for internal checking + size_type m_allocated; + //!The size of the memory segment + size_type m_size; + //!The extra size required by the segment + size_type m_extra_hdr_bytes; + } m_header; + + friend class ipcdetail::memory_algorithm_common; + + typedef ipcdetail::memory_algorithm_common algo_impl_t; + + public: + //!Constructor. "size" is the total size of the managed memory segment, + //!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(simple_seq_fit_impl) + //!offset that the allocator should not use at all. + simple_seq_fit_impl (size_type size, size_type extra_hdr_bytes); + + //!Destructor + ~simple_seq_fit_impl(); + + //!Obtains the minimum size needed by the algorithm + static size_type get_min_size (size_type extra_hdr_bytes); + + //Functions for single segment management + + //!Allocates bytes, returns 0 if there is not more memory + void* allocate (size_type nbytes); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //!Multiple element allocation, same size + void allocate_many(size_type elem_bytes, size_type num_elements, multiallocation_chain &chain) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + algo_impl_t::allocate_many(this, elem_bytes, num_elements, chain); + } + + //!Multiple element allocation, different size + void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, chain); + } + + //!Multiple element deallocation + void deallocate_many(multiallocation_chain &chain); + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Deallocates previously allocated bytes + void deallocate (void *addr); + + //!Returns the size of the memory segment + size_type get_size() const; + + //!Returns the number of free bytes of the memory segment + size_type get_free_memory() const; + + //!Increases managed memory in extra_size bytes more + void grow(size_type extra_size); + + //!Decreases managed memory as much as possible + void shrink_to_fit(); + + //!Returns true if all allocated memory has been deallocated + bool all_memory_deallocated(); + + //!Makes an internal sanity check and returns true if success + bool check_sanity(); + + //!Initializes to zero all the memory that's not in use. + //!This function is normally used for security reasons. + void zero_free_memory(); + + template + T *allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type &prefer_in_recvd_out_size, T *&reuse); + + void * raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object = 1); + + //!Returns the size of the buffer previously allocated pointed by ptr + size_type size(const void *ptr) const; + + //!Allocates aligned bytes, returns 0 if there is not more memory. + //!Alignment must be power of 2 + void* allocate_aligned (size_type nbytes, size_type alignment); + + private: + + //!Obtains the pointer returned to the user from the block control + static void *priv_get_user_buffer(const block_ctrl *block); + + //!Obtains the block control structure of the user buffer + static block_ctrl *priv_get_block(const void *ptr); + + //!Real allocation algorithm with min allocation option + void * priv_allocate(boost::interprocess::allocation_type command + ,size_type min_size + ,size_type &prefer_in_recvd_out_size, void *&reuse_ptr); + + void * priv_allocation_command(boost::interprocess::allocation_type command + ,size_type min_size + ,size_type &prefer_in_recvd_out_size + ,void *&reuse_ptr + ,size_type sizeof_object); + + //!Returns the number of total units that a user buffer + //!of "userbytes" bytes really occupies (including header) + static size_type priv_get_total_units(size_type userbytes); + + static size_type priv_first_block_offset(const void *this_ptr, size_type extra_hdr_bytes); + size_type priv_block_end_offset() const; + + //!Returns next block if it's free. + //!Returns 0 if next block is not free. + block_ctrl *priv_next_block_if_free(block_ctrl *ptr); + + //!Check if this block is free (not allocated) + bool priv_is_allocated_block(block_ctrl *ptr); + + //!Returns previous block's if it's free. + //!Returns 0 if previous block is not free. + std::pair priv_prev_block_if_free(block_ctrl *ptr); + + //!Real expand function implementation + bool priv_expand(void *ptr, size_type min_size, size_type &prefer_in_recvd_out_size); + + //!Real expand to both sides implementation + void* priv_expand_both_sides(boost::interprocess::allocation_type command + ,size_type min_size, size_type &prefer_in_recvd_out_size + ,void *reuse_ptr + ,bool only_preferred_backwards); + + //!Real private aligned allocation function + //void* priv_allocate_aligned (size_type nbytes, size_type alignment); + + //!Checks if block has enough memory and splits/unlinks the block + //!returning the address to the users + void* priv_check_and_allocate(size_type units + ,block_ctrl* prev + ,block_ctrl* block + ,size_type &received_size); + //!Real deallocation algorithm + void priv_deallocate(void *addr); + + //!Makes a new memory portion available for allocation + void priv_add_segment(void *addr, size_type size); + + void priv_mark_new_allocated_block(block_ctrl *block); + + public: + static const size_type Alignment = ::boost::container::container_detail::alignment_of + < ::boost::container::container_detail::max_align_t>::value; + private: + static const size_type BlockCtrlBytes = ipcdetail::ct_rounded_size::value; + static const size_type BlockCtrlUnits = BlockCtrlBytes/Alignment; + static const size_type MinBlockUnits = BlockCtrlUnits; + static const size_type MinBlockSize = MinBlockUnits*Alignment; + static const size_type AllocatedCtrlBytes = BlockCtrlBytes; + static const size_type AllocatedCtrlUnits = BlockCtrlUnits; + static const size_type UsableByPreviousChunk = 0; + + public: + static const size_type PayloadPerAllocation = BlockCtrlBytes; +}; + +template +inline typename simple_seq_fit_impl::size_type +simple_seq_fit_impl + ::priv_first_block_offset(const void *this_ptr, size_type extra_hdr_bytes) +{ + //First align "this" pointer + size_type uint_this = (std::size_t)this_ptr; + size_type uint_aligned_this = uint_this/Alignment*Alignment; + size_type this_disalignment = (uint_this - uint_aligned_this); + size_type block1_off = + ipcdetail::get_rounded_size(sizeof(simple_seq_fit_impl) + extra_hdr_bytes + this_disalignment, Alignment) + - this_disalignment; + algo_impl_t::assert_alignment(this_disalignment + block1_off); + return block1_off; +} + +template +inline typename simple_seq_fit_impl::size_type +simple_seq_fit_impl + ::priv_block_end_offset() const +{ + //First align "this" pointer + size_type uint_this = (std::size_t)this; + size_type uint_aligned_this = uint_this/Alignment*Alignment; + size_type this_disalignment = (uint_this - uint_aligned_this); + size_type old_end = + ipcdetail::get_truncated_size(m_header.m_size + this_disalignment, Alignment) + - this_disalignment; + algo_impl_t::assert_alignment(old_end + this_disalignment); + return old_end; +} + +template +inline simple_seq_fit_impl:: + simple_seq_fit_impl(size_type segment_size, size_type extra_hdr_bytes) +{ + //Initialize sizes and counters + m_header.m_allocated = 0; + m_header.m_size = segment_size; + m_header.m_extra_hdr_bytes = extra_hdr_bytes; + + //Initialize pointers + size_type block1_off = priv_first_block_offset(this, extra_hdr_bytes); + + m_header.m_root.m_next = reinterpret_cast + ((reinterpret_cast(this) + block1_off)); + algo_impl_t::assert_alignment(ipcdetail::to_raw_pointer(m_header.m_root.m_next)); + m_header.m_root.m_next->m_size = (segment_size - block1_off)/Alignment; + m_header.m_root.m_next->m_next = &m_header.m_root; +} + +template +inline simple_seq_fit_impl::~simple_seq_fit_impl() +{ + //There is a memory leak! +// BOOST_ASSERT(m_header.m_allocated == 0); +// BOOST_ASSERT(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root)); +} + +template +inline void simple_seq_fit_impl::grow(size_type extra_size) +{ + //Old highest address block's end offset + size_type old_end = this->priv_block_end_offset(); + + //Update managed buffer's size + m_header.m_size += extra_size; + + //We need at least MinBlockSize blocks to create a new block + if((m_header.m_size - old_end) < MinBlockSize){ + return; + } + + //We'll create a new free block with extra_size bytes + + block_ctrl *new_block = reinterpret_cast + (reinterpret_cast(this) + old_end); + + algo_impl_t::assert_alignment(new_block); + new_block->m_next = 0; + new_block->m_size = (m_header.m_size - old_end)/Alignment; + m_header.m_allocated += new_block->m_size*Alignment; + this->priv_deallocate(priv_get_user_buffer(new_block)); +} + +template +void simple_seq_fit_impl::shrink_to_fit() +{ + //Get the root and the first memory block + block_ctrl *prev = &m_header.m_root; + block_ctrl *last = &m_header.m_root; + block_ctrl *block = ipcdetail::to_raw_pointer(last->m_next); + block_ctrl *root = &m_header.m_root; + + //No free block? + if(block == root) return; + + //Iterate through the free block list + while(block != root){ + prev = last; + last = block; + block = ipcdetail::to_raw_pointer(block->m_next); + } + + char *last_free_end_address = reinterpret_cast(last) + last->m_size*Alignment; + if(last_free_end_address != (reinterpret_cast(this) + priv_block_end_offset())){ + //there is an allocated block in the end of this block + //so no shrinking is possible + return; + } + + //Check if have only 1 big free block + void *unique_block = 0; + if(!m_header.m_allocated){ + BOOST_ASSERT(prev == root); + size_type ignore_recvd = 0; + void *ignore_reuse = 0; + unique_block = priv_allocate(boost::interprocess::allocate_new, 0, ignore_recvd, ignore_reuse); + if(!unique_block) + return; + last = ipcdetail::to_raw_pointer(m_header.m_root.m_next); + BOOST_ASSERT(last_free_end_address == (reinterpret_cast(last) + last->m_size*Alignment)); + } + size_type last_units = last->m_size; + + size_type received_size; + void *addr = priv_check_and_allocate(last_units, prev, last, received_size); + (void)addr; + BOOST_ASSERT(addr); + BOOST_ASSERT(received_size == last_units*Alignment - AllocatedCtrlBytes); + + //Shrink it + m_header.m_size /= Alignment; + m_header.m_size -= last->m_size; + m_header.m_size *= Alignment; + m_header.m_allocated -= last->m_size*Alignment; + + if(unique_block) + priv_deallocate(unique_block); +} + +template +inline void simple_seq_fit_impl:: + priv_mark_new_allocated_block(block_ctrl *new_block) +{ + new_block->m_next = 0; +} + +template +inline +typename simple_seq_fit_impl::block_ctrl * + simple_seq_fit_impl::priv_get_block(const void *ptr) +{ + return const_cast(reinterpret_cast + (reinterpret_cast(ptr) - AllocatedCtrlBytes)); +} + +template +inline +void *simple_seq_fit_impl:: + priv_get_user_buffer(const typename simple_seq_fit_impl::block_ctrl *block) +{ + return const_cast(reinterpret_cast(block) + AllocatedCtrlBytes); +} + +template +inline void simple_seq_fit_impl::priv_add_segment(void *addr, size_type segment_size) +{ + algo_impl_t::assert_alignment(addr); + //Check size + BOOST_ASSERT(!(segment_size < MinBlockSize)); + if(segment_size < MinBlockSize) + return; + //Construct big block using the new segment + block_ctrl *new_block = static_cast(addr); + new_block->m_size = segment_size/Alignment; + new_block->m_next = 0; + //Simulate this block was previously allocated + m_header.m_allocated += new_block->m_size*Alignment; + //Return block and insert it in the free block list + this->priv_deallocate(priv_get_user_buffer(new_block)); +} + +template +inline typename simple_seq_fit_impl::size_type +simple_seq_fit_impl::get_size() const + { return m_header.m_size; } + +template +inline typename simple_seq_fit_impl::size_type +simple_seq_fit_impl::get_free_memory() const +{ + return m_header.m_size - m_header.m_allocated - + algo_impl_t::multiple_of_units(sizeof(*this) + m_header.m_extra_hdr_bytes); +} + +template +inline typename simple_seq_fit_impl::size_type +simple_seq_fit_impl:: + get_min_size (size_type extra_hdr_bytes) +{ + return ipcdetail::get_rounded_size((size_type)sizeof(simple_seq_fit_impl),Alignment) + + ipcdetail::get_rounded_size(extra_hdr_bytes,Alignment) + + MinBlockSize; +} + +template +inline bool simple_seq_fit_impl:: + all_memory_deallocated() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return m_header.m_allocated == 0 && + ipcdetail::to_raw_pointer(m_header.m_root.m_next->m_next) == &m_header.m_root; +} + +template +inline void simple_seq_fit_impl::zero_free_memory() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + block_ctrl *block = ipcdetail::to_raw_pointer(m_header.m_root.m_next); + + //Iterate through all free portions + do{ + //Just clear user the memory part reserved for the user + std::memset( priv_get_user_buffer(block) + , 0 + , block->get_user_bytes()); + block = ipcdetail::to_raw_pointer(block->m_next); + } + while(block != &m_header.m_root); +} + +template +inline bool simple_seq_fit_impl:: + check_sanity() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + block_ctrl *block = ipcdetail::to_raw_pointer(m_header.m_root.m_next); + + size_type free_memory = 0; + + //Iterate through all blocks obtaining their size + while(block != &m_header.m_root){ + algo_impl_t::assert_alignment(block); + if(!algo_impl_t::check_alignment(block)) + return false; + //Free blocks's next must be always valid + block_ctrl *next = ipcdetail::to_raw_pointer(block->m_next); + if(!next){ + return false; + } + free_memory += block->m_size*Alignment; + block = next; + } + + //Check allocated bytes are less than size + if(m_header.m_allocated > m_header.m_size){ + return false; + } + + //Check free bytes are less than size + if(free_memory > m_header.m_size){ + return false; + } + return true; +} + +template +inline void* simple_seq_fit_impl:: + allocate(size_type nbytes) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + size_type ignore_recvd = nbytes; + void *ignore_reuse = 0; + return priv_allocate(boost::interprocess::allocate_new, nbytes, ignore_recvd, ignore_reuse); +} + +template +inline void* simple_seq_fit_impl:: + allocate_aligned(size_type nbytes, size_type alignment) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t:: + allocate_aligned(this, nbytes, alignment); +} + +template +template +inline T* simple_seq_fit_impl:: + allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type &prefer_in_recvd_out_size, T *&reuse_ptr) +{ + void *raw_reuse = reuse_ptr; + void * const ret = priv_allocation_command + (command, limit_size, prefer_in_recvd_out_size, raw_reuse, sizeof(T)); + BOOST_ASSERT(0 == ((std::size_t)ret % ::boost::container::container_detail::alignment_of::value)); + reuse_ptr = static_cast(raw_reuse); + return static_cast(ret); +} + +template +inline void* simple_seq_fit_impl:: + raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects, + size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object) +{ + size_type const preferred_objects = prefer_in_recvd_out_size; + if(!sizeof_object){ + return reuse_ptr = 0, static_cast(0); + } + if(command & boost::interprocess::try_shrink_in_place){ + if(!reuse_ptr) return static_cast(0); + prefer_in_recvd_out_size = preferred_objects*sizeof_object; + bool success = algo_impl_t::try_shrink + ( this, reuse_ptr, limit_objects*sizeof_object, prefer_in_recvd_out_size); + prefer_in_recvd_out_size /= sizeof_object; + return success ? reuse_ptr : 0; + } + else{ + return priv_allocation_command + (command, limit_objects, prefer_in_recvd_out_size, reuse_ptr, sizeof_object); + } +} + +template +inline void* simple_seq_fit_impl:: + priv_allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object) +{ + size_type const preferred_size = prefer_in_recvd_out_size; + command &= ~boost::interprocess::expand_bwd; + if(!command){ + return reuse_ptr = 0, static_cast(0); + } + + size_type max_count = m_header.m_size/sizeof_object; + if(limit_size > max_count || preferred_size > max_count){ + return reuse_ptr = 0, static_cast(0); + } + size_type l_size = limit_size*sizeof_object; + size_type r_size = preferred_size*sizeof_object; + void *ret = 0; + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + ret = priv_allocate(command, l_size, r_size, reuse_ptr); + } + prefer_in_recvd_out_size = r_size/sizeof_object; + return ret; +} + +template +inline typename simple_seq_fit_impl::size_type +simple_seq_fit_impl::size(const void *ptr) const +{ + //We need no synchronization since this block is not going + //to be modified + //Obtain the real size of the block + const block_ctrl *block = static_cast(priv_get_block(ptr)); + return block->get_user_bytes(); +} + +template +void* simple_seq_fit_impl:: + priv_expand_both_sides(boost::interprocess::allocation_type command + ,size_type min_size + ,size_type &prefer_in_recvd_out_size + ,void *reuse_ptr + ,bool only_preferred_backwards) +{ + size_type const preferred_size = prefer_in_recvd_out_size; + typedef std::pair prev_block_t; + block_ctrl *reuse = priv_get_block(reuse_ptr); + prefer_in_recvd_out_size = 0; + + if(this->size(reuse_ptr) > min_size){ + prefer_in_recvd_out_size = this->size(reuse_ptr); + return reuse_ptr; + } + + if(command & boost::interprocess::expand_fwd){ + if(priv_expand(reuse_ptr, min_size, prefer_in_recvd_out_size = preferred_size)) + return reuse_ptr; + } + else{ + prefer_in_recvd_out_size = this->size(reuse_ptr); + } + if(command & boost::interprocess::expand_bwd){ + size_type extra_forward = !prefer_in_recvd_out_size ? 0 : prefer_in_recvd_out_size + BlockCtrlBytes; + prev_block_t prev_pair = priv_prev_block_if_free(reuse); + block_ctrl *prev = prev_pair.second; + if(!prev){ + return 0; + } + + size_type needs_backwards = + ipcdetail::get_rounded_size(preferred_size - extra_forward, Alignment); + + if(!only_preferred_backwards){ + max_value(ipcdetail::get_rounded_size(min_size - extra_forward, Alignment) + ,min_value(prev->get_user_bytes(), needs_backwards)); + } + + //Check if previous block has enough size + if((prev->get_user_bytes()) >= needs_backwards){ + //Now take all next space. This will succeed + if(!priv_expand(reuse_ptr, prefer_in_recvd_out_size, prefer_in_recvd_out_size)){ + BOOST_ASSERT(0); + } + + //We need a minimum size to split the previous one + if((prev->get_user_bytes() - needs_backwards) > 2*BlockCtrlBytes){ + block_ctrl *new_block = reinterpret_cast + (reinterpret_cast(reuse) - needs_backwards - BlockCtrlBytes); + + new_block->m_next = 0; + new_block->m_size = + BlockCtrlUnits + (needs_backwards + extra_forward)/Alignment; + prev->m_size = + (prev->get_total_bytes() - needs_backwards)/Alignment - BlockCtrlUnits; + prefer_in_recvd_out_size = needs_backwards + extra_forward; + m_header.m_allocated += needs_backwards + BlockCtrlBytes; + return priv_get_user_buffer(new_block); + } + else{ + //Just merge the whole previous block + block_ctrl *prev_2_block = prev_pair.first; + //Update received size and allocation + prefer_in_recvd_out_size = extra_forward + prev->get_user_bytes(); + m_header.m_allocated += prev->get_total_bytes(); + //Now unlink it from previous block + prev_2_block->m_next = prev->m_next; + prev->m_size = reuse->m_size + prev->m_size; + prev->m_next = 0; + priv_get_user_buffer(prev); + } + } + } + return 0; +} + +template +inline void simple_seq_fit_impl:: + deallocate_many(typename simple_seq_fit_impl::multiallocation_chain &chain) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + while(!chain.empty()){ + this->priv_deallocate(to_raw_pointer(chain.pop_front())); + } +} + +template +inline typename simple_seq_fit_impl::size_type +simple_seq_fit_impl:: + priv_get_total_units(size_type userbytes) +{ + size_type s = ipcdetail::get_rounded_size(userbytes, Alignment)/Alignment; + if(!s) ++s; + return BlockCtrlUnits + s; +} + +template +void * simple_seq_fit_impl:: + priv_allocate(boost::interprocess::allocation_type command + ,size_type limit_size, size_type &prefer_in_recvd_out_size, void *&reuse_ptr) +{ + size_type const preferred_size = prefer_in_recvd_out_size; + if(command & boost::interprocess::shrink_in_place){ + if(!reuse_ptr) return static_cast(0); + bool success = algo_impl_t::shrink(this, reuse_ptr, limit_size, prefer_in_recvd_out_size); + return success ? reuse_ptr : 0; + } + prefer_in_recvd_out_size = 0; + + if(limit_size > preferred_size){ + return reuse_ptr = 0, static_cast(0); + } + + //Number of units to request (including block_ctrl header) + size_type nunits = ipcdetail::get_rounded_size(preferred_size, Alignment)/Alignment + BlockCtrlUnits; + + //Get the root and the first memory block + block_ctrl *prev = &m_header.m_root; + block_ctrl *block = ipcdetail::to_raw_pointer(prev->m_next); + block_ctrl *root = &m_header.m_root; + block_ctrl *biggest_block = 0; + block_ctrl *prev_biggest_block = 0; + size_type biggest_size = 0; + + //Expand in place + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ + void *ret = priv_expand_both_sides(command, limit_size, prefer_in_recvd_out_size = preferred_size, reuse_ptr, true); + if(ret){ + algo_impl_t::assert_alignment(ret); + return ret; + } + } + + if(command & boost::interprocess::allocate_new){ + prefer_in_recvd_out_size = 0; + while(block != root){ + //Update biggest block pointers + if(block->m_size > biggest_size){ + prev_biggest_block = prev; + biggest_size = block->m_size; + biggest_block = block; + } + algo_impl_t::assert_alignment(block); + void *addr = this->priv_check_and_allocate(nunits, prev, block, prefer_in_recvd_out_size); + if(addr){ + algo_impl_t::assert_alignment(addr); + return reuse_ptr = 0, addr; + } + //Bad luck, let's check next block + prev = block; + block = ipcdetail::to_raw_pointer(block->m_next); + } + + //Bad luck finding preferred_size, now if we have any biggest_block + //try with this block + if(biggest_block){ + size_type limit_units = ipcdetail::get_rounded_size(limit_size, Alignment)/Alignment + BlockCtrlUnits; + if(biggest_block->m_size < limit_units){ + return reuse_ptr = 0, static_cast(0); + } + void *ret = this->priv_check_and_allocate + (biggest_block->m_size, prev_biggest_block, biggest_block, prefer_in_recvd_out_size = biggest_block->m_size*Alignment - BlockCtrlUnits); + BOOST_ASSERT(ret != 0); + algo_impl_t::assert_alignment(ret); + return reuse_ptr = 0, ret; + } + } + //Now try to expand both sides with min size + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ + void *ret = priv_expand_both_sides (command, limit_size, prefer_in_recvd_out_size = preferred_size, reuse_ptr, false); + algo_impl_t::assert_alignment(ret); + return ret; + } + return reuse_ptr = 0, static_cast(0); +} + +template inline +bool simple_seq_fit_impl::priv_is_allocated_block + (typename simple_seq_fit_impl::block_ctrl *block) +{ return block->m_next == 0; } + +template +inline typename simple_seq_fit_impl::block_ctrl * + simple_seq_fit_impl:: + priv_next_block_if_free + (typename simple_seq_fit_impl::block_ctrl *ptr) +{ + //Take the address where the next block should go + block_ctrl *next_block = reinterpret_cast + (reinterpret_cast(ptr) + ptr->m_size*Alignment); + + //Check if the adjacent block is in the managed segment + char *this_char_ptr = reinterpret_cast(this); + char *next_char_ptr = reinterpret_cast(next_block); + size_type distance = (size_type)(next_char_ptr - this_char_ptr)/Alignment; + + if(distance >= (m_header.m_size/Alignment)){ + //"next_block" does not exist so we can't expand "block" + return 0; + } + + if(!next_block->m_next) + return 0; + + return next_block; +} + +template +inline + std::pair::block_ctrl * + ,typename simple_seq_fit_impl::block_ctrl *> + simple_seq_fit_impl:: + priv_prev_block_if_free + (typename simple_seq_fit_impl::block_ctrl *ptr) +{ + typedef std::pair prev_pair_t; + //Take the address where the previous block should go + block_ctrl *root = &m_header.m_root; + block_ctrl *prev_2_block = root; + block_ctrl *prev_block = ipcdetail::to_raw_pointer(root->m_next); + + while((reinterpret_cast(prev_block) + prev_block->m_size*Alignment) + != reinterpret_cast(ptr) + && prev_block != root){ + prev_2_block = prev_block; + prev_block = ipcdetail::to_raw_pointer(prev_block->m_next); + } + + if(prev_block == root || !prev_block->m_next) + return prev_pair_t(static_cast(0), static_cast(0)); + + //Check if the previous block is in the managed segment + char *this_char_ptr = reinterpret_cast(this); + char *prev_char_ptr = reinterpret_cast(prev_block); + size_type distance = (size_type)(prev_char_ptr - this_char_ptr)/Alignment; + + if(distance >= (m_header.m_size/Alignment)){ + //"previous_block" does not exist so we can't expand "block" + return prev_pair_t(static_cast(0), static_cast(0)); + } + return prev_pair_t(prev_2_block, prev_block); +} + + +template +inline bool simple_seq_fit_impl:: + priv_expand (void *ptr, size_type min_size, size_type &received_size) +{ + size_type preferred_size = received_size; + //Obtain the real size of the block + block_ctrl *block = reinterpret_cast(priv_get_block(ptr)); + size_type old_block_size = block->m_size; + + //All used blocks' next is marked with 0 so check it + BOOST_ASSERT(block->m_next == 0); + + //Put this to a safe value + received_size = old_block_size*Alignment - BlockCtrlBytes; + + //Now translate it to Alignment units + min_size = ipcdetail::get_rounded_size(min_size, Alignment)/Alignment; + preferred_size = ipcdetail::get_rounded_size(preferred_size, Alignment)/Alignment; + + //Some parameter checks + if(min_size > preferred_size) + return false; + + size_type data_size = old_block_size - BlockCtrlUnits; + + if(data_size >= min_size) + return true; + + block_ctrl *next_block = priv_next_block_if_free(block); + if(!next_block){ + return false; + } + + //Is "block" + "next_block" big enough? + size_type merged_size = old_block_size + next_block->m_size; + + //Now we can expand this block further than before + received_size = merged_size*Alignment - BlockCtrlBytes; + + if(merged_size < (min_size + BlockCtrlUnits)){ + return false; + } + + //We can fill expand. Merge both blocks, + block->m_next = next_block->m_next; + block->m_size = merged_size; + + //Find the previous free block of next_block + block_ctrl *prev = &m_header.m_root; + while(ipcdetail::to_raw_pointer(prev->m_next) != next_block){ + prev = ipcdetail::to_raw_pointer(prev->m_next); + } + + //Now insert merged block in the free list + //This allows reusing allocation logic in this function + m_header.m_allocated -= old_block_size*Alignment; + prev->m_next = block; + + //Now use check and allocate to do the allocation logic + preferred_size += BlockCtrlUnits; + size_type nunits = preferred_size < merged_size ? preferred_size : merged_size; + + //This must success since nunits is less than merged_size! + if(!this->priv_check_and_allocate (nunits, prev, block, received_size)){ + //Something very ugly is happening here. This is a bug + //or there is memory corruption + BOOST_ASSERT(0); + return false; + } + return true; +} + +template inline +void* simple_seq_fit_impl::priv_check_and_allocate + (size_type nunits + ,typename simple_seq_fit_impl::block_ctrl* prev + ,typename simple_seq_fit_impl::block_ctrl* block + ,size_type &received_size) +{ + size_type upper_nunits = nunits + BlockCtrlUnits; + bool found = false; + + if (block->m_size > upper_nunits){ + //This block is bigger than needed, split it in + //two blocks, the first's size will be "units" + //the second's size will be "block->m_size-units" + size_type total_size = block->m_size; + block->m_size = nunits; + + block_ctrl *new_block = reinterpret_cast + (reinterpret_cast(block) + Alignment*nunits); + new_block->m_size = total_size - nunits; + new_block->m_next = block->m_next; + prev->m_next = new_block; + found = true; + } + else if (block->m_size >= nunits){ + //This block has exactly the right size with an extra + //unusable extra bytes. + prev->m_next = block->m_next; + found = true; + } + + if(found){ + //We need block_ctrl for deallocation stuff, so + //return memory user can overwrite + m_header.m_allocated += block->m_size*Alignment; + received_size = block->get_user_bytes(); + //Mark the block as allocated + block->m_next = 0; + //Check alignment + algo_impl_t::assert_alignment(block); + return priv_get_user_buffer(block); + } + return 0; +} + +template +void simple_seq_fit_impl::deallocate(void* addr) +{ + if(!addr) return; + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return this->priv_deallocate(addr); +} + +template +void simple_seq_fit_impl::priv_deallocate(void* addr) +{ + if(!addr) return; + + //Let's get free block list. List is always sorted + //by memory address to allow block merging. + //Pointer next always points to the first + //(lower address) block + block_ctrl * prev = &m_header.m_root; + block_ctrl * pos = ipcdetail::to_raw_pointer(m_header.m_root.m_next); + block_ctrl * block = reinterpret_cast(priv_get_block(addr)); + + //All used blocks' next is marked with 0 so check it + BOOST_ASSERT(block->m_next == 0); + + //Check if alignment and block size are right + algo_impl_t::assert_alignment(addr); + + size_type total_size = Alignment*block->m_size; + BOOST_ASSERT(m_header.m_allocated >= total_size); + + //Update used memory count + m_header.m_allocated -= total_size; + + //Let's find the previous and the next block of the block to deallocate + //This ordering comparison must be done with original pointers + //types since their mapping to raw pointers can be different + //in each process + while((ipcdetail::to_raw_pointer(pos) != &m_header.m_root) && (block > pos)){ + prev = pos; + pos = ipcdetail::to_raw_pointer(pos->m_next); + } + + //Try to combine with upper block + char *block_char_ptr = reinterpret_cast(ipcdetail::to_raw_pointer(block)); + + if ((block_char_ptr + Alignment*block->m_size) == + reinterpret_cast(ipcdetail::to_raw_pointer(pos))){ + block->m_size += pos->m_size; + block->m_next = pos->m_next; + } + else{ + block->m_next = pos; + } + + //Try to combine with lower block + if ((reinterpret_cast(ipcdetail::to_raw_pointer(prev)) + + Alignment*prev->m_size) == + block_char_ptr){ + + + prev->m_size += block->m_size; + prev->m_next = block->m_next; + } + else{ + prev->m_next = block; + } +} + +} //namespace ipcdetail { + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP + diff --git a/libraries/boost/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/libraries/boost/boost/interprocess/mem_algo/rbtree_best_fit.hpp new file mode 100644 index 000000000..dc4307fe7 --- /dev/null +++ b/libraries/boost/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -0,0 +1,1400 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP +#define BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +// interprocess +#include +#include +#include +#include +#include +#include +// interprocess/detail +#include +#include +#include +#include +// container +#include +// container/detail +#include +// move/detail +#include //make_unsigned, alignment_of +// intrusive +#include +#include +// other boost +#include +#include +// std +#include +#include + +//#define BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP +//to maintain ABI compatible with the original version +//ABI had to be updated to fix compatibility issues when +//sharing shared memory between 32 adn 64 bit processes. + +//!\file +//!Describes a best-fit algorithm based in an intrusive red-black tree used to allocate +//!objects in shared memory. This class is intended as a base class for single segment +//!and multi-segment implementations. + +namespace boost { +namespace interprocess { + +//!This class implements an algorithm that stores the free nodes in a red-black tree +//!to have logarithmic search/insert times. +template +class rbtree_best_fit +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + rbtree_best_fit(); + rbtree_best_fit(const rbtree_best_fit &); + rbtree_best_fit &operator=(const rbtree_best_fit &); + + private: + struct block_ctrl; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type block_ctrl_ptr; + + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type char_ptr; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Shared mutex family used for the rest of the Interprocess framework + typedef MutexFamily mutex_family; + //!Pointer type to be used with the rest of the Interprocess framework + typedef VoidPointer void_pointer; + typedef ipcdetail::basic_multiallocation_chain multiallocation_chain; + + typedef typename boost::intrusive::pointer_traits::difference_type difference_type; + typedef typename boost::container::container_detail::make_unsigned::type size_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + private: + + typedef typename bi::make_set_base_hook + < bi::void_pointer + , bi::optimize_size + , bi::link_mode >::type TreeHook; + + struct SizeHolder + { + //!This block's memory size (including block_ctrl + //!header) in Alignment units + size_type m_prev_size : sizeof(size_type)*CHAR_BIT; + size_type m_size : sizeof(size_type)*CHAR_BIT - 2; + size_type m_prev_allocated : 1; + size_type m_allocated : 1; + }; + + //!Block control structure + struct block_ctrl + : public SizeHolder, public TreeHook + { + block_ctrl() + { this->m_size = 0; this->m_allocated = 0, this->m_prev_allocated = 0; } + + friend bool operator<(const block_ctrl &a, const block_ctrl &b) + { return a.m_size < b.m_size; } + friend bool operator==(const block_ctrl &a, const block_ctrl &b) + { return a.m_size == b.m_size; } + }; + + struct size_block_ctrl_compare + { + bool operator()(size_type size, const block_ctrl &block) const + { return size < block.m_size; } + + bool operator()(const block_ctrl &block, size_type size) const + { return block.m_size < size; } + }; + + //!Shared mutex to protect memory allocate/deallocate + typedef typename MutexFamily::mutex_type mutex_type; + typedef typename bi::make_multiset + >::type Imultiset; + + typedef typename Imultiset::iterator imultiset_iterator; + typedef typename Imultiset::const_iterator imultiset_const_iterator; + + //!This struct includes needed data and derives from + //!mutex_type to allow EBO when using null mutex_type + struct header_t : public mutex_type + { + Imultiset m_imultiset; + + //!The extra size required by the segment + size_type m_extra_hdr_bytes; + //!Allocated bytes for internal checking + size_type m_allocated; + //!The size of the memory segment + size_type m_size; + } m_header; + + friend class ipcdetail::memory_algorithm_common; + + typedef ipcdetail::memory_algorithm_common algo_impl_t; + + public: + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Constructor. "size" is the total size of the managed memory segment, + //!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(rbtree_best_fit) + //!offset that the allocator should not use at all. + rbtree_best_fit (size_type size, size_type extra_hdr_bytes); + + //!Destructor. + ~rbtree_best_fit(); + + //!Obtains the minimum size needed by the algorithm + static size_type get_min_size (size_type extra_hdr_bytes); + + //Functions for single segment management + + //!Allocates bytes, returns 0 if there is not more memory + void* allocate (size_type nbytes); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Experimental. Dont' use + + //!Multiple element allocation, same size + void allocate_many(size_type elem_bytes, size_type num_elements, multiallocation_chain &chain) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + algo_impl_t::allocate_many(this, elem_bytes, num_elements, chain); + } + + //!Multiple element allocation, different size + void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, chain); + } + + //!Multiple element allocation, different size + void deallocate_many(multiallocation_chain &chain); + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Deallocates previously allocated bytes + void deallocate (void *addr); + + //!Returns the size of the memory segment + size_type get_size() const; + + //!Returns the number of free bytes of the segment + size_type get_free_memory() const; + + //!Initializes to zero all the memory that's not in use. + //!This function is normally used for security reasons. + void zero_free_memory(); + + //!Increases managed memory in + //!extra_size bytes more + void grow(size_type extra_size); + + //!Decreases managed memory as much as possible + void shrink_to_fit(); + + //!Returns true if all allocated memory has been deallocated + bool all_memory_deallocated(); + + //!Makes an internal sanity check + //!and returns true if success + bool check_sanity(); + + template + T * allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type &prefer_in_recvd_out_size, T *&reuse); + + void * raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_object, + size_type &prefer_in_recvd_out_size, + void *&reuse_ptr, size_type sizeof_object = 1); + + //!Returns the size of the buffer previously allocated pointed by ptr + size_type size(const void *ptr) const; + + //!Allocates aligned bytes, returns 0 if there is not more memory. + //!Alignment must be power of 2 + void* allocate_aligned (size_type nbytes, size_type alignment); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + static size_type priv_first_block_offset_from_this(const void *this_ptr, size_type extra_hdr_bytes); + + block_ctrl *priv_first_block(); + + block_ctrl *priv_end_block(); + + void* priv_allocation_command(boost::interprocess::allocation_type command, size_type limit_size, + size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object); + + + //!Real allocation algorithm with min allocation option + void * priv_allocate( boost::interprocess::allocation_type command + , size_type limit_size, size_type &prefer_in_recvd_out_size + , void *&reuse_ptr, size_type backwards_multiple = 1); + + //!Obtains the block control structure of the user buffer + static block_ctrl *priv_get_block(const void *ptr); + + //!Obtains the pointer returned to the user from the block control + static void *priv_get_user_buffer(const block_ctrl *block); + + //!Returns the number of total units that a user buffer + //!of "userbytes" bytes really occupies (including header) + static size_type priv_get_total_units(size_type userbytes); + + //!Real expand function implementation + bool priv_expand(void *ptr, const size_type min_size, size_type &prefer_in_recvd_out_size); + + //!Real expand to both sides implementation + void* priv_expand_both_sides(boost::interprocess::allocation_type command + ,size_type min_size + ,size_type &prefer_in_recvd_out_size + ,void *reuse_ptr + ,bool only_preferred_backwards + ,size_type backwards_multiple); + + //!Returns true if the previous block is allocated + bool priv_is_prev_allocated(block_ctrl *ptr); + + //!Get a pointer of the "end" block from the first block of the segment + static block_ctrl * priv_end_block(block_ctrl *first_segment_block); + + //!Get a pointer of the "first" block from the end block of the segment + static block_ctrl * priv_first_block(block_ctrl *end_segment_block); + + //!Get poitner of the previous block (previous block must be free) + static block_ctrl * priv_prev_block(block_ctrl *ptr); + + //!Get the size in the tail of the previous block + static block_ctrl * priv_next_block(block_ctrl *ptr); + + //!Check if this block is free (not allocated) + bool priv_is_allocated_block(block_ctrl *ptr); + + //!Marks the block as allocated + void priv_mark_as_allocated_block(block_ctrl *ptr); + + //!Marks the block as allocated + void priv_mark_new_allocated_block(block_ctrl *ptr) + { return priv_mark_as_allocated_block(ptr); } + + //!Marks the block as allocated + void priv_mark_as_free_block(block_ctrl *ptr); + + //!Checks if block has enough memory and splits/unlinks the block + //!returning the address to the users + void* priv_check_and_allocate(size_type units + ,block_ctrl* block + ,size_type &received_size); + //!Real deallocation algorithm + void priv_deallocate(void *addr); + + //!Makes a new memory portion available for allocation + void priv_add_segment(void *addr, size_type size); + + public: + + static const size_type Alignment = !MemAlignment + ? size_type(::boost::container::container_detail::alignment_of + < ::boost::container::container_detail::max_align_t>::value) + : size_type(MemAlignment) + ; + + private: + //Due to embedded bits in size, Alignment must be at least 4 + BOOST_STATIC_ASSERT((Alignment >= 4)); + //Due to rbtree size optimizations, Alignment must have at least pointer alignment + BOOST_STATIC_ASSERT((Alignment >= ::boost::container::container_detail::alignment_of::value)); + static const size_type AlignmentMask = (Alignment - 1); + static const size_type BlockCtrlBytes = ipcdetail::ct_rounded_size::value; + static const size_type BlockCtrlUnits = BlockCtrlBytes/Alignment; + static const size_type AllocatedCtrlBytes = ipcdetail::ct_rounded_size::value; + static const size_type AllocatedCtrlUnits = AllocatedCtrlBytes/Alignment; + static const size_type EndCtrlBlockBytes = ipcdetail::ct_rounded_size::value; + static const size_type EndCtrlBlockUnits = EndCtrlBlockBytes/Alignment; + static const size_type MinBlockUnits = BlockCtrlUnits; + static const size_type UsableByPreviousChunk = sizeof(size_type); + + //Make sure the maximum alignment is power of two + BOOST_STATIC_ASSERT((0 == (Alignment & (Alignment - size_type(1u))))); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + static const size_type PayloadPerAllocation = AllocatedCtrlBytes - UsableByPreviousChunk; +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +template +inline typename rbtree_best_fit::size_type + rbtree_best_fit + ::priv_first_block_offset_from_this(const void *this_ptr, size_type extra_hdr_bytes) +{ + size_type uint_this = (std::size_t)this_ptr; + size_type main_hdr_end = uint_this + sizeof(rbtree_best_fit) + extra_hdr_bytes; + size_type aligned_main_hdr_end = ipcdetail::get_rounded_size(main_hdr_end, Alignment); + size_type block1_off = aligned_main_hdr_end - uint_this; + algo_impl_t::assert_alignment(aligned_main_hdr_end); + algo_impl_t::assert_alignment(uint_this + block1_off); + return block1_off; +} + +template +void rbtree_best_fit:: + priv_add_segment(void *addr, size_type segment_size) +{ + //Check alignment + algo_impl_t::check_alignment(addr); + //Check size + BOOST_ASSERT(segment_size >= (BlockCtrlBytes + EndCtrlBlockBytes)); + + //Initialize the first big block and the "end" node + block_ctrl *first_big_block = ::new(addr, boost_container_new_t())block_ctrl; + first_big_block->m_size = segment_size/Alignment - EndCtrlBlockUnits; + BOOST_ASSERT(first_big_block->m_size >= BlockCtrlUnits); + + //The "end" node is just a node of size 0 with the "end" bit set + block_ctrl *end_block = static_cast + (new (reinterpret_cast(addr) + first_big_block->m_size*Alignment)SizeHolder); + + //This will overwrite the prev part of the "end" node + priv_mark_as_free_block (first_big_block); + #ifdef BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP + first_big_block->m_prev_size = end_block->m_size = + (reinterpret_cast(first_big_block) - reinterpret_cast(end_block))/Alignment; + #else + first_big_block->m_prev_size = end_block->m_size = + (reinterpret_cast(end_block) - reinterpret_cast(first_big_block))/Alignment; + #endif + end_block->m_allocated = 1; + first_big_block->m_prev_allocated = 1; + + BOOST_ASSERT(priv_next_block(first_big_block) == end_block); + BOOST_ASSERT(priv_prev_block(end_block) == first_big_block); + BOOST_ASSERT(priv_first_block() == first_big_block); + BOOST_ASSERT(priv_end_block() == end_block); + + //Some check to validate the algorithm, since it makes some assumptions + //to optimize the space wasted in bookkeeping: + + //Check that the sizes of the header are placed before the rbtree + BOOST_ASSERT(static_cast(static_cast(first_big_block)) + < static_cast(static_cast(first_big_block))); + //Insert it in the intrusive containers + m_header.m_imultiset.insert(*first_big_block); +} + +template +inline typename rbtree_best_fit::block_ctrl * + rbtree_best_fit + ::priv_first_block() +{ + size_type block1_off = priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes); + return reinterpret_cast(reinterpret_cast(this) + block1_off); +} + +template +inline typename rbtree_best_fit::block_ctrl * + rbtree_best_fit + ::priv_end_block() +{ + size_type block1_off = priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes); + const size_type original_first_block_size = m_header.m_size/Alignment*Alignment - block1_off/Alignment*Alignment - EndCtrlBlockBytes; + block_ctrl *end_block = reinterpret_cast + (reinterpret_cast(this) + block1_off + original_first_block_size); + return end_block; +} + +template +inline rbtree_best_fit:: + rbtree_best_fit(size_type segment_size, size_type extra_hdr_bytes) +{ + //Initialize the header + m_header.m_allocated = 0; + m_header.m_size = segment_size; + m_header.m_extra_hdr_bytes = extra_hdr_bytes; + + //Now write calculate the offset of the first big block that will + //cover the whole segment + BOOST_ASSERT(get_min_size(extra_hdr_bytes) <= segment_size); + size_type block1_off = priv_first_block_offset_from_this(this, extra_hdr_bytes); + priv_add_segment(reinterpret_cast(this) + block1_off, segment_size - block1_off); +} + +template +inline rbtree_best_fit::~rbtree_best_fit() +{ + //There is a memory leak! +// BOOST_ASSERT(m_header.m_allocated == 0); +// BOOST_ASSERT(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root)); +} + +template +void rbtree_best_fit::grow(size_type extra_size) +{ + //Get the address of the first block + block_ctrl *first_block = priv_first_block(); + block_ctrl *old_end_block = priv_end_block(); + size_type old_border_offset = (size_type)(reinterpret_cast(old_end_block) - + reinterpret_cast(this)) + EndCtrlBlockBytes; + + //Update managed buffer's size + m_header.m_size += extra_size; + + //We need at least MinBlockUnits blocks to create a new block + if((m_header.m_size - old_border_offset) < MinBlockUnits){ + return; + } + + //Now create a new block between the old end and the new end + size_type align_offset = (m_header.m_size - old_border_offset)/Alignment; + block_ctrl *new_end_block = reinterpret_cast + (reinterpret_cast(old_end_block) + align_offset*Alignment); + + //the last and first block are special: + //new_end_block->m_size & first_block->m_prev_size store the absolute value + //between them + new_end_block->m_allocated = 1; + #ifdef BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP + new_end_block->m_size = (reinterpret_cast(first_block) - + reinterpret_cast(new_end_block))/Alignment; + #else + new_end_block->m_size = (reinterpret_cast(new_end_block) - + reinterpret_cast(first_block))/Alignment; + #endif + first_block->m_prev_size = new_end_block->m_size; + first_block->m_prev_allocated = 1; + BOOST_ASSERT(new_end_block == priv_end_block()); + + //The old end block is the new block + block_ctrl *new_block = old_end_block; + new_block->m_size = (reinterpret_cast(new_end_block) - + reinterpret_cast(new_block))/Alignment; + BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits); + priv_mark_as_allocated_block(new_block); + BOOST_ASSERT(priv_next_block(new_block) == new_end_block); + + m_header.m_allocated += (size_type)new_block->m_size*Alignment; + + //Now deallocate the newly created block + this->priv_deallocate(priv_get_user_buffer(new_block)); +} + +template +void rbtree_best_fit::shrink_to_fit() +{ + //Get the address of the first block + block_ctrl *first_block = priv_first_block(); + algo_impl_t::assert_alignment(first_block); + + //block_ctrl *old_end_block = priv_end_block(first_block); + block_ctrl *old_end_block = priv_end_block(); + algo_impl_t::assert_alignment(old_end_block); + size_type old_end_block_size = old_end_block->m_size; + + void *unique_buffer = 0; + block_ctrl *last_block; + //Check if no memory is allocated between the first and last block + if(priv_next_block(first_block) == old_end_block){ + //If so check if we can allocate memory + size_type ignore_recvd = 0; + void *ignore_reuse = 0; + unique_buffer = priv_allocate(boost::interprocess::allocate_new, 0, ignore_recvd, ignore_reuse); + //If not, return, we can't shrink + if(!unique_buffer) + return; + //If we can, mark the position just after the new allocation as the new end + algo_impl_t::assert_alignment(unique_buffer); + block_ctrl *unique_block = priv_get_block(unique_buffer); + BOOST_ASSERT(priv_is_allocated_block(unique_block)); + algo_impl_t::assert_alignment(unique_block); + last_block = priv_next_block(unique_block); + BOOST_ASSERT(!priv_is_allocated_block(last_block)); + algo_impl_t::assert_alignment(last_block); + } + else{ + //If memory is allocated, check if the last block is allocated + if(priv_is_prev_allocated(old_end_block)) + return; + //If not, mark last block after the free block + last_block = priv_prev_block(old_end_block); + } + + size_type last_block_size = last_block->m_size; + + //Erase block from the free tree, since we will erase it + m_header.m_imultiset.erase(Imultiset::s_iterator_to(*last_block)); + + size_type shrunk_border_offset = (size_type)(reinterpret_cast(last_block) - + reinterpret_cast(this)) + EndCtrlBlockBytes; + + block_ctrl *new_end_block = last_block; + algo_impl_t::assert_alignment(new_end_block); + + //Write new end block attributes + #ifdef BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP + new_end_block->m_size = first_block->m_prev_size = + (reinterpret_cast(first_block) - reinterpret_cast(new_end_block))/Alignment; + #else + new_end_block->m_size = first_block->m_prev_size = + (reinterpret_cast(new_end_block) - reinterpret_cast(first_block))/Alignment; + #endif + + new_end_block->m_allocated = 1; + (void)last_block_size; + (void)old_end_block_size; + BOOST_ASSERT(new_end_block->m_size == (old_end_block_size - last_block_size)); + + //Update managed buffer's size + m_header.m_size = shrunk_border_offset; + BOOST_ASSERT(priv_end_block() == new_end_block); + if(unique_buffer) + priv_deallocate(unique_buffer); +} + +template +inline typename rbtree_best_fit::size_type +rbtree_best_fit::get_size() const +{ return m_header.m_size; } + +template +typename rbtree_best_fit::size_type +rbtree_best_fit::get_free_memory() const +{ + return m_header.m_size - m_header.m_allocated - + priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes); +} + +template +typename rbtree_best_fit::size_type +rbtree_best_fit:: + get_min_size (size_type extra_hdr_bytes) +{ + return (algo_impl_t::ceil_units(sizeof(rbtree_best_fit)) + + algo_impl_t::ceil_units(extra_hdr_bytes) + + MinBlockUnits + EndCtrlBlockUnits)*Alignment; +} + +template +inline bool rbtree_best_fit:: + all_memory_deallocated() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + size_type block1_off = + priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes); + + return m_header.m_allocated == 0 && + m_header.m_imultiset.begin() != m_header.m_imultiset.end() && + (++m_header.m_imultiset.begin()) == m_header.m_imultiset.end() + && m_header.m_imultiset.begin()->m_size == + (m_header.m_size - block1_off - EndCtrlBlockBytes)/Alignment; +} + +template +bool rbtree_best_fit:: + check_sanity() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + imultiset_iterator ib(m_header.m_imultiset.begin()), ie(m_header.m_imultiset.end()); + + size_type free_memory = 0; + + //Iterate through all blocks obtaining their size + for(; ib != ie; ++ib){ + free_memory += (size_type)ib->m_size*Alignment; + algo_impl_t::assert_alignment(&*ib); + if(!algo_impl_t::check_alignment(&*ib)) + return false; + } + + //Check allocated bytes are less than size + if(m_header.m_allocated > m_header.m_size){ + return false; + } + + size_type block1_off = + priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes); + + //Check free bytes are less than size + if(free_memory > (m_header.m_size - block1_off)){ + return false; + } + return true; +} + +template +inline void* rbtree_best_fit:: + allocate(size_type nbytes) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + size_type ignore_recvd = nbytes; + void *ignore_reuse = 0; + return priv_allocate(boost::interprocess::allocate_new, nbytes, ignore_recvd, ignore_reuse); +} + +template +inline void* rbtree_best_fit:: + allocate_aligned(size_type nbytes, size_type alignment) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_aligned(this, nbytes, alignment); +} + +template +template +inline T* rbtree_best_fit:: + allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type &prefer_in_recvd_out_size, T *&reuse) +{ + void* raw_reuse = reuse; + void* const ret = priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, raw_reuse, sizeof(T)); + reuse = static_cast(raw_reuse); + BOOST_ASSERT(0 == ((std::size_t)ret % ::boost::container::container_detail::alignment_of::value)); + return static_cast(ret); +} + +template +inline void* rbtree_best_fit:: + raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects, + size_type &prefer_in_recvd_out_objects, void *&reuse_ptr, size_type sizeof_object) +{ + size_type const preferred_objects = prefer_in_recvd_out_objects; + if(!sizeof_object) + return reuse_ptr = 0, static_cast(0); + if(command & boost::interprocess::try_shrink_in_place){ + if(!reuse_ptr) return static_cast(0); + const bool success = algo_impl_t::try_shrink + ( this, reuse_ptr, limit_objects*sizeof_object + , prefer_in_recvd_out_objects = preferred_objects*sizeof_object); + prefer_in_recvd_out_objects /= sizeof_object; + return success ? reuse_ptr : 0; + } + else{ + return priv_allocation_command + (command, limit_objects, prefer_in_recvd_out_objects, reuse_ptr, sizeof_object); + } +} + + +template +inline void* rbtree_best_fit:: + priv_allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type &prefer_in_recvd_out_size, + void *&reuse_ptr, size_type sizeof_object) +{ + void* ret; + size_type const preferred_size = prefer_in_recvd_out_size; + size_type const max_count = m_header.m_size/sizeof_object; + if(limit_size > max_count || preferred_size > max_count){ + return reuse_ptr = 0, static_cast(0); + } + size_type l_size = limit_size*sizeof_object; + size_type p_size = preferred_size*sizeof_object; + size_type r_size; + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + ret = priv_allocate(command, l_size, r_size = p_size, reuse_ptr, sizeof_object); + } + prefer_in_recvd_out_size = r_size/sizeof_object; + return ret; +} + +template +typename rbtree_best_fit::size_type +rbtree_best_fit:: + size(const void *ptr) const +{ + //We need no synchronization since this block's size is not going + //to be modified by anyone else + //Obtain the real size of the block + return ((size_type)priv_get_block(ptr)->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; +} + +template +inline void rbtree_best_fit::zero_free_memory() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + imultiset_iterator ib(m_header.m_imultiset.begin()), ie(m_header.m_imultiset.end()); + + //Iterate through all blocks obtaining their size + while(ib != ie){ + //Just clear user the memory part reserved for the user + volatile char *ptr = reinterpret_cast(&*ib) + BlockCtrlBytes; + size_type s = (size_type)ib->m_size*Alignment - BlockCtrlBytes; + while(s--){ + *ptr++ = 0; + } + + //This surprisingly is optimized out by Visual C++ 7.1 in release mode! + //std::memset( reinterpret_cast(&*ib) + BlockCtrlBytes + // , 0 + // , ib->m_size*Alignment - BlockCtrlBytes); + ++ib; + } +} + +template +void* rbtree_best_fit:: + priv_expand_both_sides(boost::interprocess::allocation_type command + ,size_type min_size + ,size_type &prefer_in_recvd_out_size + ,void *reuse_ptr + ,bool only_preferred_backwards + ,size_type backwards_multiple) +{ + size_type const preferred_size = prefer_in_recvd_out_size; + algo_impl_t::assert_alignment(reuse_ptr); + if(command & boost::interprocess::expand_fwd){ + if(priv_expand(reuse_ptr, min_size, prefer_in_recvd_out_size = preferred_size)) + return reuse_ptr; + } + else{ + prefer_in_recvd_out_size = this->size(reuse_ptr); + if(prefer_in_recvd_out_size >= preferred_size || prefer_in_recvd_out_size >= min_size) + return reuse_ptr; + } + + if(backwards_multiple){ + BOOST_ASSERT(0 == (min_size % backwards_multiple)); + BOOST_ASSERT(0 == (preferred_size % backwards_multiple)); + } + + if(command & boost::interprocess::expand_bwd){ + //Obtain the real size of the block + block_ctrl *reuse = priv_get_block(reuse_ptr); + + //Sanity check + algo_impl_t::assert_alignment(reuse); + + block_ctrl *prev_block; + + //If the previous block is not free, there is nothing to do + if(priv_is_prev_allocated(reuse)){ + return 0; + } + + prev_block = priv_prev_block(reuse); + BOOST_ASSERT(!priv_is_allocated_block(prev_block)); + + //Some sanity checks + BOOST_ASSERT(prev_block->m_size == reuse->m_prev_size); + algo_impl_t::assert_alignment(prev_block); + + size_type needs_backwards_aligned; + size_type lcm; + if(!algo_impl_t::calculate_lcm_and_needs_backwards_lcmed + ( backwards_multiple + , prefer_in_recvd_out_size + , only_preferred_backwards ? preferred_size : min_size + , lcm, needs_backwards_aligned)){ + return 0; + } + + //Check if previous block has enough size + if(size_type(prev_block->m_size*Alignment) >= needs_backwards_aligned){ + //Now take all next space. This will succeed + if(command & boost::interprocess::expand_fwd){ + size_type received_size2; + if(!priv_expand(reuse_ptr, prefer_in_recvd_out_size, received_size2 = prefer_in_recvd_out_size)){ + BOOST_ASSERT(0); + } + BOOST_ASSERT(prefer_in_recvd_out_size == received_size2); + } + //We need a minimum size to split the previous one + if(prev_block->m_size >= (needs_backwards_aligned/Alignment + BlockCtrlUnits)){ + block_ctrl *new_block = reinterpret_cast + (reinterpret_cast(reuse) - needs_backwards_aligned); + + //Free old previous buffer + new_block->m_size = + AllocatedCtrlUnits + (needs_backwards_aligned + (prefer_in_recvd_out_size - UsableByPreviousChunk))/Alignment; + BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits); + priv_mark_as_allocated_block(new_block); + + prev_block->m_size = (reinterpret_cast(new_block) - + reinterpret_cast(prev_block))/Alignment; + BOOST_ASSERT(prev_block->m_size >= BlockCtrlUnits); + priv_mark_as_free_block(prev_block); + + //Update the old previous block in the free blocks tree + //If the new size fulfills tree invariants do nothing, + //otherwise erase() + insert() + { + imultiset_iterator prev_block_it(Imultiset::s_iterator_to(*prev_block)); + imultiset_iterator was_smaller_it(prev_block_it); + if(prev_block_it != m_header.m_imultiset.begin() && + (--(was_smaller_it = prev_block_it))->m_size > prev_block->m_size){ + m_header.m_imultiset.erase(prev_block_it); + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *prev_block); + } + } + + prefer_in_recvd_out_size = needs_backwards_aligned + prefer_in_recvd_out_size; + m_header.m_allocated += needs_backwards_aligned; + + //Check alignment + algo_impl_t::assert_alignment(new_block); + + //If the backwards expansion has remaining bytes in the + //first bytes, fill them with a pattern + void *p = priv_get_user_buffer(new_block); + void *user_ptr = reinterpret_cast(p); + BOOST_ASSERT((static_cast(reuse_ptr) - static_cast(user_ptr)) % backwards_multiple == 0); + algo_impl_t::assert_alignment(user_ptr); + return user_ptr; + } + //Check if there is no place to create a new block and + //the whole new block is multiple of the backwards expansion multiple + else if(prev_block->m_size >= needs_backwards_aligned/Alignment && + 0 == ((prev_block->m_size*Alignment) % lcm)) { + //Erase old previous block, since we will change it + m_header.m_imultiset.erase(Imultiset::s_iterator_to(*prev_block)); + + //Just merge the whole previous block + //prev_block->m_size*Alignment is multiple of lcm (and backwards_multiple) + prefer_in_recvd_out_size = prefer_in_recvd_out_size + (size_type)prev_block->m_size*Alignment; + + m_header.m_allocated += (size_type)prev_block->m_size*Alignment; + //Now update sizes + prev_block->m_size = prev_block->m_size + reuse->m_size; + BOOST_ASSERT(prev_block->m_size >= BlockCtrlUnits); + priv_mark_as_allocated_block(prev_block); + + //If the backwards expansion has remaining bytes in the + //first bytes, fill them with a pattern + void *user_ptr = priv_get_user_buffer(prev_block); + BOOST_ASSERT((static_cast(reuse_ptr) - static_cast(user_ptr)) % backwards_multiple == 0); + algo_impl_t::assert_alignment(user_ptr); + return user_ptr; + } + else{ + //Alignment issues + } + } + } + return 0; +} + +template +inline void rbtree_best_fit:: + deallocate_many(typename rbtree_best_fit::multiallocation_chain &chain) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + algo_impl_t::deallocate_many(this, chain); +} + +template +void * rbtree_best_fit:: + priv_allocate(boost::interprocess::allocation_type command + ,size_type limit_size + ,size_type &prefer_in_recvd_out_size + ,void *&reuse_ptr + ,size_type backwards_multiple) +{ + size_type const preferred_size = prefer_in_recvd_out_size; + if(command & boost::interprocess::shrink_in_place){ + if(!reuse_ptr) return static_cast(0); + bool success = + algo_impl_t::shrink(this, reuse_ptr, limit_size, prefer_in_recvd_out_size = preferred_size); + return success ? reuse_ptr : 0; + } + + prefer_in_recvd_out_size = 0; + + if(limit_size > preferred_size) + return reuse_ptr = 0, static_cast(0); + + //Number of units to request (including block_ctrl header) + size_type preferred_units = priv_get_total_units(preferred_size); + + //Number of units to request (including block_ctrl header) + size_type limit_units = priv_get_total_units(limit_size); + + //Expand in place + prefer_in_recvd_out_size = preferred_size; + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ + void *ret = priv_expand_both_sides + (command, limit_size, prefer_in_recvd_out_size, reuse_ptr, true, backwards_multiple); + if(ret) + return ret; + } + + if(command & boost::interprocess::allocate_new){ + size_block_ctrl_compare comp; + imultiset_iterator it(m_header.m_imultiset.lower_bound(preferred_units, comp)); + + if(it != m_header.m_imultiset.end()){ + return reuse_ptr = 0, this->priv_check_and_allocate + (preferred_units, ipcdetail::to_raw_pointer(&*it), prefer_in_recvd_out_size); + } + + if(it != m_header.m_imultiset.begin()&& + (--it)->m_size >= limit_units){ + return reuse_ptr = 0, this->priv_check_and_allocate + (it->m_size, ipcdetail::to_raw_pointer(&*it), prefer_in_recvd_out_size); + } + } + + + //Now try to expand both sides with min size + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ + return priv_expand_both_sides + (command, limit_size, prefer_in_recvd_out_size = preferred_size, reuse_ptr, false, backwards_multiple); + } + return reuse_ptr = 0, static_cast(0); +} + +template +inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_get_block(const void *ptr) +{ + return const_cast + (reinterpret_cast + (reinterpret_cast(ptr) - AllocatedCtrlBytes)); +} + +template +inline +void *rbtree_best_fit:: + priv_get_user_buffer(const typename rbtree_best_fit::block_ctrl *block) +{ return const_cast(reinterpret_cast(block) + AllocatedCtrlBytes); } + +template +inline typename rbtree_best_fit::size_type +rbtree_best_fit:: + priv_get_total_units(size_type userbytes) +{ + if(userbytes < UsableByPreviousChunk) + userbytes = UsableByPreviousChunk; + size_type units = ipcdetail::get_rounded_size(userbytes - UsableByPreviousChunk, Alignment)/Alignment + AllocatedCtrlUnits; + if(units < BlockCtrlUnits) units = BlockCtrlUnits; + return units; +} + +template +bool rbtree_best_fit:: + priv_expand (void *ptr, const size_type min_size, size_type &prefer_in_recvd_out_size) +{ + size_type const preferred_size = prefer_in_recvd_out_size; + //Obtain the real size of the block + block_ctrl *block = priv_get_block(ptr); + size_type old_block_units = block->m_size; + + //The block must be marked as allocated and the sizes must be equal + BOOST_ASSERT(priv_is_allocated_block(block)); + + //Put this to a safe value + prefer_in_recvd_out_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; + if(prefer_in_recvd_out_size >= preferred_size || prefer_in_recvd_out_size >= min_size) + return true; + + //Now translate it to Alignment units + const size_type min_user_units = algo_impl_t::ceil_units(min_size - UsableByPreviousChunk); + const size_type preferred_user_units = algo_impl_t::ceil_units(preferred_size - UsableByPreviousChunk); + + //Some parameter checks + BOOST_ASSERT(min_user_units <= preferred_user_units); + + block_ctrl *next_block; + + if(priv_is_allocated_block(next_block = priv_next_block(block))){ + return prefer_in_recvd_out_size >= min_size; + } + algo_impl_t::assert_alignment(next_block); + + //Is "block" + "next_block" big enough? + const size_type merged_units = old_block_units + (size_type)next_block->m_size; + + //Now get the expansion size + const size_type merged_user_units = merged_units - AllocatedCtrlUnits; + + if(merged_user_units < min_user_units){ + prefer_in_recvd_out_size = merged_units*Alignment - UsableByPreviousChunk; + return false; + } + + //Now get the maximum size the user can allocate + size_type intended_user_units = (merged_user_units < preferred_user_units) ? + merged_user_units : preferred_user_units; + + //These are total units of the merged block (supposing the next block can be split) + const size_type intended_units = AllocatedCtrlUnits + intended_user_units; + + //Check if we can split the next one in two parts + if((merged_units - intended_units) >= BlockCtrlUnits){ + //This block is bigger than needed, split it in + //two blocks, the first one will be merged and + //the second's size will be the remaining space + BOOST_ASSERT(next_block->m_size == priv_next_block(next_block)->m_prev_size); + const size_type rem_units = merged_units - intended_units; + + //Check if we we need to update the old next block in the free blocks tree + //If the new size fulfills tree invariants, we just need to replace the node + //(the block start has been displaced), otherwise erase() + insert(). + // + //This fixup must be done in two parts, because the new next block might + //overwrite the tree hook of the old next block. So we first erase the + //old if needed and we'll insert the new one after creating the new next + imultiset_iterator old_next_block_it(Imultiset::s_iterator_to(*next_block)); + const bool size_invariants_broken = + (next_block->m_size - rem_units ) < BlockCtrlUnits || + (old_next_block_it != m_header.m_imultiset.begin() && + (--imultiset_iterator(old_next_block_it))->m_size > rem_units); + if(size_invariants_broken){ + m_header.m_imultiset.erase(old_next_block_it); + } + //This is the remaining block + block_ctrl *rem_block = ::new(reinterpret_cast + (reinterpret_cast(block) + intended_units*Alignment), boost_container_new_t())block_ctrl; + rem_block->m_size = rem_units; + algo_impl_t::assert_alignment(rem_block); + BOOST_ASSERT(rem_block->m_size >= BlockCtrlUnits); + priv_mark_as_free_block(rem_block); + + //Now the second part of the fixup + if(size_invariants_broken) + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *rem_block); + else + m_header.m_imultiset.replace_node(old_next_block_it, *rem_block); + + //Write the new length + block->m_size = intended_user_units + AllocatedCtrlUnits; + BOOST_ASSERT(block->m_size >= BlockCtrlUnits); + m_header.m_allocated += (intended_units - old_block_units)*Alignment; + } + //There is no free space to create a new node: just merge both blocks + else{ + //Now we have to update the data in the tree + m_header.m_imultiset.erase(Imultiset::s_iterator_to(*next_block)); + + //Write the new length + block->m_size = merged_units; + BOOST_ASSERT(block->m_size >= BlockCtrlUnits); + m_header.m_allocated += (merged_units - old_block_units)*Alignment; + } + priv_mark_as_allocated_block(block); + prefer_in_recvd_out_size = ((size_type)block->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; + return true; +} + +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_prev_block + (typename rbtree_best_fit::block_ctrl *ptr) +{ + BOOST_ASSERT(!ptr->m_prev_allocated); + return reinterpret_cast + (reinterpret_cast(ptr) - ptr->m_prev_size*Alignment); +} + + + +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_end_block + (typename rbtree_best_fit::block_ctrl *first_segment_block) +{ + //The first block's logic is different from the rest of blocks: stores in m_prev_size the absolute + //distance with the end block + BOOST_ASSERT(first_segment_block->m_prev_allocated); + block_ctrl *end_block = reinterpret_cast + (reinterpret_cast(first_segment_block) + first_segment_block->m_prev_size*Alignment); + (void)end_block; + BOOST_ASSERT(end_block->m_allocated == 1); + BOOST_ASSERT(end_block->m_size == first_segment_block->m_prev_size); + BOOST_ASSERT(end_block > first_segment_block); + return end_block; +} + +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_first_block + (typename rbtree_best_fit::block_ctrl *end_segment_block) +{ + //The first block's logic is different from the rest of blocks: stores in m_prev_size the absolute + //distance with the end block + BOOST_ASSERT(end_segment_block->m_allocated); + block_ctrl *first_block = reinterpret_cast + (reinterpret_cast(end_segment_block) - end_segment_block->m_size*Alignment); + (void)first_block; + BOOST_ASSERT(first_block->m_prev_allocated == 1); + BOOST_ASSERT(first_block->m_prev_size == end_segment_block->m_size); + BOOST_ASSERT(end_segment_block > first_block); + return first_block; +} + + +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_next_block + (typename rbtree_best_fit::block_ctrl *ptr) +{ + return reinterpret_cast + (reinterpret_cast(ptr) + ptr->m_size*Alignment); +} + +template inline +bool rbtree_best_fit::priv_is_allocated_block + (typename rbtree_best_fit::block_ctrl *block) +{ + bool allocated = block->m_allocated != 0; + #ifndef NDEBUG + if(block != priv_end_block()){ + block_ctrl *next_block = reinterpret_cast + (reinterpret_cast(block) + block->m_size*Alignment); + bool next_block_prev_allocated = next_block->m_prev_allocated != 0; + (void)next_block_prev_allocated; + BOOST_ASSERT(allocated == next_block_prev_allocated); + } + #endif + return allocated; +} + +template inline +bool rbtree_best_fit::priv_is_prev_allocated + (typename rbtree_best_fit::block_ctrl *block) +{ + if(block->m_prev_allocated){ + return true; + } + else{ + #ifndef NDEBUG + if(block != priv_first_block()){ + block_ctrl *prev = priv_prev_block(block); + (void)prev; + BOOST_ASSERT(!prev->m_allocated); + BOOST_ASSERT(prev->m_size == block->m_prev_size); + } + #endif + return false; + } +} + +template inline +void rbtree_best_fit::priv_mark_as_allocated_block + (typename rbtree_best_fit::block_ctrl *block) +{ + block->m_allocated = 1; + reinterpret_cast + (reinterpret_cast(block)+ block->m_size*Alignment)->m_prev_allocated = 1; +} + +template inline +void rbtree_best_fit::priv_mark_as_free_block + (typename rbtree_best_fit::block_ctrl *block) +{ + block->m_allocated = 0; + block_ctrl *next_block = priv_next_block(block); + next_block->m_prev_allocated = 0; + next_block->m_prev_size = block->m_size; +} + +template inline +void* rbtree_best_fit::priv_check_and_allocate + (size_type nunits + ,typename rbtree_best_fit::block_ctrl* block + ,size_type &received_size) +{ + size_type upper_nunits = nunits + BlockCtrlUnits; + imultiset_iterator it_old = Imultiset::s_iterator_to(*block); + algo_impl_t::assert_alignment(block); + + if (block->m_size >= upper_nunits){ + //This block is bigger than needed, split it in + //two blocks, the first's size will be "units" and + //the second's size "block->m_size-units" + size_type block_old_size = block->m_size; + block->m_size = nunits; + BOOST_ASSERT(block->m_size >= BlockCtrlUnits); + + //This is the remaining block + block_ctrl *rem_block = ::new(reinterpret_cast + (reinterpret_cast(block) + Alignment*nunits), boost_container_new_t())block_ctrl; + algo_impl_t::assert_alignment(rem_block); + rem_block->m_size = block_old_size - nunits; + BOOST_ASSERT(rem_block->m_size >= BlockCtrlUnits); + priv_mark_as_free_block(rem_block); + + imultiset_iterator it_hint; + if(it_old == m_header.m_imultiset.begin() + || (--imultiset_iterator(it_old))->m_size <= rem_block->m_size){ + //option a: slow but secure + //m_header.m_imultiset.insert(m_header.m_imultiset.erase(it_old), *rem_block); + //option b: Construct an empty node and swap + //Imultiset::init_node(*rem_block); + //block->swap_nodes(*rem_block); + //option c: replace the node directly + m_header.m_imultiset.replace_node(Imultiset::s_iterator_to(*it_old), *rem_block); + } + else{ + //Now we have to update the data in the tree + m_header.m_imultiset.erase(it_old); + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *rem_block); + } + + } + else if (block->m_size >= nunits){ + m_header.m_imultiset.erase(it_old); + } + else{ + BOOST_ASSERT(0); + return 0; + } + //We need block_ctrl for deallocation stuff, so + //return memory user can overwrite + m_header.m_allocated += (size_type)block->m_size*Alignment; + received_size = ((size_type)block->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; + + //Mark the block as allocated + priv_mark_as_allocated_block(block); + + //Clear the memory occupied by the tree hook, since this won't be + //cleared with zero_free_memory + TreeHook *t = static_cast(block); + //Just clear the memory part reserved for the user + std::size_t tree_hook_offset_in_block = (char*)t - (char*)block; + //volatile char *ptr = + char *ptr = reinterpret_cast(block)+tree_hook_offset_in_block; + const std::size_t s = BlockCtrlBytes - tree_hook_offset_in_block; + std::memset(ptr, 0, s); + this->priv_next_block(block)->m_prev_size = 0; + return priv_get_user_buffer(block); +} + +template +void rbtree_best_fit::deallocate(void* addr) +{ + if(!addr) return; + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return this->priv_deallocate(addr); +} + +template +void rbtree_best_fit::priv_deallocate(void* addr) +{ + if(!addr) return; + + block_ctrl *block = priv_get_block(addr); + + //The blocks must be marked as allocated and the sizes must be equal + BOOST_ASSERT(priv_is_allocated_block(block)); + + //Check if alignment and block size are right + algo_impl_t::assert_alignment(addr); + + size_type block_old_size = Alignment*(size_type)block->m_size; + BOOST_ASSERT(m_header.m_allocated >= block_old_size); + + //Update used memory count + m_header.m_allocated -= block_old_size; + + //The block to insert in the tree + block_ctrl *block_to_insert = block; + + //Get the next block + block_ctrl *const next_block = priv_next_block(block); + const bool merge_with_prev = !priv_is_prev_allocated(block); + const bool merge_with_next = !priv_is_allocated_block(next_block); + + //Merge logic. First just update block sizes, then fix free blocks tree + if(merge_with_prev || merge_with_next){ + //Merge if the previous is free + if(merge_with_prev){ + //Get the previous block + block_to_insert = priv_prev_block(block); + block_to_insert->m_size += block->m_size; + BOOST_ASSERT(block_to_insert->m_size >= BlockCtrlUnits); + } + //Merge if the next is free + if(merge_with_next){ + block_to_insert->m_size += next_block->m_size; + BOOST_ASSERT(block_to_insert->m_size >= BlockCtrlUnits); + const imultiset_iterator next_it = Imultiset::s_iterator_to(*next_block); + if(merge_with_prev){ + m_header.m_imultiset.erase(next_it); + } + else{ + m_header.m_imultiset.replace_node(next_it, *block_to_insert); + } + } + + //Now try to shortcut erasure + insertion (O(log(N))) with + //a O(1) operation if merging does not alter tree positions + const imultiset_iterator block_to_check_it = Imultiset::s_iterator_to(*block_to_insert); + imultiset_const_iterator next_to_check_it(block_to_check_it), end_it(m_header.m_imultiset.end()); + + if(++next_to_check_it != end_it && block_to_insert->m_size > next_to_check_it->m_size){ + //Block is bigger than next, so move it + m_header.m_imultiset.erase(block_to_check_it); + m_header.m_imultiset.insert(end_it, *block_to_insert); + } + else{ + //Block size increment didn't violate tree invariants so there is nothing to fix + } + } + else{ + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *block_to_insert); + } + priv_mark_as_free_block(block_to_insert); +} + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP diff --git a/libraries/boost/boost/interprocess/mem_algo/simple_seq_fit.hpp b/libraries/boost/boost/interprocess/mem_algo/simple_seq_fit.hpp new file mode 100644 index 000000000..69813f41b --- /dev/null +++ b/libraries/boost/boost/interprocess/mem_algo/simple_seq_fit.hpp @@ -0,0 +1,62 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SIMPLE_SEQ_FIT_HPP +#define BOOST_INTERPROCESS_SIMPLE_SEQ_FIT_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include + +//!\file +//!Describes sequential fit algorithm used to allocate objects in shared memory. + +namespace boost { +namespace interprocess { + +//!This class implements the simple sequential fit algorithm with a simply +//!linked list of free buffers. +template +class simple_seq_fit + : public ipcdetail::simple_seq_fit_impl +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef ipcdetail::simple_seq_fit_impl base_t; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef typename base_t::size_type size_type; + + //!Constructor. "size" is the total size of the managed memory segment, + //!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(simple_seq_fit) + //!offset that the allocator should not use at all.*/ + simple_seq_fit(size_type segment_size, size_type extra_hdr_bytes) + : base_t(segment_size, extra_hdr_bytes){} +}; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_SIMPLE_SEQ_FIT_HPP + diff --git a/libraries/boost/boost/interprocess/offset_ptr.hpp b/libraries/boost/boost/interprocess/offset_ptr.hpp new file mode 100644 index 000000000..fca444eaa --- /dev/null +++ b/libraries/boost/boost/interprocess/offset_ptr.hpp @@ -0,0 +1,751 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_OFFSET_PTR_HPP +#define BOOST_INTERPROCESS_OFFSET_PTR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include //alignment_of, aligned_storage +#include +#include + +//!\file +//!Describes a smart pointer that stores the offset between this pointer and +//!target pointee, called offset_ptr. + +namespace boost { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +//Predeclarations +template +struct has_trivial_destructor; + +#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +namespace ipcdetail { + + template + union offset_ptr_internal + { + BOOST_STATIC_ASSERT(sizeof(OffsetType) >= sizeof(uintptr_t)); + + explicit offset_ptr_internal(OffsetType off) + : m_offset(off) + {} + + OffsetType m_offset; //Distance between this object and pointee address + + typename ::boost::container::container_detail::aligned_storage + < sizeof(OffsetType)//for offset_type_alignment m_offset will be enough + , (OffsetAlignment == offset_type_alignment) ? 1u : OffsetAlignment + >::type alignment_helper; + }; + + //Note: using the address of a local variable to point to another address + //is not standard conforming and this can be optimized-away by the compiler. + //Non-inlining is a method to remain illegal but correct + + //Undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_XXX if your compiler can inline + //this code without breaking the library + + //////////////////////////////////////////////////////////////////////// + // + // offset_ptr_to_raw_pointer + // + //////////////////////////////////////////////////////////////////////// + #define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR + BOOST_INTERPROCESS_FORCEINLINE void * offset_ptr_to_raw_pointer(const volatile void *this_ptr, uintptr_t offset) + { + typedef pointer_uintptr_caster caster_t; + #ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR + if(offset == 1){ + return 0; + } + else{ + return caster_t(caster_t(this_ptr).uintptr() + offset).pointer(); + } + #else + uintptr_t mask = offset == 1; + --mask; + uintptr_t target_offset = caster_t(this_ptr).uintptr() + offset; + target_offset &= mask; + return caster_t(target_offset).pointer(); + #endif + } + + //////////////////////////////////////////////////////////////////////// + // + // offset_ptr_to_offset + // + //////////////////////////////////////////////////////////////////////// + #define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF + BOOST_INTERPROCESS_FORCEINLINE uintptr_t offset_ptr_to_offset(const volatile void *ptr, const volatile void *this_ptr) + { + typedef pointer_uintptr_caster caster_t; + #ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF + //offset == 1 && ptr != 0 is not legal for this pointer + if(!ptr){ + return 1; + } + else{ + uintptr_t offset = caster_t(ptr).uintptr() - caster_t(this_ptr).uintptr(); + BOOST_ASSERT(offset != 1); + return offset; + } + #else + //const uintptr_t other = -uintptr_t(ptr != 0); + //const uintptr_t offset = (caster_t(ptr).uintptr() - caster_t(this_ptr).uintptr()) & other; + //return offset + uintptr_t(!other); + // + uintptr_t offset = caster_t(ptr).uintptr() - caster_t(this_ptr).uintptr(); + --offset; + uintptr_t mask = uintptr_t(ptr == 0); + --mask; + offset &= mask; + return ++offset; + #endif + } + + //////////////////////////////////////////////////////////////////////// + // + // offset_ptr_to_offset_from_other + // + //////////////////////////////////////////////////////////////////////// + #define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER + BOOST_INTERPROCESS_FORCEINLINE uintptr_t offset_ptr_to_offset_from_other + (const volatile void *this_ptr, const volatile void *other_ptr, uintptr_t other_offset) + { + typedef pointer_uintptr_caster caster_t; + #ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER + if(other_offset == 1){ + return 1; + } + else{ + uintptr_t offset = caster_t(other_ptr).uintptr() - caster_t(this_ptr).uintptr() + other_offset; + BOOST_ASSERT(offset != 1); + return offset; + } + #else + uintptr_t mask = other_offset == 1; + --mask; + uintptr_t offset = caster_t(other_ptr).uintptr() - caster_t(this_ptr).uintptr(); + offset &= mask; + return offset + other_offset; + + //uintptr_t mask = -uintptr_t(other_offset != 1); + //uintptr_t offset = caster_t(other_ptr).uintptr() - caster_t(this_ptr).uintptr(); + //offset &= mask; + //return offset + other_offset; + #endif + } + + //////////////////////////////////////////////////////////////////////// + // + // Let's assume cast to void and cv cast don't change any target address + // + //////////////////////////////////////////////////////////////////////// + template + struct offset_ptr_maintains_address + { + static const bool value = ipcdetail::is_cv_same::value + || ipcdetail::is_cv_same::value + || ipcdetail::is_cv_same::value + ; + }; + + template + struct enable_if_convertible_equal_address + : enable_if_c< ::boost::is_convertible::value + && offset_ptr_maintains_address::value + , Ret> + {}; + + template + struct enable_if_convertible_unequal_address + : enable_if_c< ::boost::is_convertible::value + && !offset_ptr_maintains_address::value + , Ret> + {}; + +} //namespace ipcdetail { +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!A smart pointer that stores the offset between between the pointer and the +//!the object it points. This allows offset allows special properties, since +//!the pointer is independent from the address of the pointee, if the +//!pointer and the pointee are still separated by the same offset. This feature +//!converts offset_ptr in a smart pointer that can be placed in shared memory and +//!memory mapped files mapped in different addresses in every process. +//! +//! \tparam PointedType The type of the pointee. +//! \tparam DifferenceType A signed integer type that can represent the arithmetic operations on the pointer +//! \tparam OffsetType An unsigned integer type that can represent the +//! distance between two pointers reinterpret_cast-ed as unsigned integers. This type +//! should be at least of the same size of std::uintptr_t. In some systems it's possible to communicate +//! between 32 and 64 bit processes using 64 bit offsets. +//! \tparam OffsetAlignment Alignment of the OffsetType stored inside. In some systems might be necessary +//! to align it to 64 bits in order to communicate 32 and 64 bit processes using 64 bit offsets. +//! +//!Note: offset_ptr uses implementation defined properties, present in most platforms, for +//!performance reasons: +//! - Assumes that uintptr_t representation of nullptr is (uintptr_t)zero. +//! - Assumes that incrementing a uintptr_t obtained from a pointer is equivalent +//! to incrementing the pointer and then converting it back to uintptr_t. +template +class offset_ptr +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef offset_ptr self_t; + void unspecified_bool_type_func() const {} + typedef void (self_t::*unspecified_bool_type)() const; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef PointedType element_type; + typedef PointedType * pointer; + typedef typename ipcdetail:: + add_reference::type reference; + typedef typename ipcdetail:: + remove_volatile::type + >::type value_type; + typedef DifferenceType difference_type; + typedef std::random_access_iterator_tag iterator_category; + typedef OffsetType offset_type; + + public: //Public Functions + + //!Default constructor (null pointer). + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr() BOOST_NOEXCEPT + : internal(1) + {} + + //!Constructor from raw pointer (allows "0" pointer conversion). + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr(pointer ptr) BOOST_NOEXCEPT + : internal(static_cast(ipcdetail::offset_ptr_to_offset(ptr, this))) + {} + + //!Constructor from other pointer. + //!Never throws. + template + BOOST_INTERPROCESS_FORCEINLINE offset_ptr( T *ptr + , typename ipcdetail::enable_if< ::boost::is_convertible >::type * = 0) BOOST_NOEXCEPT + : internal(static_cast + (ipcdetail::offset_ptr_to_offset(static_cast(ptr), this))) + {} + + //!Constructor from other offset_ptr + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr& ptr) BOOST_NOEXCEPT + : internal(static_cast + (ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.internal.m_offset))) + {} + + //!Constructor from other offset_ptr. If pointers of pointee types are + //!convertible, offset_ptrs will be convertibles. Never throws. + template + BOOST_INTERPROCESS_FORCEINLINE offset_ptr( const offset_ptr &ptr + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + , typename ipcdetail::enable_if_convertible_equal_address::type* = 0 + #endif + ) BOOST_NOEXCEPT + : internal(static_cast + (ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.get_offset()))) + {} + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Constructor from other offset_ptr. If pointers of pointee types are + //!convertible, offset_ptrs will be convertibles. Never throws. + template + BOOST_INTERPROCESS_FORCEINLINE offset_ptr( const offset_ptr &ptr + , typename ipcdetail::enable_if_convertible_unequal_address::type* = 0) BOOST_NOEXCEPT + : internal(static_cast + (ipcdetail::offset_ptr_to_offset(static_cast(ptr.get()), this))) + {} + + #endif + + //!Emulates static_cast operator. + //!Never throws. + template + BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr & r, ipcdetail::static_cast_tag) BOOST_NOEXCEPT + : internal(static_cast + (ipcdetail::offset_ptr_to_offset(static_cast(r.get()), this))) + {} + + //!Emulates const_cast operator. + //!Never throws. + template + BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr & r, ipcdetail::const_cast_tag) BOOST_NOEXCEPT + : internal(static_cast + (ipcdetail::offset_ptr_to_offset(const_cast(r.get()), this))) + {} + + //!Emulates dynamic_cast operator. + //!Never throws. + template + BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr & r, ipcdetail::dynamic_cast_tag) BOOST_NOEXCEPT + : internal(static_cast + (ipcdetail::offset_ptr_to_offset(dynamic_cast(r.get()), this))) + {} + + //!Emulates reinterpret_cast operator. + //!Never throws. + template + BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr & r, ipcdetail::reinterpret_cast_tag) BOOST_NOEXCEPT + : internal(static_cast + (ipcdetail::offset_ptr_to_offset(reinterpret_cast(r.get()), this))) + {} + + //!Obtains raw pointer from offset. + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE pointer get() const BOOST_NOEXCEPT + { return (pointer)ipcdetail::offset_ptr_to_raw_pointer(this, this->internal.m_offset); } + + BOOST_INTERPROCESS_FORCEINLINE offset_type get_offset() const BOOST_NOEXCEPT + { return this->internal.m_offset; } + + //!Pointer-like -> operator. It can return 0 pointer. + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE pointer operator->() const BOOST_NOEXCEPT + { return this->get(); } + + //!Dereferencing operator, if it is a null offset_ptr behavior + //! is undefined. Never throws. + BOOST_INTERPROCESS_FORCEINLINE reference operator* () const BOOST_NOEXCEPT + { + pointer p = this->get(); + reference r = *p; + return r; + } + + //!Indexing operator. + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE reference operator[](difference_type idx) const BOOST_NOEXCEPT + { return this->get()[idx]; } + + //!Assignment from pointer (saves extra conversion). + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (pointer from) BOOST_NOEXCEPT + { + this->internal.m_offset = + static_cast(ipcdetail::offset_ptr_to_offset(from, this)); + return *this; + } + + //!Assignment from other offset_ptr. + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (const offset_ptr & ptr) BOOST_NOEXCEPT + { + this->internal.m_offset = + static_cast(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.internal.m_offset)); + return *this; + } + + //!Assignment from related offset_ptr. If pointers of pointee types + //! are assignable, offset_ptrs will be assignable. Never throws. + template BOOST_INTERPROCESS_FORCEINLINE + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typename ipcdetail::enable_if_c + < ::boost::is_convertible::value, offset_ptr&>::type + #else + offset_ptr& + #endif + operator= (const offset_ptr &ptr) BOOST_NOEXCEPT + { + this->assign(ptr, ipcdetail::bool_::value>()); + return *this; + } + + public: + + //!offset_ptr += difference_type. + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr &operator+= (difference_type offset) BOOST_NOEXCEPT + { this->inc_offset(offset * sizeof (PointedType)); return *this; } + + //!offset_ptr -= difference_type. + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr &operator-= (difference_type offset) BOOST_NOEXCEPT + { this->dec_offset(offset * sizeof (PointedType)); return *this; } + + //!++offset_ptr. + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator++ (void) BOOST_NOEXCEPT + { this->inc_offset(sizeof (PointedType)); return *this; } + + //!offset_ptr++. + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr operator++ (int) BOOST_NOEXCEPT + { + offset_ptr tmp(*this); + this->inc_offset(sizeof (PointedType)); + return tmp; + } + + //!--offset_ptr. + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator-- (void) BOOST_NOEXCEPT + { this->dec_offset(sizeof (PointedType)); return *this; } + + //!offset_ptr--. + //!Never throws. + BOOST_INTERPROCESS_FORCEINLINE offset_ptr operator-- (int) BOOST_NOEXCEPT + { + offset_ptr tmp(*this); + this->dec_offset(sizeof (PointedType)); + return tmp; + } + + //!safe bool conversion operator. + //!Never throws. + #if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + BOOST_INTERPROCESS_FORCEINLINE operator unspecified_bool_type() const BOOST_NOEXCEPT + { return this->internal.m_offset != 1? &self_t::unspecified_bool_type_func : 0; } + #else + explicit operator bool() const BOOST_NOEXCEPT + { return this->internal.m_offset != 1; } + #endif + + //!Not operator. Not needed in theory, but improves portability. + //!Never throws + BOOST_INTERPROCESS_FORCEINLINE bool operator! () const BOOST_NOEXCEPT + { return this->internal.m_offset == 1; } + + //!Compatibility with pointer_traits + //! + template + struct rebind + { typedef offset_ptr other; }; + + //!Compatibility with pointer_traits + //! + BOOST_INTERPROCESS_FORCEINLINE static offset_ptr pointer_to(reference r) BOOST_NOEXCEPT + { return offset_ptr(&r); } + + //!difference_type + offset_ptr + //!operation + BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator+(difference_type diff, offset_ptr right) BOOST_NOEXCEPT + { right += diff; return right; } + + //!offset_ptr + difference_type + //!operation + BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator+(offset_ptr left, difference_type diff) BOOST_NOEXCEPT + { left += diff; return left; } + + //!offset_ptr - diff + //!operation + BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator-(offset_ptr left, difference_type diff) BOOST_NOEXCEPT + { left -= diff; return left; } + + //!offset_ptr - diff + //!operation + BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator-(difference_type diff, offset_ptr right) BOOST_NOEXCEPT + { right -= diff; return right; } + + //!offset_ptr - offset_ptr + //!operation + BOOST_INTERPROCESS_FORCEINLINE friend difference_type operator-(const offset_ptr &pt, const offset_ptr &pt2) BOOST_NOEXCEPT + { return difference_type(pt.get()- pt2.get()); } + + //Comparison + BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1.get() == pt2.get(); } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1.get() != pt2.get(); } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1.get() < pt2.get(); } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1.get() <= pt2.get(); } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1.get() > pt2.get(); } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1.get() >= pt2.get(); } + + //Comparison to raw ptr to support literal 0 + BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1 == pt2.get(); } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1 != pt2.get(); } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1 < pt2.get(); } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1 <= pt2.get(); } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1 > pt2.get(); } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT + { return pt1 >= pt2.get(); } + + //Comparison + BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT + { return pt1.get() == pt2; } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT + { return pt1.get() != pt2; } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT + { return pt1.get() < pt2; } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT + { return pt1.get() <= pt2; } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT + { return pt1.get() > pt2; } + + BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT + { return pt1.get() >= pt2; } + + BOOST_INTERPROCESS_FORCEINLINE friend void swap(offset_ptr &left, offset_ptr &right) BOOST_NOEXCEPT + { + pointer ptr = right.get(); + right = left; + left = ptr; + } + + private: + template + BOOST_INTERPROCESS_FORCEINLINE void assign(const offset_ptr &ptr, ipcdetail::bool_) BOOST_NOEXCEPT + { //no need to pointer adjustment + this->internal.m_offset = + static_cast(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.get_offset())); + } + + template + BOOST_INTERPROCESS_FORCEINLINE void assign(const offset_ptr &ptr, ipcdetail::bool_) BOOST_NOEXCEPT + { //we must convert to raw before calculating the offset + this->internal.m_offset = + static_cast(ipcdetail::offset_ptr_to_offset(static_cast(ptr.get()), this)); + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + BOOST_INTERPROCESS_FORCEINLINE void inc_offset(DifferenceType bytes) BOOST_NOEXCEPT + { internal.m_offset += bytes; } + + BOOST_INTERPROCESS_FORCEINLINE void dec_offset(DifferenceType bytes) BOOST_NOEXCEPT + { internal.m_offset -= bytes; } + + ipcdetail::offset_ptr_internal internal; + + public: + BOOST_INTERPROCESS_FORCEINLINE const OffsetType &priv_offset() const BOOST_NOEXCEPT + { return internal.m_offset; } + + BOOST_INTERPROCESS_FORCEINLINE OffsetType &priv_offset() BOOST_NOEXCEPT + { return internal.m_offset; } + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!operator<< +//!for offset ptr +template +inline std::basic_ostream & operator<< + (std::basic_ostream & os, offset_ptr const & p) +{ return os << p.get_offset(); } + +//!operator>> +//!for offset ptr +template +inline std::basic_istream & operator>> + (std::basic_istream & is, offset_ptr & p) +{ return is >> p.get_offset(); } + +//!Simulation of static_cast between pointers. Never throws. +template +BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr + static_pointer_cast(const boost::interprocess::offset_ptr & r) BOOST_NOEXCEPT +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::ipcdetail::static_cast_tag()); +} + +//!Simulation of const_cast between pointers. Never throws. +template +BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr + const_pointer_cast(const boost::interprocess::offset_ptr & r) BOOST_NOEXCEPT +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::ipcdetail::const_cast_tag()); +} + +//!Simulation of dynamic_cast between pointers. Never throws. +template +BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr + dynamic_pointer_cast(const boost::interprocess::offset_ptr & r) BOOST_NOEXCEPT +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::ipcdetail::dynamic_cast_tag()); +} + +//!Simulation of reinterpret_cast between pointers. Never throws. +template +BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr + reinterpret_pointer_cast(const boost::interprocess::offset_ptr & r) BOOST_NOEXCEPT +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::ipcdetail::reinterpret_cast_tag()); +} + +} //namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +///has_trivial_destructor<> == true_type specialization for optimizations +template +struct has_trivial_destructor< ::boost::interprocess::offset_ptr > +{ + static const bool value = true; +}; + +namespace move_detail { + +///has_trivial_destructor<> == true_type specialization for optimizations +template +struct is_trivially_destructible< ::boost::interprocess::offset_ptr > +{ + static const bool value = true; +}; + +} //namespace move_detail { + +namespace interprocess { + +//!to_raw_pointer() enables boost::mem_fn to recognize offset_ptr. +//!Never throws. +template +BOOST_INTERPROCESS_FORCEINLINE T * to_raw_pointer(boost::interprocess::offset_ptr const & p) BOOST_NOEXCEPT +{ return ipcdetail::to_raw_pointer(p); } + +} //namespace interprocess + + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +} //namespace boost { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace boost{ + +//This is to support embedding a bit in the pointer +//for intrusive containers, saving space +namespace intrusive { + +//Predeclaration to avoid including header +template +struct max_pointer_plus_bits; + +template +struct max_pointer_plus_bits, OffsetAlignment> +{ + //The offset ptr can embed one bit less than the alignment since it + //uses offset == 1 to store the null pointer. + static const std::size_t value = ::boost::interprocess::ipcdetail::ls_zeros::value - 1; +}; + +//Predeclaration +template +struct pointer_plus_bits; + +template +struct pointer_plus_bits, NumBits> +{ + typedef boost::interprocess::offset_ptr pointer; + //Bits are stored in the lower bits of the pointer except the LSB, + //because this bit is used to represent the null pointer. + static const uintptr_t Mask = ((uintptr_t(1) << uintptr_t(NumBits)) - uintptr_t(1)) << uintptr_t(1); + BOOST_STATIC_ASSERT(0 ==(Mask&1)); + + //We must ALWAYS take argument "n" by reference as a copy of a null pointer + //with a bit (e.g. offset == 3) would be incorrectly copied and interpreted as non-null. + + BOOST_INTERPROCESS_FORCEINLINE static pointer get_pointer(const pointer &n) BOOST_NOEXCEPT + { + pointer p; + O const tmp_off = n.priv_offset() & O(~Mask); + p.priv_offset() = boost::interprocess::ipcdetail::offset_ptr_to_offset_from_other(&p, &n, tmp_off); + return p; + } + + BOOST_INTERPROCESS_FORCEINLINE static void set_pointer(pointer &n, const pointer &p) BOOST_NOEXCEPT + { + BOOST_ASSERT(0 == (get_bits)(p)); + O const stored_bits = O(n.priv_offset() & Mask); + n = p; + n.priv_offset() |= stored_bits; + } + + BOOST_INTERPROCESS_FORCEINLINE static std::size_t get_bits(const pointer &n) BOOST_NOEXCEPT + { + return std::size_t((n.priv_offset() & Mask) >> 1u); + } + + BOOST_INTERPROCESS_FORCEINLINE static void set_bits(pointer &n, std::size_t const b) BOOST_NOEXCEPT + { + BOOST_ASSERT(b < (std::size_t(1) << NumBits)); + O tmp = n.priv_offset(); + tmp &= O(~Mask); + tmp |= O(b << 1u); + n.priv_offset() = tmp; + } +}; + +} //namespace intrusive + +//Predeclaration +template +struct pointer_to_other; + +//Backwards compatibility with pointer_to_other +template +struct pointer_to_other + < ::boost::interprocess::offset_ptr, U > +{ + typedef ::boost::interprocess::offset_ptr type; +}; + +} //namespace boost{ +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +#include + +#endif //#ifndef BOOST_INTERPROCESS_OFFSET_PTR_HPP diff --git a/libraries/boost/boost/interprocess/permissions.hpp b/libraries/boost/boost/interprocess/permissions.hpp new file mode 100644 index 000000000..87fea28be --- /dev/null +++ b/libraries/boost/boost/interprocess/permissions.hpp @@ -0,0 +1,132 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_PERMISSIONS_HPP +#define BOOST_INTERPROCESS_PERMISSIONS_HPP + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +#include + +#endif + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!\file +//!Describes permissions class + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +namespace ipcdetail { + +template +struct unrestricted_permissions_holder +{ + static winapi::interprocess_all_access_security unrestricted; +}; + +template +winapi::interprocess_all_access_security unrestricted_permissions_holder::unrestricted; + +} //namespace ipcdetail { + +#endif //defined BOOST_INTERPROCESS_WINDOWS + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!The permissions class represents permissions to be set to shared memory or +//!files, that can be constructed form usual permission representations: +//!a SECURITY_ATTRIBUTES pointer in windows or ORed rwx chmod integer in UNIX. +class permissions +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + #if defined(BOOST_INTERPROCESS_WINDOWS) + typedef void* os_permissions_type; + #else + typedef int os_permissions_type; + #endif + os_permissions_type m_perm; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructs a permissions object from a user provided os-dependent + //!permissions. + permissions(os_permissions_type type) + : m_perm(type) + {} + + //!Constructs a default permissions object: + //!A null security attributes pointer for windows or 0644 + //!for UNIX. + permissions() + { set_default(); } + + //!Sets permissions to default values: + //!A null security attributes pointer for windows or 0644 + //!for UNIX. + void set_default() + { + #if defined (BOOST_INTERPROCESS_WINDOWS) + m_perm = 0; + #else + m_perm = 0644; + #endif + } + + //!Sets permissions to unrestricted access: + //!A null DACL for windows or 0666 for UNIX. + void set_unrestricted() + { + #if defined (BOOST_INTERPROCESS_WINDOWS) + m_perm = &ipcdetail::unrestricted_permissions_holder<0>::unrestricted; + #else + m_perm = 0666; + #endif + } + + //!Sets permissions from a user provided os-dependent + //!permissions. + void set_permissions(os_permissions_type perm) + { m_perm = perm; } + + //!Returns stored os-dependent + //!permissions + os_permissions_type get_permissions() const + { return m_perm; } +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_PERMISSIONS_HPP + diff --git a/libraries/boost/boost/interprocess/segment_manager.hpp b/libraries/boost/boost/interprocess/segment_manager.hpp new file mode 100644 index 000000000..d00f17716 --- /dev/null +++ b/libraries/boost/boost/interprocess/segment_manager.hpp @@ -0,0 +1,1343 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP +#define BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// container/detail +#include +#include +// std +#include //std::size_t +#include +#include +#ifndef BOOST_NO_EXCEPTIONS +#include +#endif + +//!\file +//!Describes the object placed in a memory segment that provides +//!named object allocation capabilities for single-segment and +//!multi-segment allocations. + +namespace boost{ +namespace interprocess{ + +//!This object is the public base class of segment manager. +//!This class only depends on the memory allocation algorithm +//!and implements all the allocation features not related +//!to named or unique objects. +//! +//!Storing a reference to segment_manager forces +//!the holder class to be dependent on index types and character types. +//!When such dependence is not desirable and only anonymous and raw +//!allocations are needed, segment_manager_base is the correct answer. +template +class segment_manager_base + : private MemoryAlgorithm +{ + public: + typedef segment_manager_base segment_manager_base_type; + typedef typename MemoryAlgorithm::void_pointer void_pointer; + typedef typename MemoryAlgorithm::mutex_family mutex_family; + typedef MemoryAlgorithm memory_algorithm; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Experimental. Don't use + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; + typedef typename MemoryAlgorithm::difference_type difference_type; + typedef typename MemoryAlgorithm::size_type size_type; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!This constant indicates the payload size + //!associated with each allocation of the memory algorithm + static const size_type PayloadPerAllocation = MemoryAlgorithm::PayloadPerAllocation; + + //!Constructor of the segment_manager_base + //! + //!"size" is the size of the memory segment where + //!the basic segment manager is being constructed. + //! + //!"reserved_bytes" is the number of bytes + //!after the end of the memory algorithm object itself + //!that the memory algorithm will exclude from + //!dynamic allocation + //! + //!Can throw + segment_manager_base(size_type sz, size_type reserved_bytes) + : MemoryAlgorithm(sz, reserved_bytes) + { + BOOST_ASSERT((sizeof(segment_manager_base) == sizeof(MemoryAlgorithm))); + } + + //!Returns the size of the memory + //!segment + size_type get_size() const + { return MemoryAlgorithm::get_size(); } + + //!Returns the number of free bytes of the memory + //!segment + size_type get_free_memory() const + { return MemoryAlgorithm::get_free_memory(); } + + //!Obtains the minimum size needed by + //!the segment manager + static size_type get_min_size (size_type size) + { return MemoryAlgorithm::get_min_size(size); } + + //!Allocates nbytes bytes. This function is only used in + //!single-segment management. Never throws + void * allocate (size_type nbytes, const std::nothrow_t &) + { return MemoryAlgorithm::allocate(nbytes); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Experimental. Dont' use. + //!Allocates n_elements of elem_bytes bytes. + //!Throws bad_alloc on failure. chain.size() is not increased on failure. + void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + { + size_type prev_size = chain.size(); + MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); + if(!elem_bytes || chain.size() == prev_size){ + throw bad_alloc(); + } + } + + //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes. + //!Throws bad_alloc on failure. chain.size() is not increased on failure. + void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { + size_type prev_size = chain.size(); + MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain); + if(!sizeof_element || chain.size() == prev_size){ + throw bad_alloc(); + } + } + + //!Allocates n_elements of elem_bytes bytes. + //!Non-throwing version. chain.size() is not increased on failure. + void allocate_many(const std::nothrow_t &, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + { MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); } + + //!Allocates n_elements, each one of + //!element_lengths[i]*sizeof_element bytes. + //!Non-throwing version. chain.size() is not increased on failure. + void allocate_many(const std::nothrow_t &, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); } + + //!Deallocates all elements contained in chain. + //!Never throws. + void deallocate_many(multiallocation_chain &chain) + { MemoryAlgorithm::deallocate_many(chain); } + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc + //!on failure + void * allocate(size_type nbytes) + { + void * ret = MemoryAlgorithm::allocate(nbytes); + if(!ret) + throw bad_alloc(); + return ret; + } + + //!Allocates nbytes bytes. This function is only used in + //!single-segment management. Never throws + void * allocate_aligned (size_type nbytes, size_type alignment, const std::nothrow_t &) + { return MemoryAlgorithm::allocate_aligned(nbytes, alignment); } + + //!Allocates nbytes bytes. This function is only used in + //!single-segment management. Throws bad_alloc when fails + void * allocate_aligned(size_type nbytes, size_type alignment) + { + void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment); + if(!ret) + throw bad_alloc(); + return ret; + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + template + T *allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type &prefer_in_recvd_out_size, T *&reuse) + { + T *ret = MemoryAlgorithm::allocation_command + (command | boost::interprocess::nothrow_allocation, limit_size, prefer_in_recvd_out_size, reuse); + if(!(command & boost::interprocess::nothrow_allocation) && !ret) + throw bad_alloc(); + return ret; + } + + void *raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects, + size_type &prefer_in_recvd_out_size, void *&reuse, size_type sizeof_object = 1) + { + void *ret = MemoryAlgorithm::raw_allocation_command + ( command | boost::interprocess::nothrow_allocation, limit_objects, + prefer_in_recvd_out_size, reuse, sizeof_object); + if(!(command & boost::interprocess::nothrow_allocation) && !ret) + throw bad_alloc(); + return ret; + } + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Deallocates the bytes allocated with allocate/allocate_many() + //!pointed by addr + void deallocate (void *addr) + { MemoryAlgorithm::deallocate(addr); } + + //!Increases managed memory in extra_size bytes more. This only works + //!with single-segment management. + void grow(size_type extra_size) + { MemoryAlgorithm::grow(extra_size); } + + //!Decreases managed memory to the minimum. This only works + //!with single-segment management. + void shrink_to_fit() + { MemoryAlgorithm::shrink_to_fit(); } + + //!Returns the result of "all_memory_deallocated()" function + //!of the used memory algorithm + bool all_memory_deallocated() + { return MemoryAlgorithm::all_memory_deallocated(); } + + //!Returns the result of "check_sanity()" function + //!of the used memory algorithm + bool check_sanity() + { return MemoryAlgorithm::check_sanity(); } + + //!Writes to zero free memory (memory not yet allocated) + //!of the memory algorithm + void zero_free_memory() + { MemoryAlgorithm::zero_free_memory(); } + + //!Returns the size of the buffer previously allocated pointed by ptr + size_type size(const void *ptr) const + { return MemoryAlgorithm::size(ptr); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + protected: + void * prot_anonymous_construct + (size_type num, bool dothrow, ipcdetail::in_place_interface &table) + { + typedef ipcdetail::block_header block_header_t; + block_header_t block_info ( size_type(table.size*num) + , size_type(table.alignment) + , anonymous_type + , 1 + , 0); + + //Allocate memory + void *ptr_struct = this->allocate(block_info.total_size(), nothrow<>::get()); + + //Check if there is enough memory + if(!ptr_struct){ + if(dothrow){ + throw bad_alloc(); + } + else{ + return 0; + } + } + + //Build scoped ptr to avoid leaks with constructor exception + ipcdetail::mem_algo_deallocator mem(ptr_struct, *this); + + //Now construct the header + block_header_t * hdr = ::new(ptr_struct, boost_container_new_t()) block_header_t(block_info); + void *ptr = 0; //avoid gcc warning + ptr = hdr->value(); + + //Now call constructors + ipcdetail::array_construct(ptr, num, table); + + //All constructors successful, we don't want erase memory + mem.release(); + return ptr; + } + + //!Calls the destructor and makes an anonymous deallocate + void prot_anonymous_destroy(const void *object, ipcdetail::in_place_interface &table) + { + + //Get control data from associated with this object + typedef ipcdetail::block_header block_header_t; + block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment); + + //------------------------------- + //scoped_lock guard(m_header); + //------------------------------- + + if(ctrl_data->alloc_type() != anonymous_type){ + //This is not an anonymous object, the pointer is wrong! + BOOST_ASSERT(0); + } + + //Call destructors and free memory + //Build scoped ptr to avoid leaks with destructor exception + std::size_t destroyed = 0; + table.destroy_n(const_cast(object), ctrl_data->m_value_bytes/table.size, destroyed); + this->deallocate(ctrl_data); + } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!This object is placed in the beginning of memory segment and +//!implements the allocation (named or anonymous) of portions +//!of the segment. This object contains two indexes that +//!maintain an association between a name and a portion of the segment. +//! +//!The first index contains the mappings for normal named objects using the +//!char type specified in the template parameter. +//! +//!The second index contains the association for unique instances. The key will +//!be the const char * returned from type_info.name() function for the unique +//!type to be constructed. +//! +//!segment_manager inherits publicly +//!from segment_manager_base and inherits from it +//!many public functions related to anonymous object and raw memory allocation. +//!See segment_manager_base reference to know about those functions. +template class IndexType> +class segment_manager + : public segment_manager_base +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + segment_manager(); + segment_manager(const segment_manager &); + segment_manager &operator=(const segment_manager &); + typedef segment_manager_base segment_manager_base_t; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef MemoryAlgorithm memory_algorithm; + typedef typename segment_manager_base_t::void_pointer void_pointer; + typedef typename segment_manager_base_t::size_type size_type; + typedef typename segment_manager_base_t::difference_type difference_type; + typedef CharType char_type; + + typedef segment_manager_base segment_manager_base_type; + + static const size_type PayloadPerAllocation = segment_manager_base_t::PayloadPerAllocation; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef ipcdetail::block_header block_header_t; + typedef ipcdetail::index_config index_config_named; + typedef ipcdetail::index_config index_config_unique; + typedef IndexType index_type; + typedef ipcdetail::bool_::value > is_intrusive_t; + typedef ipcdetail::bool_::value> is_node_index_t; + + public: + typedef IndexType named_index_t; + typedef IndexType unique_index_t; + typedef ipcdetail::char_ptr_holder char_ptr_holder_t; + typedef ipcdetail::segment_manager_iterator_transform + ::value> named_transform; + + typedef ipcdetail::segment_manager_iterator_transform + ::value> unique_transform; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + typedef typename segment_manager_base_t::mutex_family mutex_family; + + typedef transform_iterator + const_named_iterator; + typedef transform_iterator + const_unique_iterator; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //!Constructor proxy object definition helper class + template + struct construct_proxy + { + typedef ipcdetail::named_proxy type; + }; + + //!Constructor proxy object definition helper class + template + struct construct_iter_proxy + { + typedef ipcdetail::named_proxy type; + }; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Constructor of the segment manager + //!"size" is the size of the memory segment where + //!the segment manager is being constructed. + //!Can throw + explicit segment_manager(size_type segment_size) + : segment_manager_base_t(segment_size, priv_get_reserved_bytes()) + , m_header(static_cast(get_this_pointer())) + { + (void) anonymous_instance; (void) unique_instance; + //Check EBO is applied, it's required + const void * const this_addr = this; + const void *const segm_addr = static_cast(this); + (void)this_addr; (void)segm_addr; + BOOST_ASSERT( this_addr == segm_addr); + } + + //!Tries to find a previous named/unique allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. + template + std::pair find (char_ptr_holder_t name) + { return this->priv_find_impl(name, true); } + + //!Tries to find a previous named/unique allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. This search is not mutex-protected! + //!Use it only inside atomic_func() calls, where the internal mutex + //!is guaranteed to be locked. + template + std::pair find_no_lock (char_ptr_holder_t name) + { return this->priv_find_impl(name, false); } + + //!Returns throwing "construct" proxy + //!object + template + typename construct_proxy::type + construct(char_ptr_holder_t name) + { return typename construct_proxy::type (this, name, false, true); } + + //!Returns throwing "search or construct" proxy + //!object + template + typename construct_proxy::type find_or_construct(char_ptr_holder_t name) + { return typename construct_proxy::type (this, name, true, true); } + + //!Returns no throwing "construct" proxy + //!object + template + typename construct_proxy::type + construct(char_ptr_holder_t name, const std::nothrow_t &) + { return typename construct_proxy::type (this, name, false, false); } + + //!Returns no throwing "search or construct" + //!proxy object + template + typename construct_proxy::type + find_or_construct(char_ptr_holder_t name, const std::nothrow_t &) + { return typename construct_proxy::type (this, name, true, false); } + + //!Returns throwing "construct from iterators" proxy object + template + typename construct_iter_proxy::type + construct_it(char_ptr_holder_t name) + { return typename construct_iter_proxy::type (this, name, false, true); } + + //!Returns throwing "search or construct from iterators" + //!proxy object + template + typename construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name) + { return typename construct_iter_proxy::type (this, name, true, true); } + + //!Returns no throwing "construct from iterators" + //!proxy object + template + typename construct_iter_proxy::type + construct_it(char_ptr_holder_t name, const std::nothrow_t &) + { return typename construct_iter_proxy::type (this, name, false, false); } + + //!Returns no throwing "search or construct from iterators" + //!proxy object + template + typename construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name, const std::nothrow_t &) + { return typename construct_iter_proxy::type (this, name, true, false); } + + //!Calls object function blocking recursive interprocess_mutex and guarantees that + //!no new named_alloc or destroy will be executed by any process while + //!executing the object function call + template + void atomic_func(Func &f) + { scoped_lock guard(m_header); f(); } + + //!Tries to calls 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) + { + scoped_lock guard(m_header, try_to_lock); + if(guard){ + f(); + return true; + } + else{ + return false; + } + } + + //!Destroys a previously created named/unique instance. + //!Returns false if the object was not present. + template + bool destroy(char_ptr_holder_t name) + { + BOOST_ASSERT(!name.is_anonymous()); + ipcdetail::placement_destroy dtor; + + if(name.is_unique()){ + return this->priv_generic_named_destroy + ( typeid(T).name(), m_header.m_unique_index , dtor, is_intrusive_t()); + } + else{ + return this->priv_generic_named_destroy + ( name.get(), m_header.m_named_index, dtor, is_intrusive_t()); + } + } + + //!Destroys an anonymous, unique or named object + //!using its address + template + void destroy_ptr(const T *p) + { + //If T is void transform it to char + typedef typename ipcdetail::char_if_void::type data_t; + ipcdetail::placement_destroy dtor; + priv_destroy_ptr(p, dtor); + } + + //!Returns the name of an object created with construct/find_or_construct + //!functions. Does not throw + template + static const CharType *get_instance_name(const T *ptr) + { return priv_get_instance_name(block_header_t::block_header_from_value(ptr)); } + + //!Returns the length of an object created with construct/find_or_construct + //!functions. Does not throw. + template + static size_type get_instance_length(const T *ptr) + { return priv_get_instance_length(block_header_t::block_header_from_value(ptr), sizeof(T)); } + + //!Returns is the the name of an object created with construct/find_or_construct + //!functions. Does not throw + template + static instance_type get_instance_type(const T *ptr) + { return priv_get_instance_type(block_header_t::block_header_from_value(ptr)); } + + //!Preallocates needed index resources to optimize the + //!creation of "num" named objects in the managed memory segment. + //!Can throw boost::interprocess::bad_alloc if there is no enough memory. + void reserve_named_objects(size_type num) + { + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + m_header.m_named_index.reserve(num); + } + + //!Preallocates needed index resources to optimize the + //!creation of "num" unique objects in the managed memory segment. + //!Can throw boost::interprocess::bad_alloc if there is no enough memory. + void reserve_unique_objects(size_type num) + { + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + m_header.m_unique_index.reserve(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() + { + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + m_header.m_named_index.shrink_to_fit(); + m_header.m_unique_index.shrink_to_fit(); + } + + //!Returns the number of named objects stored in + //!the segment. + size_type get_num_named_objects() + { + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + return m_header.m_named_index.size(); + } + + //!Returns the number of unique objects stored in + //!the segment. + size_type get_num_unique_objects() + { + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + return m_header.m_unique_index.size(); + } + + //!Obtains the minimum size needed by the + //!segment manager + static size_type get_min_size() + { return segment_manager_base_t::get_min_size(priv_get_reserved_bytes()); } + + //!Returns a constant iterator to the beginning of the information about + //!the named allocations performed in this segment manager + const_named_iterator named_begin() const + { + return make_transform_iterator + (m_header.m_named_index.begin(), named_transform()); + } + + //!Returns a constant iterator to the end of the information about + //!the named allocations performed in this segment manager + const_named_iterator named_end() const + { + return make_transform_iterator + (m_header.m_named_index.end(), named_transform()); + } + + //!Returns a constant iterator to the beginning of the information about + //!the unique allocations performed in this segment manager + const_unique_iterator unique_begin() const + { + return make_transform_iterator + (m_header.m_unique_index.begin(), unique_transform()); + } + + //!Returns a constant iterator to the end of the information about + //!the unique allocations performed in this segment manager + const_unique_iterator unique_end() const + { + return make_transform_iterator + (m_header.m_unique_index.end(), unique_transform()); + } + + //!This is the default allocator to allocate types T + //!from this managed segment + template + struct allocator + { + typedef boost::interprocess::allocator 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 typename allocator::type(this); } + + //!This is the default deleter to delete types T + //!from this managed segment. + template + struct deleter + { + typedef boost::interprocess::deleter type; + }; + + //!Returns an instance of the default deleter for type T + //!that will delete an object constructed in this segment manager. + template + typename deleter::type + get_deleter() + { return typename deleter::type(this); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //!Generic named/anonymous new function. Offers all the possibilities, + //!such as throwing, search before creating, and the constructor is + //!encapsulated in an object function. + template + T *generic_construct(const CharType *name, + size_type num, + bool try2find, + bool dothrow, + ipcdetail::in_place_interface &table) + { + return static_cast + (priv_generic_construct(name, num, try2find, dothrow, table)); + } + + private: + //!Tries to find a previous named allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. + template + std::pair priv_find_impl (const CharType* name, bool lock) + { + //The name can't be null, no anonymous object can be found by name + BOOST_ASSERT(name != 0); + ipcdetail::placement_destroy table; + size_type sz; + void *ret; + + if(name == reinterpret_cast(-1)){ + ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, sz, is_intrusive_t(), lock); + } + else{ + ret = priv_generic_find (name, m_header.m_named_index, table, sz, is_intrusive_t(), lock); + } + return std::pair(static_cast(ret), sz); + } + + //!Tries to find a previous unique allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. + template + std::pair priv_find_impl (const ipcdetail::unique_instance_t* name, bool lock) + { + ipcdetail::placement_destroy table; + size_type size; + void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock); + return std::pair(static_cast(ret), size); + } + + void *priv_generic_construct + (const CharType *name, size_type num, bool try2find, bool dothrow, ipcdetail::in_place_interface &table) + { + void *ret; + //Security overflow check + if(num > ((std::size_t)-1)/table.size){ + if(dothrow) + throw bad_alloc(); + else + return 0; + } + if(name == 0){ + ret = this->prot_anonymous_construct(num, dothrow, table); + } + else if(name == reinterpret_cast(-1)){ + ret = this->priv_generic_named_construct + (unique_type, table.type_name, num, try2find, dothrow, table, m_header.m_unique_index, is_intrusive_t()); + } + else{ + ret = this->priv_generic_named_construct + (named_type, name, num, try2find, dothrow, table, m_header.m_named_index, is_intrusive_t()); + } + return ret; + } + + void priv_destroy_ptr(const void *ptr, ipcdetail::in_place_interface &dtor) + { + block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment); + switch(ctrl_data->alloc_type()){ + case anonymous_type: + this->prot_anonymous_destroy(ptr, dtor); + break; + + case named_type: + this->priv_generic_named_destroy + (ctrl_data, m_header.m_named_index, dtor, is_node_index_t()); + break; + + case unique_type: + this->priv_generic_named_destroy + (ctrl_data, m_header.m_unique_index, dtor, is_node_index_t()); + break; + + default: + //This type is unknown, bad pointer passed to this function! + BOOST_ASSERT(0); + break; + } + } + + //!Returns the name of an object created with construct/find_or_construct + //!functions. Does not throw + static const CharType *priv_get_instance_name(block_header_t *ctrl_data) + { + boost::interprocess::allocation_type type = ctrl_data->alloc_type(); + if(type == anonymous_type){ + BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) || + (type == unique_type && ctrl_data->m_num_char != 0) ); + return 0; + } + CharType *name = static_cast(ctrl_data->template name()); + + //Sanity checks + BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharType)); + BOOST_ASSERT(ctrl_data->m_num_char == std::char_traits::length(name)); + return name; + } + + static size_type priv_get_instance_length(block_header_t *ctrl_data, size_type sizeofvalue) + { + //Get header + BOOST_ASSERT((ctrl_data->value_bytes() %sizeofvalue) == 0); + return ctrl_data->value_bytes()/sizeofvalue; + } + + //!Returns is the the name of an object created with construct/find_or_construct + //!functions. Does not throw + static instance_type priv_get_instance_type(block_header_t *ctrl_data) + { + //Get header + BOOST_ASSERT((instance_type)ctrl_data->alloc_type() < max_allocation_type); + return (instance_type)ctrl_data->alloc_type(); + } + + static size_type priv_get_reserved_bytes() + { + //Get the number of bytes until the end of (*this) + //beginning in the end of the segment_manager_base_t base. + return sizeof(segment_manager) - sizeof(segment_manager_base_t); + } + + template + void *priv_generic_find + (const CharT* name, + IndexType > &index, + ipcdetail::in_place_interface &table, + size_type &length, ipcdetail::true_ is_intrusive, bool use_lock) + { + (void)is_intrusive; + typedef IndexType > index_type; + typedef typename index_type::iterator index_it; + + //------------------------------- + scoped_lock guard(priv_get_lock(use_lock)); + //------------------------------- + //Find name in index + ipcdetail::intrusive_compare_key key + (name, std::char_traits::length(name)); + index_it it = index.find(key); + + //Initialize return values + void *ret_ptr = 0; + length = 0; + + //If found, assign values + if(it != index.end()){ + //Get header + block_header_t *ctrl_data = it->get_block_header(); + + //Sanity check + BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); + BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT)); + ret_ptr = ctrl_data->value(); + length = ctrl_data->m_value_bytes/table.size; + } + return ret_ptr; + } + + template + void *priv_generic_find + (const CharT* name, + IndexType > &index, + ipcdetail::in_place_interface &table, + size_type &length, ipcdetail::false_ is_intrusive, bool use_lock) + { + (void)is_intrusive; + typedef IndexType > index_type; + typedef typename index_type::key_type key_type; + typedef typename index_type::iterator index_it; + + //------------------------------- + scoped_lock guard(priv_get_lock(use_lock)); + //------------------------------- + //Find name in index + index_it it = index.find(key_type(name, std::char_traits::length(name))); + + //Initialize return values + void *ret_ptr = 0; + length = 0; + + //If found, assign values + if(it != index.end()){ + //Get header + block_header_t *ctrl_data = reinterpret_cast + (ipcdetail::to_raw_pointer(it->second.m_ptr)); + + //Sanity check + BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); + BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT)); + ret_ptr = ctrl_data->value(); + length = ctrl_data->m_value_bytes/table.size; + } + return ret_ptr; + } + + template + bool priv_generic_named_destroy + (block_header_t *block_header, + IndexType > &index, + ipcdetail::in_place_interface &table, ipcdetail::true_ is_node_index) + { + (void)is_node_index; + typedef typename IndexType >::iterator index_it; + + index_it *ihdr = block_header_t::template to_first_header(block_header); + return this->priv_generic_named_destroy_impl(*ihdr, index, table); + } + + template + bool priv_generic_named_destroy + (block_header_t *block_header, + IndexType > &index, + ipcdetail::in_place_interface &table, + ipcdetail::false_ is_node_index) + { + (void)is_node_index; + CharT *name = static_cast(block_header->template name()); + return this->priv_generic_named_destroy(name, index, table, is_intrusive_t()); + } + + template + bool priv_generic_named_destroy(const CharT *name, + IndexType > &index, + ipcdetail::in_place_interface &table, ipcdetail::true_ is_intrusive_index) + { + (void)is_intrusive_index; + typedef IndexType > index_type; + typedef typename index_type::iterator index_it; + typedef typename index_type::value_type intrusive_value_type; + + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + //Find name in index + ipcdetail::intrusive_compare_key key + (name, std::char_traits::length(name)); + index_it it = index.find(key); + + //If not found, return false + if(it == index.end()){ + //This name is not present in the index, wrong pointer or name! + //BOOST_ASSERT(0); + return false; + } + + block_header_t *ctrl_data = it->get_block_header(); + intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data); + void *memory = iv; + void *values = ctrl_data->value(); + std::size_t num = ctrl_data->m_value_bytes/table.size; + + //Sanity check + BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); + BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char()); + + //Erase node from index + index.erase(it); + + //Destroy the headers + ctrl_data->~block_header_t(); + iv->~intrusive_value_type(); + + //Call destructors and free memory + std::size_t destroyed; + table.destroy_n(values, num, destroyed); + this->deallocate(memory); + return true; + } + + template + bool priv_generic_named_destroy(const CharT *name, + IndexType > &index, + ipcdetail::in_place_interface &table, + ipcdetail::false_ is_intrusive_index) + { + (void)is_intrusive_index; + typedef IndexType > index_type; + typedef typename index_type::iterator index_it; + typedef typename index_type::key_type key_type; + + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + //Try to find the name in the index + index_it it = index.find(key_type (name, + std::char_traits::length(name))); + + //If not found, return false + if(it == index.end()){ + //This name is not present in the index, wrong pointer or name! + //BOOST_ASSERT(0); + return false; + } + return this->priv_generic_named_destroy_impl(it, index, table); + } + + template + bool priv_generic_named_destroy_impl + (const typename IndexType >::iterator &it, + IndexType > &index, + ipcdetail::in_place_interface &table) + { + typedef IndexType > index_type; + typedef typename index_type::iterator index_it; + + //Get allocation parameters + block_header_t *ctrl_data = reinterpret_cast + (ipcdetail::to_raw_pointer(it->second.m_ptr)); + char *stored_name = static_cast(static_cast(const_cast(it->first.name()))); + (void)stored_name; + + //Check if the distance between the name pointer and the memory pointer + //is correct (this can detect incorrect type in destruction) + std::size_t num = ctrl_data->m_value_bytes/table.size; + void *values = ctrl_data->value(); + + //Sanity check + BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); + BOOST_ASSERT(static_cast(stored_name) == static_cast(ctrl_data->template name())); + BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char()); + + //Erase node from index + index.erase(it); + + //Destroy the header + ctrl_data->~block_header_t(); + + void *memory; + if(is_node_index_t::value){ + index_it *ihdr = block_header_t::template + to_first_header(ctrl_data); + ihdr->~index_it(); + memory = ihdr; + } + else{ + memory = ctrl_data; + } + + //Call destructors and free memory + std::size_t destroyed; + table.destroy_n(values, num, destroyed); + this->deallocate(memory); + return true; + } + + template + void * priv_generic_named_construct + (unsigned char type, const CharT *name, size_type num, bool try2find, + bool dothrow, ipcdetail::in_place_interface &table, + IndexType > &index, ipcdetail::true_ is_intrusive) + { + (void)is_intrusive; + std::size_t namelen = std::char_traits::length(name); + + block_header_t block_info ( size_type(table.size*num) + , size_type(table.alignment) + , type + , sizeof(CharT) + , namelen); + + typedef IndexType > index_type; + typedef typename index_type::iterator index_it; + typedef std::pair index_ib; + + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + //Insert the node. This can throw. + //First, we want to know if the key is already present before + //we allocate any memory, and if the key is not present, we + //want to allocate all memory in a single buffer that will + //contain the name and the user buffer. + // + //Since equal_range(key) + insert(hint, value) approach is + //quite inefficient in container implementations + //(they re-test if the position is correct), I've chosen + //to insert the node, do an ugly un-const cast and modify + //the key (which is a smart pointer) to an equivalent one + index_ib insert_ret; + + typename index_type::insert_commit_data commit_data; + typedef typename index_type::value_type intrusive_value_type; + + BOOST_TRY{ + ipcdetail::intrusive_compare_key key(name, namelen); + insert_ret = index.insert_check(key, commit_data); + } + //Ignore exceptions + BOOST_CATCH(...){ + if(dothrow) + BOOST_RETHROW + return 0; + } + BOOST_CATCH_END + + index_it it = insert_ret.first; + + //If found and this is find or construct, return data + //else return null + if(!insert_ret.second){ + if(try2find){ + return it->get_block_header()->value(); + } + if(dothrow){ + throw interprocess_exception(already_exists_error); + } + else{ + return 0; + } + } + + //Allocates buffer for name + data, this can throw (it hurts) + void *buffer_ptr; + + //Check if there is enough memory + if(dothrow){ + buffer_ptr = this->allocate + (block_info.template total_size_with_header()); + } + else{ + buffer_ptr = this->allocate + (block_info.template total_size_with_header(), nothrow<>::get()); + if(!buffer_ptr) + return 0; + } + + //Now construct the intrusive hook plus the header + intrusive_value_type * intrusive_hdr = ::new(buffer_ptr, boost_container_new_t()) intrusive_value_type(); + block_header_t * hdr = ::new(intrusive_hdr->get_block_header(), boost_container_new_t())block_header_t(block_info); + void *ptr = 0; //avoid gcc warning + ptr = hdr->value(); + + //Copy name to memory segment and insert data + CharT *name_ptr = static_cast(hdr->template name()); + std::char_traits::copy(name_ptr, name, namelen+1); + + BOOST_TRY{ + //Now commit the insertion using previous context data + it = index.insert_commit(*intrusive_hdr, commit_data); + } + //Ignore exceptions + BOOST_CATCH(...){ + if(dothrow) + BOOST_RETHROW + return 0; + } + BOOST_CATCH_END + + //Avoid constructions if constructor is trivial + //Build scoped ptr to avoid leaks with constructor exception + ipcdetail::mem_algo_deallocator mem + (buffer_ptr, *static_cast(this)); + + //Initialize the node value_eraser to erase inserted node + //if something goes wrong. This will be executed *before* + //the memory allocation as the intrusive value is built in that + //memory + value_eraser v_eraser(index, it); + + //Construct array, this can throw + ipcdetail::array_construct(ptr, num, table); + + //Release rollbacks since construction was successful + v_eraser.release(); + mem.release(); + return ptr; + } + + //!Generic named new function for + //!named functions + template + void * priv_generic_named_construct + (unsigned char type, const CharT *name, size_type num, bool try2find, bool dothrow, + ipcdetail::in_place_interface &table, + IndexType > &index, ipcdetail::false_ is_intrusive) + { + (void)is_intrusive; + std::size_t namelen = std::char_traits::length(name); + + block_header_t block_info ( size_type(table.size*num) + , size_type(table.alignment) + , type + , sizeof(CharT) + , namelen); + + typedef IndexType > index_type; + typedef typename index_type::key_type key_type; + typedef typename index_type::mapped_type mapped_type; + typedef typename index_type::value_type value_type; + typedef typename index_type::iterator index_it; + typedef std::pair index_ib; + + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + //Insert the node. This can throw. + //First, we want to know if the key is already present before + //we allocate any memory, and if the key is not present, we + //want to allocate all memory in a single buffer that will + //contain the name and the user buffer. + // + //Since equal_range(key) + insert(hint, value) approach is + //quite inefficient in container implementations + //(they re-test if the position is correct), I've chosen + //to insert the node, do an ugly un-const cast and modify + //the key (which is a smart pointer) to an equivalent one + index_ib insert_ret; + BOOST_TRY{ + insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0))); + } + //Ignore exceptions + BOOST_CATCH(...){ + if(dothrow) + BOOST_RETHROW; + return 0; + } + BOOST_CATCH_END + + index_it it = insert_ret.first; + + //If found and this is find or construct, return data + //else return null + if(!insert_ret.second){ + if(try2find){ + block_header_t *hdr = static_cast + (ipcdetail::to_raw_pointer(it->second.m_ptr)); + return hdr->value(); + } + return 0; + } + //Initialize the node value_eraser to erase inserted node + //if something goes wrong + value_eraser v_eraser(index, it); + + //Allocates buffer for name + data, this can throw (it hurts) + void *buffer_ptr; + block_header_t * hdr; + + //Allocate and construct the headers + if(is_node_index_t::value){ + size_type total_size = block_info.template total_size_with_header(); + if(dothrow){ + buffer_ptr = this->allocate(total_size); + } + else{ + buffer_ptr = this->allocate(total_size, nothrow<>::get()); + if(!buffer_ptr) + return 0; + } + index_it *idr = ::new(buffer_ptr, boost_container_new_t()) index_it(it); + hdr = block_header_t::template from_first_header(idr); + } + else{ + if(dothrow){ + buffer_ptr = this->allocate(block_info.total_size()); + } + else{ + buffer_ptr = this->allocate(block_info.total_size(), nothrow<>::get()); + if(!buffer_ptr) + return 0; + } + hdr = static_cast(buffer_ptr); + } + + hdr = ::new(hdr, boost_container_new_t())block_header_t(block_info); + void *ptr = 0; //avoid gcc warning + ptr = hdr->value(); + + //Copy name to memory segment and insert data + CharT *name_ptr = static_cast(hdr->template name()); + std::char_traits::copy(name_ptr, name, namelen+1); + + //Do the ugly cast, please mama, forgive me! + //This new key points to an identical string, so it must have the + //same position than the overwritten key according to the predicate + const_cast(it->first).name(name_ptr); + it->second.m_ptr = hdr; + + //Build scoped ptr to avoid leaks with constructor exception + ipcdetail::mem_algo_deallocator mem + (buffer_ptr, *static_cast(this)); + + //Construct array, this can throw + ipcdetail::array_construct(ptr, num, table); + + //All constructors successful, we don't want to release memory + mem.release(); + + //Release node v_eraser since construction was successful + v_eraser.release(); + return ptr; + } + + private: + //!Returns the this pointer + segment_manager *get_this_pointer() + { return this; } + + typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex; + + scoped_lock priv_get_lock(bool use_lock) + { + scoped_lock local(m_header, defer_lock); + if(use_lock){ + local.lock(); + } + return scoped_lock(boost::move(local)); + } + + //!This struct includes needed data and derives from + //!rmutex to allow EBO when using null interprocess_mutex + struct header_t + : public rmutex + { + named_index_t m_named_index; + unique_index_t m_unique_index; + + header_t(segment_manager_base_t *segment_mngr_base) + : m_named_index (segment_mngr_base) + , m_unique_index(segment_mngr_base) + {} + } m_header; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + + +}} //namespace boost { namespace interprocess + +#include + +#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP + diff --git a/libraries/boost/boost/interprocess/shared_memory_object.hpp b/libraries/boost/boost/interprocess/shared_memory_object.hpp new file mode 100644 index 000000000..34a695d46 --- /dev/null +++ b/libraries/boost/boost/interprocess/shared_memory_object.hpp @@ -0,0 +1,436 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP +#define BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) +# include //O_CREAT, O_*... +# include //shm_xxx +# include //ftruncate, close +# include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, +# if defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) +# if defined(__FreeBSD__) +# include +# endif +# endif +#else +// +#endif + +//!\file +//!Describes a shared memory object management class. + +namespace boost { +namespace interprocess { + +//!A class that wraps a shared memory mapping that can be used to +//!create mapped regions from the mapped files +class shared_memory_object +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable and non-assignable + BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_memory_object) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Default constructor. Represents an empty shared_memory_object. + shared_memory_object(); + + //!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode" + //!If the file previously exists, throws an error.*/ + shared_memory_object(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm); } + + //!Tries to create a shared memory object with name "name" and mode "mode", with the + //!access mode "mode". If the file previously exists, it tries to open it with mode "mode". + //!Otherwise throws an error. + shared_memory_object(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm); } + + //!Tries to open a shared memory object with name "name", with the access mode "mode". + //!If the file does not previously exist, it throws an error. + shared_memory_object(open_only_t, const char *name, mode_t mode) + { this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); } + + //!Moves the ownership of "moved"'s shared memory object to *this. + //!After the call, "moved" does not represent any shared memory object. + //!Does not throw + shared_memory_object(BOOST_RV_REF(shared_memory_object) moved) + : m_handle(file_handle_t(ipcdetail::invalid_file())) + , m_mode(read_only) + { this->swap(moved); } + + //!Moves the ownership of "moved"'s shared memory to *this. + //!After the call, "moved" does not represent any shared memory. + //!Does not throw + shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved) + { + shared_memory_object tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps the shared_memory_objects. Does not throw + void swap(shared_memory_object &moved); + + //!Erases a shared memory object from the system. + //!Returns false on error. Never throws + static bool remove(const char *name); + + //!Sets the size of the shared memory mapping + void truncate(offset_t length); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. All mapped regions are still + //!valid after destruction. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~shared_memory_object(); + + //!Returns the name of the shared memory object. + const char *get_name() const; + + //!Returns true if the size of the shared memory object + //!can be obtained and writes the size in the passed reference + bool get_size(offset_t &size) const; + + //!Returns access mode + mode_t get_mode() const; + + //!Returns mapping handle. Never throws. + mapping_handle_t get_mapping_handle() const; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + + //!Closes a previously opened file mapping. Never throws. + void priv_close(); + + //!Opens or creates a shared memory object. + bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm); + + file_handle_t m_handle; + mode_t m_mode; + std::string m_filename; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline shared_memory_object::shared_memory_object() + : m_handle(file_handle_t(ipcdetail::invalid_file())) + , m_mode(read_only) +{} + +inline shared_memory_object::~shared_memory_object() +{ this->priv_close(); } + + +inline const char *shared_memory_object::get_name() const +{ return m_filename.c_str(); } + +inline bool shared_memory_object::get_size(offset_t &size) const +{ return ipcdetail::get_file_size((file_handle_t)m_handle, size); } + +inline void shared_memory_object::swap(shared_memory_object &other) +{ + boost::adl_move_swap(m_handle, other.m_handle); + boost::adl_move_swap(m_mode, other.m_mode); + m_filename.swap(other.m_filename); +} + +inline mapping_handle_t shared_memory_object::get_mapping_handle() const +{ + return ipcdetail::mapping_handle_from_file_handle(m_handle); +} + +inline mode_t shared_memory_object::get_mode() const +{ return m_mode; } + +#if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) + +inline bool shared_memory_object::priv_open_or_create + (ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm) +{ + m_filename = filename; + std::string shmfile; + ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, shmfile); + + //Set accesses + if (mode != read_write && mode != read_only){ + error_info err = other_error; + throw interprocess_exception(err); + } + + switch(type){ + case ipcdetail::DoOpen: + m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true); + break; + case ipcdetail::DoCreate: + m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true); + break; + case ipcdetail::DoOpenOrCreate: + m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true); + break; + default: + { + error_info err = other_error; + throw interprocess_exception(err); + } + } + + //Check for error + if(m_handle == ipcdetail::invalid_file()){ + error_info err = system_error_code(); + this->priv_close(); + throw interprocess_exception(err); + } + + m_mode = mode; + return true; +} + +inline bool shared_memory_object::remove(const char *filename) +{ + try{ + //Make sure a temporary path is created for shared memory + std::string shmfile; + ipcdetail::shared_filepath(filename, shmfile); + return ipcdetail::delete_file(shmfile.c_str()); + } + catch(...){ + return false; + } +} + +inline void shared_memory_object::truncate(offset_t length) +{ + if(!ipcdetail::truncate_file(m_handle, length)){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } +} + +inline void shared_memory_object::priv_close() +{ + if(m_handle != ipcdetail::invalid_file()){ + ipcdetail::close_file(m_handle); + m_handle = ipcdetail::invalid_file(); + } +} + +#else //!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) + +namespace shared_memory_object_detail { + +#ifdef BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY + +#if defined(__FreeBSD__) + +inline bool use_filesystem_based_posix() +{ + int jailed = 0; + std::size_t len = sizeof(jailed); + ::sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0); + return jailed != 0; +} + +#else +#error "Not supported platform for BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY" +#endif + +#endif + +} //shared_memory_object_detail + +inline bool shared_memory_object::priv_open_or_create + (ipcdetail::create_enum_t type, + const char *filename, + mode_t mode, const permissions &perm) +{ + #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) + const bool add_leading_slash = false; + #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) + const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix(); + #else + const bool add_leading_slash = true; + #endif + if(add_leading_slash){ + ipcdetail::add_leading_slash(filename, m_filename); + } + else{ + ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, m_filename); + } + + //Create new mapping + int oflag = 0; + if(mode == read_only){ + oflag |= O_RDONLY; + } + else if(mode == read_write){ + oflag |= O_RDWR; + } + else{ + error_info err(mode_error); + throw interprocess_exception(err); + } + int unix_perm = perm.get_permissions(); + + switch(type){ + case ipcdetail::DoOpen: + { + //No oflag addition + m_handle = shm_open(m_filename.c_str(), oflag, unix_perm); + } + break; + case ipcdetail::DoCreate: + { + oflag |= (O_CREAT | O_EXCL); + m_handle = shm_open(m_filename.c_str(), oflag, unix_perm); + if(m_handle >= 0){ + ::fchmod(m_handle, unix_perm); + } + } + break; + case ipcdetail::DoOpenOrCreate: + { + //We need a create/open loop to change permissions correctly using fchmod, since + //with "O_CREAT" only we don't know if we've created or opened the shm. + while(1){ + //Try to create shared memory + m_handle = shm_open(m_filename.c_str(), oflag | (O_CREAT | O_EXCL), unix_perm); + //If successful change real permissions + if(m_handle >= 0){ + ::fchmod(m_handle, unix_perm); + } + //If already exists, try to open + else if(errno == EEXIST){ + m_handle = shm_open(m_filename.c_str(), oflag, unix_perm); + //If open fails and errno tells the file does not exist + //(shm was removed between creation and opening tries), just retry + if(m_handle < 0 && errno == ENOENT){ + continue; + } + } + //Exit retries + break; + } + } + break; + default: + { + error_info err = other_error; + throw interprocess_exception(err); + } + } + + //Check for error + if(m_handle < 0){ + error_info err = errno; + this->priv_close(); + throw interprocess_exception(err); + } + + m_filename = filename; + m_mode = mode; + return true; +} + +inline bool shared_memory_object::remove(const char *filename) +{ + try{ + std::string filepath; + #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) + const bool add_leading_slash = false; + #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) + const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix(); + #else + const bool add_leading_slash = true; + #endif + if(add_leading_slash){ + ipcdetail::add_leading_slash(filename, filepath); + } + else{ + ipcdetail::shared_filepath(filename, filepath); + } + return 0 == shm_unlink(filepath.c_str()); + } + catch(...){ + return false; + } +} + +inline void shared_memory_object::truncate(offset_t length) +{ + if(0 != ftruncate(m_handle, length)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } +} + +inline void shared_memory_object::priv_close() +{ + if(m_handle != -1){ + ::close(m_handle); + m_handle = -1; + } +} + +#endif + +//!A class that stores the name of a shared memory +//!and calls shared_memory_object::remove(name) in its destructor +//!Useful to remove temporary shared memory objects in the presence +//!of exceptions +class remove_shared_memory_on_destroy +{ + const char * m_name; + public: + remove_shared_memory_on_destroy(const char *name) + : m_name(name) + {} + + ~remove_shared_memory_on_destroy() + { shared_memory_object::remove(m_name); } +}; + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP diff --git a/libraries/boost/boost/interprocess/smart_ptr/deleter.hpp b/libraries/boost/boost/interprocess/smart_ptr/deleter.hpp new file mode 100644 index 000000000..3cd469df8 --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/deleter.hpp @@ -0,0 +1,68 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2012. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DELETER_HPP +#define BOOST_INTERPROCESS_DELETER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include + +//!\file +//!Describes the functor to delete objects from the segment. + +namespace boost { +namespace interprocess { + +//!A deleter that uses the segment manager's destroy_ptr +//!function to destroy the passed pointer resource. +//! +//!This deleter is used +template +class deleter +{ + public: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + + private: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type segment_manager_pointer; + + segment_manager_pointer mp_mngr; + + public: + deleter(segment_manager_pointer pmngr) + : mp_mngr(pmngr) + {} + + void operator()(const pointer &p) + { mp_mngr->destroy_ptr(ipcdetail::to_raw_pointer(p)); } +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DELETER_HPP diff --git a/libraries/boost/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp b/libraries/boost/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp new file mode 100644 index 000000000..416f7a411 --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp @@ -0,0 +1,48 @@ +////////////////////////////////////////////////////////////////////////////// +// +// This file is the adaptation for Interprocess of boost/detail/bad_weak_ptr.hpp +// +// (C) Copyright Peter Dimov and Multi Media Ltd. 2001, 2002, 2003 +// (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_BAD_WEAK_PTR_HPP_INCLUDED +#define BOOST_INTERPROCESS_BAD_WEAK_PTR_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#ifndef BOOST_NO_EXCEPTIONS +#include +#endif + +namespace boost{ +namespace interprocess{ + +class bad_weak_ptr + : public std::exception +{ + public: + + virtual char const * what() const throw() + { return "boost::interprocess::bad_weak_ptr"; } +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_BAD_WEAK_PTR_HPP_INCLUDED diff --git a/libraries/boost/boost/interprocess/smart_ptr/detail/shared_count.hpp b/libraries/boost/boost/interprocess/smart_ptr/detail/shared_count.hpp new file mode 100644 index 000000000..61cf9ea19 --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/detail/shared_count.hpp @@ -0,0 +1,343 @@ +////////////////////////////////////////////////////////////////////////////// +// +// This file is the adaptation for Interprocess of boost/detail/shared_count.hpp +// +// (C) Copyright Peter Dimov and Multi Media Ltd. 2001, 2002, 2003 +// (C) Copyright Peter Dimov 2004-2005 +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED +#define BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include //std::less +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +template +class weak_count; + +template +class shared_count +{ + public: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + + private: + typedef sp_counted_impl_pd counted_impl; + + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type counted_impl_ptr; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type counted_base_ptr; + + typedef boost::container::allocator_traits vallocator_traits; + + typedef typename vallocator_traits::template + portable_rebind_alloc::type counted_impl_allocator; + + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_deleter_pointer; + + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_allocator_pointer; + + pointer m_px; + counted_impl_ptr m_pi; + + template + friend class weak_count; + + template + friend class shared_count; + + public: + + shared_count() + : m_px(0), m_pi(0) // nothrow + {} + + template + shared_count(const shared_count &other_shared_count, const Ptr &p) + : m_px(p), m_pi(other_shared_count.m_pi) + {} + + template + shared_count(const Ptr &p, const VoidAllocator &a, Deleter d) + : m_px(p), m_pi(0) + { + BOOST_TRY{ + if(p){ + counted_impl_allocator alloc(a); + m_pi = alloc.allocate(1); + //Anti-exception deallocator + scoped_ptr > + deallocator(m_pi, alloc); + //It's more correct to use VoidAllocator::construct but + //this needs copy constructor and we don't like it + ::new(ipcdetail::to_raw_pointer(m_pi), boost_container_new_t())counted_impl(p, a, d); + deallocator.release(); + } + } + BOOST_CATCH (...){ + d(p); // delete p + BOOST_RETHROW + } + BOOST_CATCH_END + } + + ~shared_count() // nothrow + { + if(m_pi) + m_pi->release(); + } + + shared_count(shared_count const & r) + : m_px(r.m_px), m_pi(r.m_pi) // nothrow + { if( m_pi != 0 ) m_pi->add_ref_copy(); } + + //this is a test + template + explicit shared_count(shared_count const & r) + : m_px(r.m_px), m_pi(r.m_pi) // nothrow + { if( m_pi != 0 ) m_pi->add_ref_copy(); } + + //this is a test + template + explicit shared_count(const pointer & ptr, shared_count const & r) + : m_px(ptr), m_pi(r.m_pi) // nothrow + { if( m_pi != 0 ) m_pi->add_ref_copy(); } + +/* + explicit shared_count(weak_count const & r) + // throws bad_weak_ptr when r.use_count() == 0 + : m_pi( r.m_pi ) + { + if( m_pi == 0 || !m_pi->add_ref_lock() ){ + boost::throw_exception( boost::interprocess::bad_weak_ptr() ); + } + } +*/ + template + explicit shared_count(weak_count const & r) + // throws bad_weak_ptr when r.use_count() == 0 + : m_px(r.m_px), m_pi( r.m_pi ) + { + if( m_pi == 0 || !m_pi->add_ref_lock() ){ + throw( boost::interprocess::bad_weak_ptr() ); + } + } + + const pointer &to_raw_pointer() const + { return m_px; } + + pointer &to_raw_pointer() + { return m_px; } + + shared_count & operator= (shared_count const & r) // nothrow + { + m_px = r.m_px; + counted_impl_ptr tmp = r.m_pi; + if( tmp != m_pi ){ + if(tmp != 0) tmp->add_ref_copy(); + if(m_pi != 0) m_pi->release(); + m_pi = tmp; + } + return *this; + } + + template + shared_count & operator= (shared_count const & r) // nothrow + { + m_px = r.m_px; + counted_impl_ptr tmp = r.m_pi; + if( tmp != m_pi ){ + if(tmp != 0) tmp->add_ref_copy(); + if(m_pi != 0) m_pi->release(); + m_pi = tmp; + } + return *this; + } + + void swap(shared_count & r) // nothrow + { ::boost::adl_move_swap(m_px, r.m_px); ::boost::adl_move_swap(m_pi, r.m_pi); } + + long use_count() const // nothrow + { return m_pi != 0? m_pi->use_count(): 0; } + + bool unique() const // nothrow + { return use_count() == 1; } + + const_deleter_pointer get_deleter() const + { return m_pi ? m_pi->get_deleter() : 0; } + +// const_allocator_pointer get_allocator() const +// { return m_pi ? m_pi->get_allocator() : 0; } + + template + bool internal_equal (shared_count const & other) const + { return this->m_pi == other.m_pi; } + + template + bool internal_less (shared_count const & other) const + { return std::less()(this->m_pi, other.m_pi); } +}; + +template inline +bool operator==(shared_count const & a, shared_count const & b) +{ return a.internal_equal(b); } + +template inline +bool operator<(shared_count const & a, shared_count const & b) +{ return a.internal_less(b); } + + +template +class weak_count +{ + public: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + + private: + + typedef sp_counted_impl_pd counted_impl; + + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type counted_impl_ptr; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type counted_base_ptr; + + pointer m_px; + counted_impl_ptr m_pi; + + template + friend class weak_count; + + template + friend class shared_count; + + public: + + weak_count(): m_px(0), m_pi(0) // nothrow + {} + + template + explicit weak_count(shared_count const & r) + : m_px(r.m_px), m_pi(r.m_pi) // nothrow + { if(m_pi != 0) m_pi->weak_add_ref(); } + + weak_count(weak_count const & r) + : m_px(r.m_px), m_pi(r.m_pi) // nothrow + { if(m_pi != 0) m_pi->weak_add_ref(); } + + template + weak_count(weak_count const & r) + : m_px(r.m_px), m_pi(r.m_pi) // nothrow + { if(m_pi != 0) m_pi->weak_add_ref(); } + + ~weak_count() // nothrow + { if(m_pi != 0) m_pi->weak_release(); } + + template + weak_count & operator= (shared_count const & r) // nothrow + { + m_px = r.m_px; + counted_impl_ptr tmp = r.m_pi; + if(tmp != 0) tmp->weak_add_ref(); + if(m_pi != 0) m_pi->weak_release(); + m_pi = tmp; + return *this; + } + + weak_count & operator= (weak_count const & r) // nothrow + { + m_px = r.m_px; + counted_impl_ptr tmp = r.m_pi; + if(tmp != 0) tmp->weak_add_ref(); + if(m_pi != 0) m_pi->weak_release(); + m_pi = tmp; + return *this; + } + + void set_pointer(const pointer &ptr) + { m_px = ptr; } + + template + weak_count & operator= (weak_count const& r) // nothrow + { + counted_impl_ptr tmp = r.m_pi; + if(tmp != 0) tmp->weak_add_ref(); + if(m_pi != 0) m_pi->weak_release(); + m_pi = tmp; + return *this; + } + + void swap(weak_count & r) // nothrow + { ::boost::adl_move_swap(m_px, r.m_px); ::boost::adl_move_swap(m_pi, r.m_pi); } + + long use_count() const // nothrow + { return m_pi != 0? m_pi->use_count() : 0; } + + template + bool internal_equal (weak_count const & other) const + { return this->m_pi == other.m_pi; } + + template + bool internal_less (weak_count const & other) const + { return std::less()(this->m_pi, other.m_pi); } +}; + +template inline +bool operator==(weak_count const & a, weak_count const & b) +{ return a.internal_equal(b); } + +template inline +bool operator<(weak_count const & a, weak_count const & b) +{ return a.internal_less(b); } + +} // namespace ipcdetail +} // namespace interprocess +} // namespace boost + + +#include + + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED diff --git a/libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp b/libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp new file mode 100644 index 000000000..3b6a0876f --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2012. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED +#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +# include + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED + diff --git a/libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp b/libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp new file mode 100644 index 000000000..50392741d --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp @@ -0,0 +1,94 @@ +#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_ATOMIC_HPP_INCLUDED +#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_ATOMIC_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// Copyright 2007-2012 Ion Gaztanaga +// +// 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) +// +// +// Lock-free algorithm by Alexander Terekhov +// +// Thanks to Ben Hitchings for the #weak + (#shared != 0) +// formulation +// + +#include +#include + +#include +#include + +namespace boost { + +namespace interprocess { + +namespace ipcdetail { + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + boost::uint32_t use_count_; // #shared + boost::uint32_t weak_count_; // #weak + (#shared != 0) + +public: + + sp_counted_base(): use_count_( 1 ), weak_count_( 1 ) + {} + + ~sp_counted_base() // nothrow + {} + + void add_ref_copy() + { + ipcdetail::atomic_inc32( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + for( ;; ) + { + boost::uint32_t tmp = static_cast< boost::uint32_t const volatile& >( use_count_ ); + if( tmp == 0 ) return false; + if( ipcdetail::atomic_cas32( &use_count_, tmp + 1, tmp ) == tmp ) + return true; + } + } + + bool ref_release() // nothrow + { return 1 == ipcdetail::atomic_dec32( &use_count_ ); } + + void weak_add_ref() // nothrow + { ipcdetail::atomic_inc32( &weak_count_ ); } + + bool weak_release() // nothrow + { return 1 == ipcdetail::atomic_dec32( &weak_count_ ); } + + long use_count() const // nothrow + { return (long)static_cast( use_count_ ); } +}; + +} // namespace ipcdetail + +} // namespace interprocess + +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_ATOMIC_HPP_INCLUDED diff --git a/libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp b/libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp new file mode 100644 index 000000000..a025309bd --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp @@ -0,0 +1,159 @@ +#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED +#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +// +// This file is the adaptation for shared memory memory mapped +// files of boost/detail/sp_counted_impl.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// Copyright 2006 Ion Gaztanaga +// +// 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) +// + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace boost { + +namespace interprocess { + +namespace ipcdetail { + +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an object using a STL allocator. +template +struct scoped_ptr_dealloc_functor +{ + typedef typename Allocator::pointer pointer; + typedef ipcdetail::integral_constant::value> alloc_version; + typedef ipcdetail::integral_constant allocator_v1; + typedef ipcdetail::integral_constant allocator_v2; + + private: + void priv_deallocate(const typename Allocator::pointer &p, allocator_v1) + { m_alloc.deallocate(p, 1); } + + void priv_deallocate(const typename Allocator::pointer &p, allocator_v2) + { m_alloc.deallocate_one(p); } + + public: + Allocator& m_alloc; + + scoped_ptr_dealloc_functor(Allocator& a) + : m_alloc(a) {} + + void operator()(pointer ptr) + { if (ptr) priv_deallocate(ptr, alloc_version()); } +}; + + + +template +class sp_counted_impl_pd + : public sp_counted_base + , boost::container::allocator_traits::template + portable_rebind_alloc< sp_counted_impl_pd >::type + , D // copy constructor must not throw +{ + private: + typedef sp_counted_impl_pd this_type; + typedef typename boost::container:: + allocator_traits::template + portable_rebind_alloc + < this_type >::type this_allocator; + typedef typename boost::container:: + allocator_traits::template + portable_rebind_alloc + < const this_type >::type const_this_allocator; + typedef typename this_allocator::pointer this_pointer; + typedef typename boost::intrusive:: + pointer_traits this_pointer_traits; + + sp_counted_impl_pd( sp_counted_impl_pd const & ); + sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & ); + + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_deleter_pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_allocator_pointer; + + typedef typename D::pointer pointer; + pointer m_ptr; + + public: + // pre: d(p) must not throw + template + sp_counted_impl_pd(const Ptr & p, const A &a, const D &d ) + : this_allocator(a), D(d), m_ptr(p) + {} + + const_deleter_pointer get_deleter() const + { return const_deleter_pointer(&static_cast(*this)); } + + const_allocator_pointer get_allocator() const + { return const_allocator_pointer(&static_cast(*this)); } + + void dispose() // nothrow + { static_cast(*this)(m_ptr); } + + void destroy() // nothrow + { + //Self destruction, so move the allocator + this_allocator a_copy(::boost::move(static_cast(*this))); + BOOST_ASSERT(a_copy == *this); + this_pointer this_ptr(this_pointer_traits::pointer_to(*this)); + //Do it now! + scoped_ptr< this_type, scoped_ptr_dealloc_functor > + deleter_ptr(this_ptr, a_copy); + typedef typename this_allocator::value_type value_type; + ipcdetail::to_raw_pointer(this_ptr)->~value_type(); + } + + void release() // nothrow + { + if(this->ref_release()){ + this->dispose(); + this->weak_release(); + } + } + + void weak_release() // nothrow + { + if(sp_counted_base::weak_release()){ + this->destroy(); + } + } +}; + + +} // namespace ipcdetail + +} // namespace interprocess + +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED diff --git a/libraries/boost/boost/interprocess/smart_ptr/enable_shared_from_this.hpp b/libraries/boost/boost/interprocess/smart_ptr/enable_shared_from_this.hpp new file mode 100644 index 000000000..188b68d67 --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/enable_shared_from_this.hpp @@ -0,0 +1,87 @@ +////////////////////////////////////////////////////////////////////////////// +// +// This file is the adaptation for Interprocess of boost/enable_shared_from_this.hpp +// +// (C) Copyright Peter Dimov 2002 +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED +#define BOOST_INTERPROCESS_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include + +//!\file +//!Describes an utility to form a shared pointer from this + +namespace boost{ +namespace interprocess{ + +//!This class is used as a base class that allows a shared_ptr to the current +//!object to be obtained from within a member function. +//!enable_shared_from_this defines two member functions called shared_from_this +//!that return a shared_ptr and shared_ptr, depending on constness, to this. +template +class enable_shared_from_this +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + protected: + enable_shared_from_this() + {} + + enable_shared_from_this(enable_shared_from_this const &) + {} + + enable_shared_from_this & operator=(enable_shared_from_this const &) + { return *this; } + + ~enable_shared_from_this() + {} + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + shared_ptr shared_from_this() + { + shared_ptr p(_internal_weak_this); + BOOST_ASSERT(ipcdetail::to_raw_pointer(p.get()) == this); + return p; + } + + shared_ptr shared_from_this() const + { + shared_ptr p(_internal_weak_this); + BOOST_ASSERT(ipcdetail::to_raw_pointer(p.get()) == this); + return p; + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef T element_type; + mutable weak_ptr _internal_weak_this; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED + diff --git a/libraries/boost/boost/interprocess/smart_ptr/intrusive_ptr.hpp b/libraries/boost/boost/interprocess/smart_ptr/intrusive_ptr.hpp new file mode 100644 index 000000000..e2cf45fdb --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/intrusive_ptr.hpp @@ -0,0 +1,305 @@ +////////////////////////////////////////////////////////////////////////////// +// +// This file is the adaptation for Interprocess of boost/intrusive_ptr.hpp +// +// (C) Copyright Peter Dimov 2001, 2002 +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_INTRUSIVE_PTR_HPP_INCLUDED +#define BOOST_INTERPROCESS_INTRUSIVE_PTR_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +//!\file +//!Describes an intrusive ownership pointer. + +#include +#include + +#include +#include +#include +#include + +#include // for std::basic_ostream + +#include //std::less + +namespace boost { +namespace interprocess { + +//!The intrusive_ptr class template stores a pointer to an object +//!with an embedded reference count. intrusive_ptr is parameterized on +//!T (the type of the object pointed to) and VoidPointer(a void pointer type +//!that defines the type of pointer that intrusive_ptr will store). +//!intrusive_ptr defines a class with a T* member whereas +//!intrusive_ptr > defines a class with a offset_ptr member. +//!Relies on unqualified calls to: +//! +//! void intrusive_ptr_add_ref(T * p); +//! void intrusive_ptr_release(T * p); +//! +//! with (p != 0) +//! +//!The object is responsible for destroying itself. +template +class intrusive_ptr +{ + public: + //!Provides the type of the internal stored pointer. + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + //!Provides the type of the stored pointer. + typedef T element_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef VoidPointer VP; + typedef intrusive_ptr this_type; + typedef pointer this_type::*unspecified_bool_type; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. Initializes internal pointer to 0. + //!Does not throw + intrusive_ptr(): m_ptr(0) + {} + + //!Constructor. Copies pointer and if "p" is not zero and + //!"add_ref" is true calls intrusive_ptr_add_ref(to_raw_pointer(p)). + //!Does not throw + intrusive_ptr(const pointer &p, bool add_ref = true): m_ptr(p) + { + if(m_ptr != 0 && add_ref) intrusive_ptr_add_ref(ipcdetail::to_raw_pointer(m_ptr)); + } + + //!Copy constructor. Copies the internal pointer and if "p" is not + //!zero calls intrusive_ptr_add_ref(to_raw_pointer(p)). Does not throw + intrusive_ptr(intrusive_ptr const & rhs) + : m_ptr(rhs.m_ptr) + { + if(m_ptr != 0) intrusive_ptr_add_ref(ipcdetail::to_raw_pointer(m_ptr)); + } + + //!Constructor from related. Copies the internal pointer and if "p" is not + //!zero calls intrusive_ptr_add_ref(to_raw_pointer(p)). Does not throw + template intrusive_ptr + (intrusive_ptr const & rhs) + : m_ptr(rhs.get()) + { + if(m_ptr != 0) intrusive_ptr_add_ref(ipcdetail::to_raw_pointer(m_ptr)); + } + + //!Destructor. If internal pointer is not 0, calls + //!intrusive_ptr_release(to_raw_pointer(m_ptr)). Does not throw + ~intrusive_ptr() + { + if(m_ptr != 0) intrusive_ptr_release(ipcdetail::to_raw_pointer(m_ptr)); + } + + //!Assignment operator. Equivalent to intrusive_ptr(r).swap(*this). + //!Does not throw + intrusive_ptr & operator=(intrusive_ptr const & rhs) + { + this_type(rhs).swap(*this); + return *this; + } + + //!Assignment from related. Equivalent to intrusive_ptr(r).swap(*this). + //!Does not throw + template intrusive_ptr & operator= + (intrusive_ptr const & rhs) + { + this_type(rhs).swap(*this); + return *this; + } + + //!Assignment from pointer. Equivalent to intrusive_ptr(r).swap(*this). + //!Does not throw + intrusive_ptr & operator=(pointer rhs) + { + this_type(rhs).swap(*this); + return *this; + } + + //!Returns a reference to the internal pointer. + //!Does not throw + pointer &get() + { return m_ptr; } + + //!Returns a reference to the internal pointer. + //!Does not throw + const pointer &get() const + { return m_ptr; } + + //!Returns *get(). + //!Does not throw + T & operator*() const + { return *m_ptr; } + + //!Returns *get(). + //!Does not throw + const pointer &operator->() const + { return m_ptr; } + + //!Returns get(). + //!Does not throw + pointer &operator->() + { return m_ptr; } + + //!Conversion to boolean. + //!Does not throw + operator unspecified_bool_type () const + { return m_ptr == 0? 0: &this_type::m_ptr; } + + //!Not operator. + //!Does not throw + bool operator! () const + { return m_ptr == 0; } + + //!Exchanges the contents of the two smart pointers. + //!Does not throw + void swap(intrusive_ptr & rhs) + { ::boost::adl_move_swap(m_ptr, rhs.m_ptr); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + pointer m_ptr; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!Returns a.get() == b.get(). +//!Does not throw +template inline +bool operator==(intrusive_ptr const & a, + intrusive_ptr const & b) +{ return a.get() == b.get(); } + +//!Returns a.get() != b.get(). +//!Does not throw +template inline +bool operator!=(intrusive_ptr const & a, + intrusive_ptr const & b) +{ return a.get() != b.get(); } + +//!Returns a.get() == b. +//!Does not throw +template inline +bool operator==(intrusive_ptr const & a, + const typename intrusive_ptr::pointer &b) +{ return a.get() == b; } + +//!Returns a.get() != b. +//!Does not throw +template inline +bool operator!=(intrusive_ptr const & a, + const typename intrusive_ptr::pointer &b) +{ return a.get() != b; } + +//!Returns a == b.get(). +//!Does not throw +template inline +bool operator==(const typename intrusive_ptr::pointer &a, + intrusive_ptr const & b) +{ return a == b.get(); } + +//!Returns a != b.get(). +//!Does not throw +template inline +bool operator!=(const typename intrusive_ptr::pointer &a, + intrusive_ptr const & b) +{ return a != b.get(); } + +//!Returns a.get() < b.get(). +//!Does not throw +template inline +bool operator<(intrusive_ptr const & a, + intrusive_ptr const & b) +{ + return std::less::pointer>() + (a.get(), b.get()); +} + +//!Exchanges the contents of the two intrusive_ptrs. +//!Does not throw +template inline +void swap(intrusive_ptr & lhs, + intrusive_ptr & rhs) +{ lhs.swap(rhs); } + +// operator<< +template +inline std::basic_ostream & operator<< + (std::basic_ostream & os, intrusive_ptr const & p) +{ os << p.get(); return os; } + +//!Returns p.get(). +//!Does not throw +template +inline typename boost::interprocess::intrusive_ptr::pointer + to_raw_pointer(intrusive_ptr p) +{ return p.get(); } + +/*Emulates static cast operator. Does not throw*/ +/* +template +inline boost::interprocess::intrusive_ptr static_pointer_cast + (boost::interprocess::intrusive_ptr const & p) +{ return do_static_cast(p.get()); } +*/ +/*Emulates const cast operator. Does not throw*/ +/* +template +inline boost::interprocess::intrusive_ptr const_pointer_cast + (boost::interprocess::intrusive_ptr const & p) +{ return do_const_cast(p.get()); } +*/ + +/*Emulates dynamic cast operator. Does not throw*/ +/* +template +inline boost::interprocess::intrusive_ptr dynamic_pointer_cast + (boost::interprocess::intrusive_ptr const & p) +{ return do_dynamic_cast(p.get()); } +*/ + +/*Emulates reinterpret cast operator. Does not throw*/ +/* +template +inline boost::interprocess::intrusive_ptrreinterpret_pointer_cast + (boost::interprocess::intrusive_ptr const & p) +{ return do_reinterpret_cast(p.get()); } +*/ + +} // namespace interprocess + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#if defined(_MSC_VER) && (_MSC_VER < 1400) +//!Returns p.get(). +//!Does not throw +template +inline T *to_raw_pointer(boost::interprocess::intrusive_ptr p) +{ return p.get(); } +#endif + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_INTRUSIVE_PTR_HPP_INCLUDED diff --git a/libraries/boost/boost/interprocess/smart_ptr/scoped_ptr.hpp b/libraries/boost/boost/interprocess/smart_ptr/scoped_ptr.hpp new file mode 100644 index 000000000..5506040b6 --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/scoped_ptr.hpp @@ -0,0 +1,176 @@ +////////////////////////////////////////////////////////////////////////////// +// +// This file is the adaptation for Interprocess of boost/scoped_ptr.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// (C) Copyright Peter Dimov 2001, 2002 +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SCOPED_PTR_HPP_INCLUDED +#define BOOST_INTERPROCESS_SCOPED_PTR_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes the smart pointer scoped_ptr + +namespace boost { +namespace interprocess { + +//!scoped_ptr stores a pointer to a dynamically allocated object. +//!The object pointed to is guaranteed to be deleted, either on destruction +//!of the scoped_ptr, or via an explicit reset. The user can avoid this +//!deletion using release(). +//!scoped_ptr is parameterized on T (the type of the object pointed to) and +//!Deleter (the functor to be executed to delete the internal pointer). +//!The internal pointer will be of the same pointer type as typename +//!Deleter::pointer type (that is, if typename Deleter::pointer is +//!offset_ptr, the internal pointer will be offset_ptr). +template +class scoped_ptr + : private Deleter +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + scoped_ptr(scoped_ptr const &); + scoped_ptr & operator=(scoped_ptr const &); + + typedef scoped_ptr this_type; + typedef typename ipcdetail::add_reference::type reference; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + + typedef T element_type; + typedef Deleter deleter_type; + typedef typename ipcdetail::pointer_type::type pointer; + + //!Constructs a scoped_ptr, storing a copy of p(which can be 0) and d. + //!Does not throw. + explicit scoped_ptr(const pointer &p = 0, const Deleter &d = Deleter()) + : Deleter(d), m_ptr(p) // throws if pointer/Deleter copy ctor throws + {} + + //!If the stored pointer is not 0, destroys the object pointed to by the stored pointer. + //!calling the operator() of the stored deleter. Never throws + ~scoped_ptr() + { + if(m_ptr){ + Deleter &del = static_cast(*this); + del(m_ptr); + } + } + + //!Deletes the object pointed to by the stored pointer and then + //!stores a copy of p. Never throws + void reset(const pointer &p = 0) // never throws + { BOOST_ASSERT(p == 0 || p != m_ptr); this_type(p).swap(*this); } + + //!Deletes the object pointed to by the stored pointer and then + //!stores a copy of p and a copy of d. + void reset(const pointer &p, const Deleter &d) // never throws + { BOOST_ASSERT(p == 0 || p != m_ptr); this_type(p, d).swap(*this); } + + //!Assigns internal pointer as 0 and returns previous pointer. This will + //!avoid deletion on destructor + pointer release() + { pointer tmp(m_ptr); m_ptr = 0; return tmp; } + + //!Returns a reference to the object pointed to by the stored pointer. + //!Never throws. + reference operator*() const + { BOOST_ASSERT(m_ptr != 0); return *m_ptr; } + + //!Returns the internal stored pointer. + //!Never throws. + pointer &operator->() + { BOOST_ASSERT(m_ptr != 0); return m_ptr; } + + //!Returns the internal stored pointer. + //!Never throws. + const pointer &operator->() const + { BOOST_ASSERT(m_ptr != 0); return m_ptr; } + + //!Returns the stored pointer. + //!Never throws. + pointer & get() + { return m_ptr; } + + //!Returns the stored pointer. + //!Never throws. + const pointer & get() const + { return m_ptr; } + + typedef pointer this_type::*unspecified_bool_type; + + //!Conversion to bool + //!Never throws + operator unspecified_bool_type() const + { return m_ptr == 0? 0: &this_type::m_ptr; } + + //!Returns true if the stored pointer is 0. + //!Never throws. + bool operator! () const // never throws + { return m_ptr == 0; } + + //!Exchanges the internal pointer and deleter with other scoped_ptr + //!Never throws. + void swap(scoped_ptr & b) // never throws + { + ::boost::adl_move_swap(static_cast(*this), static_cast(b)); + ::boost::adl_move_swap(m_ptr, b.m_ptr); + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + pointer m_ptr; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!Exchanges the internal pointer and deleter with other scoped_ptr +//!Never throws. +template inline +void swap(scoped_ptr & a, scoped_ptr & b) +{ a.swap(b); } + +//!Returns a copy of the stored pointer +//!Never throws +template inline +typename scoped_ptr::pointer to_raw_pointer(scoped_ptr const & p) +{ return p.get(); } + +} // namespace interprocess + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#if defined(_MSC_VER) && (_MSC_VER < 1400) +template inline +T *to_raw_pointer(boost::interprocess::scoped_ptr const & p) +{ return p.get(); } +#endif + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_SCOPED_PTR_HPP_INCLUDED diff --git a/libraries/boost/boost/interprocess/smart_ptr/shared_ptr.hpp b/libraries/boost/boost/interprocess/smart_ptr/shared_ptr.hpp new file mode 100644 index 000000000..18e222262 --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/shared_ptr.hpp @@ -0,0 +1,428 @@ +////////////////////////////////////////////////////////////////////////////// +// +// This file is the adaptation for Interprocess of boost/shared_ptr.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// (C) Copyright Peter Dimov 2001, 2002, 2003 +// (C) Copyright Ion Gaztanaga 2006-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED +#define BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // for std::basic_ostream + +//!\file +//!Describes the smart pointer shared_ptr + +namespace boost{ +namespace interprocess{ + +template class weak_ptr; +template class enable_shared_from_this; + +namespace ipcdetail{ + +template +inline void sp_enable_shared_from_this + (shared_count const & pn + ,enable_shared_from_this *pe + ,T *ptr) + +{ + (void)ptr; + if(pe != 0){ + pe->_internal_weak_this._internal_assign(pn); + } +} + +template +inline void sp_enable_shared_from_this(shared_count const &, ...) +{} + +} // namespace ipcdetail + +//!shared_ptr stores a pointer to a dynamically allocated object. +//!The object pointed to is guaranteed to be deleted when the last shared_ptr pointing to +//!it is destroyed or reset. +//! +//!shared_ptr is parameterized on +//!T (the type of the object pointed to), VoidAllocator (the void allocator to be used +//!to allocate the auxiliary data) and Deleter (the deleter whose +//!operator() will be used to delete the object. +//! +//!The internal pointer will be of the same pointer type as typename +//!VoidAllocator::pointer type (that is, if typename VoidAllocator::pointer is +//!offset_ptr, the internal pointer will be offset_ptr). +//! +//!Because the implementation uses reference counting, cycles of shared_ptr +//!instances will not be reclaimed. For example, if main() holds a +//!shared_ptr to A, which directly or indirectly holds a shared_ptr back +//!to A, A's use count will be 2. Destruction of the original shared_ptr +//!will leave A dangling with a use count of 1. +//!Use weak_ptr to "break cycles." +template +class shared_ptr +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef shared_ptr this_type; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + + typedef T element_type; + typedef T value_type; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_deleter_pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_allocator_pointer; + + BOOST_COPYABLE_AND_MOVABLE(shared_ptr) + public: + + //!Constructs an empty shared_ptr. + //!Use_count() == 0 && get()== 0. + shared_ptr() + : m_pn() // never throws + {} + + //!Constructs a shared_ptr that owns the pointer p. Auxiliary data will be allocated + //!with a copy of a and the object will be deleted with a copy of d. + //!Requirements: Deleter and A's copy constructor must not throw. + explicit shared_ptr(const pointer&p, const VoidAllocator &a = VoidAllocator(), const Deleter &d = Deleter()) + : m_pn(p, a, d) + { + //Check that the pointer passed is of the same type that + //the pointer the allocator defines or it's a raw pointer + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type ParameterPointer; + + BOOST_STATIC_ASSERT((ipcdetail::is_same::value) || + (ipcdetail::is_pointer::value)); + ipcdetail::sp_enable_shared_from_this( m_pn, ipcdetail::to_raw_pointer(p), ipcdetail::to_raw_pointer(p) ); + } + + //!Copy constructs a shared_ptr. If r is empty, constructs an empty shared_ptr. Otherwise, constructs + //!a shared_ptr that shares ownership with r. Never throws. + shared_ptr(const shared_ptr &r) + : m_pn(r.m_pn) // never throws + {} + + //!Constructs a shared_ptr that shares ownership with other and stores p. + //!Postconditions: get() == p && use_count() == r.use_count(). + //!Throws: nothing. + shared_ptr(const shared_ptr &other, const pointer &p) + : m_pn(other.m_pn, p) + {} + + //!If r is empty, constructs an empty shared_ptr. Otherwise, constructs + //!a shared_ptr that shares ownership with r. Never throws. + template + shared_ptr(shared_ptr const & r) + : m_pn(r.m_pn) // never throws + {} + + //!Constructs a shared_ptr that shares ownership with r and stores + //!a copy of the pointer stored in r. + template + explicit shared_ptr(weak_ptr const & r) + : m_pn(r.m_pn) // may throw + {} + + //!Move-Constructs a shared_ptr that takes ownership of other resource and + //!other is put in default-constructed state. + //!Throws: nothing. + explicit shared_ptr(BOOST_RV_REF(shared_ptr) other) + : m_pn() + { this->swap(other); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + template + shared_ptr(shared_ptr const & r, ipcdetail::static_cast_tag) + : m_pn( pointer(static_cast(ipcdetail::to_raw_pointer(r.m_pn.to_raw_pointer()))) + , r.m_pn) + {} + + template + shared_ptr(shared_ptr const & r, ipcdetail::const_cast_tag) + : m_pn( pointer(const_cast(ipcdetail::to_raw_pointer(r.m_pn.to_raw_pointer()))) + , r.m_pn) + {} + + template + shared_ptr(shared_ptr const & r, ipcdetail::dynamic_cast_tag) + : m_pn( pointer(dynamic_cast(ipcdetail::to_raw_pointer(r.m_pn.to_raw_pointer()))) + , r.m_pn) + { + if(!m_pn.to_raw_pointer()){ // need to allocate new counter -- the cast failed + m_pn = ipcdetail::shared_count(); + } + } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Equivalent to shared_ptr(r).swap(*this). + //!Never throws + template + shared_ptr & operator=(shared_ptr const & r) + { + m_pn = r.m_pn; // shared_count::op= doesn't throw + return *this; + } + + //!Equivalent to shared_ptr(r).swap(*this). + //!Never throws + shared_ptr & operator=(BOOST_COPY_ASSIGN_REF(shared_ptr) r) + { + m_pn = r.m_pn; // shared_count::op= doesn't throw + return *this; + } + + //!Move-assignment. Equivalent to shared_ptr(other).swap(*this). + //!Never throws + shared_ptr & operator=(BOOST_RV_REF(shared_ptr) other) // never throws + { + this_type(other).swap(*this); + return *this; + } + + //!This is equivalent to: + //!this_type().swap(*this); + void reset() + { + this_type().swap(*this); + } + + //!This is equivalent to: + //!this_type(p, a, d).swap(*this); + template + void reset(const Pointer &p, const VoidAllocator &a = VoidAllocator(), const Deleter &d = Deleter()) + { + //Check that the pointer passed is of the same type that + //the pointer the allocator defines or it's a raw pointer + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type ParameterPointer; + BOOST_STATIC_ASSERT((ipcdetail::is_same::value) || + (ipcdetail::is_pointer::value)); + this_type(p, a, d).swap(*this); + } + + template + void reset(shared_ptr const & r, const pointer &p) + { + this_type(r, p).swap(*this); + } + + //!Returns a reference to the + //!pointed type + reference operator* () const // never throws + { BOOST_ASSERT(m_pn.to_raw_pointer() != 0); return *m_pn.to_raw_pointer(); } + + //!Returns the pointer pointing + //!to the owned object + pointer operator-> () const // never throws + { BOOST_ASSERT(m_pn.to_raw_pointer() != 0); return m_pn.to_raw_pointer(); } + + //!Returns the pointer pointing + //!to the owned object + pointer get() const // never throws + { return m_pn.to_raw_pointer(); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + // implicit conversion to "bool" + void unspecified_bool_type_func() const {} + typedef void (this_type::*unspecified_bool_type)() const; + + operator unspecified_bool_type() const // never throws + { return !m_pn.to_raw_pointer() ? 0 : &this_type::unspecified_bool_type_func; } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Not operator. + //!Returns true if this->get() != 0, false otherwise + bool operator! () const // never throws + { return !m_pn.to_raw_pointer(); } + + //!Returns use_count() == 1. + //!unique() might be faster than use_count() + bool unique() const // never throws + { return m_pn.unique(); } + + //!Returns the number of shared_ptr objects, *this included, + //!that share ownership with *this, or an unspecified nonnegative + //!value when *this is empty. + //!use_count() is not necessarily efficient. Use only for + //!debugging and testing purposes, not for production code. + long use_count() const // never throws + { return m_pn.use_count(); } + + //!Exchanges the contents of the two + //!smart pointers. + void swap(shared_ptr & other) // never throws + { m_pn.swap(other.m_pn); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + template + bool _internal_less(shared_ptr const & rhs) const + { return m_pn < rhs.m_pn; } + + const_deleter_pointer get_deleter() const + { return m_pn.get_deleter(); } + +// const_allocator_pointer get_allocator() const +// { return m_pn.get_allocator(); } + + private: + + template friend class shared_ptr; + template friend class weak_ptr; + + ipcdetail::shared_count m_pn; // reference counter + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; // shared_ptr + +template inline +bool operator==(shared_ptr const & a, shared_ptr const & b) +{ return a.get() == b.get(); } + +template inline +bool operator!=(shared_ptr const & a, shared_ptr const & b) +{ return a.get() != b.get(); } + +template inline +bool operator<(shared_ptr const & a, shared_ptr const & b) +{ return a._internal_less(b); } + +template inline +void swap(shared_ptr & a, shared_ptr & b) +{ a.swap(b); } + +template inline +shared_ptr static_pointer_cast(shared_ptr const & r) +{ return shared_ptr(r, ipcdetail::static_cast_tag()); } + +template inline +shared_ptr const_pointer_cast(shared_ptr const & r) +{ return shared_ptr(r, ipcdetail::const_cast_tag()); } + +template inline +shared_ptr dynamic_pointer_cast(shared_ptr const & r) +{ return shared_ptr(r, ipcdetail::dynamic_cast_tag()); } + +// to_raw_pointer() enables boost::mem_fn to recognize shared_ptr +template inline +T * to_raw_pointer(shared_ptr const & p) +{ return p.get(); } + +// operator<< +template inline +std::basic_ostream & operator<< + (std::basic_ostream & os, shared_ptr const & p) +{ os << p.get(); return os; } + +//!Returns the type of a shared pointer +//!of type T with the allocator boost::interprocess::allocator allocator +//!and boost::interprocess::deleter deleter +//!that can be constructed in the given managed segment type. +template +struct managed_shared_ptr +{ + typedef typename ManagedMemory::template allocator::type void_allocator; + typedef typename ManagedMemory::template deleter::type deleter; + typedef shared_ptr< T, void_allocator, deleter> type; +}; + +//!Returns an instance of a shared pointer constructed +//!with the default allocator and deleter from a pointer +//!of type T that has been allocated in the passed managed segment +template +inline typename managed_shared_ptr::type + make_managed_shared_ptr(T *constructed_object, ManagedMemory &managed_memory) +{ + return typename managed_shared_ptr::type + ( constructed_object + , managed_memory.template get_allocator() + , managed_memory.template get_deleter() + ); +} + +//!Returns an instance of a shared pointer constructed +//!with the default allocator and deleter from a pointer +//!of type T that has been allocated in the passed managed segment. +//!Does not throw, return null shared pointer in error. +template +inline typename managed_shared_ptr::type + make_managed_shared_ptr(T *constructed_object, ManagedMemory &managed_memory, const std::nothrow_t &) +{ + try{ + return typename managed_shared_ptr::type + ( constructed_object + , managed_memory.template get_allocator() + , managed_memory.template get_deleter() + ); + } + catch(...){ + return typename managed_shared_ptr::type(); + } +} + + +} // namespace interprocess + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#if defined(_MSC_VER) && (_MSC_VER < 1400) +// to_raw_pointer() enables boost::mem_fn to recognize shared_ptr +template inline +T * to_raw_pointer(boost::interprocess::shared_ptr const & p) +{ return p.get(); } +#endif + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED diff --git a/libraries/boost/boost/interprocess/smart_ptr/unique_ptr.hpp b/libraries/boost/boost/interprocess/smart_ptr/unique_ptr.hpp new file mode 100644 index 000000000..919b91d71 --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -0,0 +1,63 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_UNIQUE_PTR_HPP_INCLUDED +#define BOOST_INTERPROCESS_UNIQUE_PTR_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +//!\file +//!This header provides utilities to define a unique_ptr that plays nicely with managed segments. + +namespace boost{ +namespace interprocess{ + +//For backwards compatibility +using ::boost::movelib::unique_ptr; + +//!Returns the type of a unique pointer +//!of type T with boost::interprocess::deleter deleter +//!that can be constructed in the given managed segment type. +template +struct managed_unique_ptr +{ + typedef boost::movelib::unique_ptr + < T + , typename ManagedMemory::template deleter::type + > type; +}; + +//!Returns an instance of a unique pointer constructed +//!with boost::interproces::deleter from a pointer +//!of type T that has been allocated in the passed managed segment +template +inline typename managed_unique_ptr::type + make_managed_unique_ptr(T *constructed_object, ManagedMemory &managed_memory) +{ + return typename managed_unique_ptr::type + (constructed_object, managed_memory.template get_deleter()); +} + +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_INTERPROCESS_UNIQUE_PTR_HPP_INCLUDED diff --git a/libraries/boost/boost/interprocess/smart_ptr/weak_ptr.hpp b/libraries/boost/boost/interprocess/smart_ptr/weak_ptr.hpp new file mode 100644 index 000000000..c6e52ddab --- /dev/null +++ b/libraries/boost/boost/interprocess/smart_ptr/weak_ptr.hpp @@ -0,0 +1,269 @@ +////////////////////////////////////////////////////////////////////////////// +// +// This file is the adaptation for Interprocess of boost/weak_ptr.hpp +// +// (C) Copyright Peter Dimov 2001, 2002, 2003 +// (C) Copyright Ion Gaztanaga 2006-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_WEAK_PTR_HPP_INCLUDED +#define BOOST_INTERPROCESS_WEAK_PTR_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes the smart pointer weak_ptr. + +namespace boost{ +namespace interprocess{ + +//!The weak_ptr class template stores a "weak reference" to an object +//!that's already managed by a shared_ptr. To access the object, a weak_ptr +//!can be converted to a shared_ptr using the shared_ptr constructor or the +//!member function lock. When the last shared_ptr to the object goes away +//!and the object is deleted, the attempt to obtain a shared_ptr from the +//!weak_ptr instances that refer to the deleted object will fail: the constructor +//!will throw an exception of type bad_weak_ptr, and weak_ptr::lock will +//!return an empty shared_ptr. +//! +//!Every weak_ptr meets the CopyConstructible and Assignable requirements +//!of the C++ Standard Library, and so can be used in standard library containers. +//!Comparison operators are supplied so that weak_ptr works with the standard +//!library's associative containers. +//! +//!weak_ptr operations never throw exceptions. +//! +//!The class template is parameterized on T, the type of the object pointed to. +template +class weak_ptr +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + // Borland 5.5.1 specific workarounds + typedef weak_ptr this_type; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + typedef T element_type; + typedef T value_type; + + //!Effects: Constructs an empty weak_ptr. + //!Postconditions: use_count() == 0. + weak_ptr() + : m_pn() // never throws + {} + // generated copy constructor, assignment, destructor are fine + // + // The "obvious" converting constructor implementation: + // + // template + // weak_ptr(weak_ptr const & r): m_px(r.m_px), m_pn(r.m_pn) // never throws + // { + // } + // + // has a serious problem. + // + // r.m_px may already have been invalidated. The m_px(r.m_px) + // conversion may require access to *r.m_px (virtual inheritance). + // + // It is not possible to avoid spurious access violations since + // in multithreaded programs r.m_px may be invalidated at any point. + + //!Effects: If r is empty, constructs an empty weak_ptr; otherwise, + //!constructs a weak_ptr that shares ownership with r as if by storing a + //!copy of the pointer stored in r. + //! + //!Postconditions: use_count() == r.use_count(). + //! + //!Throws: nothing. + template + weak_ptr(weak_ptr const & r) + : m_pn(r.m_pn) // never throws + { + //Construct a temporary shared_ptr so that nobody + //can destroy the value while constructing this + const shared_ptr &ref = r.lock(); + m_pn.set_pointer(ref.get()); + } + + //!Effects: If r is empty, constructs an empty weak_ptr; otherwise, + //!constructs a weak_ptr that shares ownership with r as if by storing a + //!copy of the pointer stored in r. + //! + //!Postconditions: use_count() == r.use_count(). + //! + //!Throws: nothing. + template + weak_ptr(shared_ptr const & r) + : m_pn(r.m_pn) // never throws + {} + + //!Effects: Equivalent to weak_ptr(r).swap(*this). + //! + //!Throws: nothing. + //! + //!Notes: The implementation is free to meet the effects (and the + //!implied guarantees) via different means, without creating a temporary. + template + weak_ptr & operator=(weak_ptr const & r) // never throws + { + //Construct a temporary shared_ptr so that nobody + //can destroy the value while constructing this + const shared_ptr &ref = r.lock(); + m_pn = r.m_pn; + m_pn.set_pointer(ref.get()); + return *this; + } + + //!Effects: Equivalent to weak_ptr(r).swap(*this). + //! + //!Throws: nothing. + //! + //!Notes: The implementation is free to meet the effects (and the + //!implied guarantees) via different means, without creating a temporary. + template + weak_ptr & operator=(shared_ptr const & r) // never throws + { m_pn = r.m_pn; return *this; } + + //!Returns: expired()? shared_ptr(): shared_ptr(*this). + //! + //!Throws: nothing. + shared_ptr lock() const // never throws + { + // optimization: avoid throw overhead + if(expired()){ + return shared_ptr(); + } + BOOST_TRY{ + return shared_ptr(*this); + } + BOOST_CATCH(bad_weak_ptr const &){ + // Q: how can we get here? + // A: another thread may have invalidated r after the use_count test above. + return shared_ptr(); + } + BOOST_CATCH_END + } + + //!Returns: 0 if *this is empty; otherwise, the number of shared_ptr objects + //!that share ownership with *this. + //! + //!Throws: nothing. + //! + //!Notes: use_count() is not necessarily efficient. Use only for debugging and + //!testing purposes, not for production code. + long use_count() const // never throws + { return m_pn.use_count(); } + + //!Returns: Returns: use_count() == 0. + //! + //!Throws: nothing. + //! + //!Notes: expired() may be faster than use_count(). + bool expired() const // never throws + { return m_pn.use_count() == 0; } + + //!Effects: Equivalent to: + //!weak_ptr().swap(*this). + void reset() // never throws in 1.30+ + { this_type().swap(*this); } + + //!Effects: Exchanges the contents of the two + //!smart pointers. + //! + //!Throws: nothing. + void swap(this_type & other) // never throws + { ::boost::adl_move_swap(m_pn, other.m_pn); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + template + bool _internal_less(weak_ptr const & rhs) const + { return m_pn < rhs.m_pn; } + + template + void _internal_assign(const ipcdetail::shared_count & pn2) + { + + m_pn = pn2; + } + + private: + + template friend class shared_ptr; + template friend class weak_ptr; + + ipcdetail::weak_count m_pn; // reference counter + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; // weak_ptr + +template inline +bool operator<(weak_ptr const & a, weak_ptr const & b) +{ return a._internal_less(b); } + +template inline +void swap(weak_ptr & a, weak_ptr & b) +{ a.swap(b); } + +//!Returns the type of a weak pointer +//!of type T with the allocator boost::interprocess::allocator allocator +//!and boost::interprocess::deleter deleter +//!that can be constructed in the given managed segment type. +template +struct managed_weak_ptr +{ + typedef weak_ptr + < T + , typename ManagedMemory::template allocator::type + , typename ManagedMemory::template deleter::type + > type; +}; + +//!Returns an instance of a weak pointer constructed +//!with the default allocator and deleter from a pointer +//!of type T that has been allocated in the passed managed segment +template +inline typename managed_weak_ptr::type + make_managed_weak_ptr(T *constructed_object, ManagedMemory &managed_memory) +{ + return typename managed_weak_ptr::type + ( constructed_object + , managed_memory.template get_allocator() + , managed_memory.template get_deleter() + ); +} + +} // namespace interprocess +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_WEAK_PTR_HPP_INCLUDED diff --git a/libraries/boost/boost/interprocess/streams/bufferstream.hpp b/libraries/boost/boost/interprocess/streams/bufferstream.hpp new file mode 100644 index 000000000..015d03c65 --- /dev/null +++ b/libraries/boost/boost/interprocess/streams/bufferstream.hpp @@ -0,0 +1,491 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's sstream file. Modified by Ion Gaztanaga 2005-2012. +// Changed internal SGI string to a buffer. Added efficient +// internal buffer get/set/swap functions, so that we can obtain/establish the +// internal buffer without any reallocation or copy. Kill those temporaries! +/////////////////////////////////////////////////////////////////////////////// +/* + * Copyright (c) 1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +//!\file +//!This file defines basic_bufferbuf, basic_ibufferstream, +//!basic_obufferstream, and basic_bufferstream classes. These classes +//!represent streamsbufs and streams whose sources or destinations +//!are fixed size character buffers. + +#ifndef BOOST_INTERPROCESS_BUFFERSTREAM_HPP +#define BOOST_INTERPROCESS_BUFFERSTREAM_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include // char traits +#include // ptrdiff_t +#include +#include + +namespace boost { namespace interprocess { + +//!A streambuf class that controls the transmission of elements to and from +//!a basic_xbufferstream. The elements are transmitted from a to a fixed +//!size buffer +template +class basic_bufferbuf + : public std::basic_streambuf +{ + public: + typedef CharT char_type; + typedef typename CharTraits::int_type int_type; + typedef typename CharTraits::pos_type pos_type; + typedef typename CharTraits::off_type off_type; + typedef CharTraits traits_type; + typedef std::basic_streambuf base_t; + + public: + //!Constructor. + //!Does not throw. + explicit basic_bufferbuf(std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : base_t(), m_mode(mode), m_buffer(0), m_length(0) + {} + + //!Constructor. Assigns formatting buffer. + //!Does not throw. + explicit basic_bufferbuf(CharT *buf, std::size_t length, + std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : base_t(), m_mode(mode), m_buffer(buf), m_length(length) + { this->set_pointers(); } + + virtual ~basic_bufferbuf(){} + + public: + //!Returns the pointer and size of the internal buffer. + //!Does not throw. + std::pair buffer() const + { return std::pair(m_buffer, m_length); } + + //!Sets the underlying buffer to a new value + //!Does not throw. + void buffer(CharT *buf, std::size_t length) + { m_buffer = buf; m_length = length; this->set_pointers(); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + void set_pointers() + { + // The initial read position is the beginning of the buffer. + if(m_mode & std::ios_base::in) + this->setg(m_buffer, m_buffer, m_buffer + m_length); + + // The initial write position is the beginning of the buffer. + if(m_mode & std::ios_base::out) + this->setp(m_buffer, m_buffer + m_length); + } + + protected: + virtual int_type underflow() + { + // Precondition: gptr() >= egptr(). Returns a character, if available. + return this->gptr() != this->egptr() ? + CharTraits::to_int_type(*this->gptr()) : CharTraits::eof(); + } + + virtual int_type pbackfail(int_type c = CharTraits::eof()) + { + if(this->gptr() != this->eback()) { + if(!CharTraits::eq_int_type(c, CharTraits::eof())) { + if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) { + this->gbump(-1); + return c; + } + else if(m_mode & std::ios_base::out) { + this->gbump(-1); + *this->gptr() = c; + return c; + } + else + return CharTraits::eof(); + } + else { + this->gbump(-1); + return CharTraits::not_eof(c); + } + } + else + return CharTraits::eof(); + } + + virtual int_type overflow(int_type c = CharTraits::eof()) + { + if(m_mode & std::ios_base::out) { + if(!CharTraits::eq_int_type(c, CharTraits::eof())) { +// if(!(m_mode & std::ios_base::in)) { +// if(this->pptr() != this->epptr()) { +// *this->pptr() = CharTraits::to_char_type(c); +// this->pbump(1); +// return c; +// } +// else +// return CharTraits::eof(); +// } +// else { + if(this->pptr() == this->epptr()) { + //We can't append to a static buffer + return CharTraits::eof(); + } + else { + *this->pptr() = CharTraits::to_char_type(c); + this->pbump(1); + return c; + } +// } + } + else // c is EOF, so we don't have to do anything + return CharTraits::not_eof(c); + } + else // Overflow always fails if it's read-only. + return CharTraits::eof(); + } + + virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + { + bool in = false; + bool out = false; + + const std::ios_base::openmode inout = + std::ios_base::in | std::ios_base::out; + + if((mode & inout) == inout) { + if(dir == std::ios_base::beg || dir == std::ios_base::end) + in = out = true; + } + else if(mode & std::ios_base::in) + in = true; + else if(mode & std::ios_base::out) + out = true; + + if(!in && !out) + return pos_type(off_type(-1)); + else if((in && (!(m_mode & std::ios_base::in) || (off != 0 && this->gptr() == 0) )) || + (out && (!(m_mode & std::ios_base::out) || (off != 0 && this->pptr() == 0)))) + return pos_type(off_type(-1)); + + std::streamoff newoff; + switch(dir) { + case std::ios_base::beg: + newoff = 0; + break; + case std::ios_base::end: + newoff = static_cast(m_length); + break; + case std::ios_base::cur: + newoff = in ? static_cast(this->gptr() - this->eback()) + : static_cast(this->pptr() - this->pbase()); + break; + default: + return pos_type(off_type(-1)); + } + + off += newoff; + + if(in) { + std::ptrdiff_t n = this->egptr() - this->eback(); + + if(off < 0 || off > n) + return pos_type(off_type(-1)); + else + this->setg(this->eback(), this->eback() + off, this->eback() + n); + } + + if(out) { + std::ptrdiff_t n = this->epptr() - this->pbase(); + + if(off < 0 || off > n) + return pos_type(off_type(-1)); + else { + this->setp(this->pbase(), this->pbase() + n); + this->pbump(off); + } + } + + return pos_type(off); + } + + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + { return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode); } + + private: + std::ios_base::openmode m_mode; + CharT * m_buffer; + std::size_t m_length; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!A basic_istream class that uses a fixed size character buffer +//!as its formatting buffer. +template +class basic_ibufferstream : + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private basic_bufferbuf, + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public std::basic_istream +{ + public: // Typedefs + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef basic_bufferbuf bufferbuf_t; + typedef std::basic_ios basic_ios_t; + typedef std::basic_istream base_t; + bufferbuf_t & get_buf() { return *this; } + const bufferbuf_t & get_buf() const{ return *this; } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. + //!Does not throw. + basic_ibufferstream(std::ios_base::openmode mode = std::ios_base::in) + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(mode | std::ios_base::in) + , base_t(&get_buf()) + {} + + //!Constructor. Assigns formatting buffer. + //!Does not throw. + basic_ibufferstream(const CharT *buf, std::size_t length, + std::ios_base::openmode mode = std::ios_base::in) + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(const_cast(buf), length, mode | std::ios_base::in) + , base_t(&get_buf()) + {} + + ~basic_ibufferstream(){}; + + public: + //!Returns the address of the stored + //!stream buffer. + basic_bufferbuf* rdbuf() const + { return const_cast*>(&get_buf()); } + + //!Returns the pointer and size of the internal buffer. + //!Does not throw. + std::pair buffer() const + { return get_buf().buffer(); } + + //!Sets the underlying buffer to a new value. Resets + //!stream position. Does not throw. + void buffer(const CharT *buf, std::size_t length) + { get_buf().buffer(const_cast(buf), length); } +}; + +//!A basic_ostream class that uses a fixed size character buffer +//!as its formatting buffer. +template +class basic_obufferstream : + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private basic_bufferbuf, + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public std::basic_ostream +{ + public: + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef basic_bufferbuf bufferbuf_t; + typedef std::basic_ios basic_ios_t; + typedef std::basic_ostream base_t; + bufferbuf_t & get_buf() { return *this; } + const bufferbuf_t & get_buf() const{ return *this; } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. + //!Does not throw. + basic_obufferstream(std::ios_base::openmode mode = std::ios_base::out) + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(mode | std::ios_base::out) + , base_t(&get_buf()) + {} + + //!Constructor. Assigns formatting buffer. + //!Does not throw. + basic_obufferstream(CharT *buf, std::size_t length, + std::ios_base::openmode mode = std::ios_base::out) + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(buf, length, mode | std::ios_base::out) + , base_t(&get_buf()) + {} + + ~basic_obufferstream(){} + + public: + //!Returns the address of the stored + //!stream buffer. + basic_bufferbuf* rdbuf() const + { return const_cast*>(&get_buf()); } + + //!Returns the pointer and size of the internal buffer. + //!Does not throw. + std::pair buffer() const + { return get_buf().buffer(); } + + //!Sets the underlying buffer to a new value. Resets + //!stream position. Does not throw. + void buffer(CharT *buf, std::size_t length) + { get_buf().buffer(buf, length); } +}; + + +//!A basic_iostream class that uses a fixed size character buffer +//!as its formatting buffer. +template +class basic_bufferstream : + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private basic_bufferbuf, + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public std::basic_iostream +{ + public: // Typedefs + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef basic_bufferbuf bufferbuf_t; + typedef std::basic_ios basic_ios_t; + typedef std::basic_iostream base_t; + bufferbuf_t & get_buf() { return *this; } + const bufferbuf_t & get_buf() const{ return *this; } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. + //!Does not throw. + basic_bufferstream(std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(mode) + , base_t(&get_buf()) + {} + + //!Constructor. Assigns formatting buffer. + //!Does not throw. + basic_bufferstream(CharT *buf, std::size_t length, + std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(buf, length, mode) + , base_t(&get_buf()) + {} + + ~basic_bufferstream(){} + + public: + //!Returns the address of the stored + //!stream buffer. + basic_bufferbuf* rdbuf() const + { return const_cast*>(&get_buf()); } + + //!Returns the pointer and size of the internal buffer. + //!Does not throw. + std::pair buffer() const + { return get_buf().buffer(); } + + //!Sets the underlying buffer to a new value. Resets + //!stream position. Does not throw. + void buffer(CharT *buf, std::size_t length) + { get_buf().buffer(buf, length); } +}; + +//Some typedefs to simplify usage +typedef basic_bufferbuf bufferbuf; +typedef basic_bufferstream bufferstream; +typedef basic_ibufferstream ibufferstream; +typedef basic_obufferstream obufferstream; + +typedef basic_bufferbuf wbufferbuf; +typedef basic_bufferstream wbufferstream; +typedef basic_ibufferstream wibufferstream; +typedef basic_obufferstream wobufferstream; + + +}} //namespace boost { namespace interprocess { + +#include + +#endif /* BOOST_INTERPROCESS_BUFFERSTREAM_HPP */ diff --git a/libraries/boost/boost/interprocess/streams/vectorstream.hpp b/libraries/boost/boost/interprocess/streams/vectorstream.hpp new file mode 100644 index 000000000..8f6bf3837 --- /dev/null +++ b/libraries/boost/boost/interprocess/streams/vectorstream.hpp @@ -0,0 +1,622 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's sstream file. Modified by Ion Gaztanaga 2005-2012. +// Changed internal SGI string to a generic, templatized vector. Added efficient +// internal buffer get/set/swap functions, so that we can obtain/establish the +// internal buffer without any reallocation or copy. Kill those temporaries! +/////////////////////////////////////////////////////////////////////////////// +/* + * Copyright (c) 1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +//!\file +//!This file defines basic_vectorbuf, basic_ivectorstream, +//!basic_ovectorstream, and basic_vectorstreamclasses. These classes +//!represent streamsbufs and streams whose sources or destinations are +//!STL-like vectors that can be swapped with external vectors to avoid +//!unnecessary allocations/copies. + +#ifndef BOOST_INTERPROCESS_VECTORSTREAM_HPP +#define BOOST_INTERPROCESS_VECTORSTREAM_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include // char traits +#include // ptrdiff_t +#include +#include + +namespace boost { namespace interprocess { + +//!A streambuf class that controls the transmission of elements to and from +//!a basic_ivectorstream, basic_ovectorstream or basic_vectorstream. +//!It holds a character vector specified by CharVector template parameter +//!as its formatting buffer. The vector must have contiguous storage, like +//!std::vector, boost::interprocess::vector or boost::interprocess::basic_string +template +class basic_vectorbuf + : public std::basic_streambuf +{ + public: + typedef CharVector vector_type; + typedef typename CharVector::value_type char_type; + typedef typename CharTraits::int_type int_type; + typedef typename CharTraits::pos_type pos_type; + typedef typename CharTraits::off_type off_type; + typedef CharTraits traits_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef std::basic_streambuf base_t; + + basic_vectorbuf(const basic_vectorbuf&); + basic_vectorbuf & operator =(const basic_vectorbuf&); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. Throws if vector_type default + //!constructor throws. + explicit basic_vectorbuf(std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : base_t(), m_mode(mode) + { this->initialize_pointers(); } + + //!Constructor. Throws if + //!vector_type(const VectorParameter ¶m) throws. + template + explicit basic_vectorbuf(const VectorParameter ¶m, + std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : base_t(), m_mode(mode), m_vect(param) + { this->initialize_pointers(); } + + public: + + //!Swaps the underlying vector with the passed vector. + //!This function resets the read/write position in the stream. + //!Does not throw. + void swap_vector(vector_type &vect) + { + if (this->m_mode & std::ios_base::out){ + //Update high water if necessary + //And resize vector to remove extra size + if (mp_high_water < base_t::pptr()){ + //Restore the vector's size if necessary + mp_high_water = base_t::pptr(); + } + //This does not reallocate + m_vect.resize(mp_high_water - (m_vect.size() ? &m_vect[0] : 0)); + } + //Now swap vector + m_vect.swap(vect); + this->initialize_pointers(); + } + + //!Returns a const reference to the internal vector. + //!Does not throw. + const vector_type &vector() const + { + if (this->m_mode & std::ios_base::out){ + if (mp_high_water < base_t::pptr()){ + //Restore the vector's size if necessary + mp_high_water = base_t::pptr(); + } + //This shouldn't reallocate + typedef typename vector_type::size_type size_type; + char_type *old_ptr = base_t::pbase(); + size_type high_pos = size_type(mp_high_water-old_ptr); + if(m_vect.size() > high_pos){ + m_vect.resize(high_pos); + //But we must update end write pointer because vector size is now shorter + int old_pos = base_t::pptr() - base_t::pbase(); + const_cast(this)->base_t::setp(old_ptr, old_ptr + high_pos); + const_cast(this)->base_t::pbump(old_pos); + } + } + return m_vect; + } + + //!Preallocates memory from the internal vector. + //!Resets the stream to the first position. + //!Throws if the internals vector's memory allocation throws. + void reserve(typename vector_type::size_type size) + { + if (this->m_mode & std::ios_base::out && size > m_vect.size()){ + typename vector_type::difference_type write_pos = base_t::pptr() - base_t::pbase(); + typename vector_type::difference_type read_pos = base_t::gptr() - base_t::eback(); + //Now update pointer data + m_vect.reserve(size); + this->initialize_pointers(); + base_t::pbump((int)write_pos); + if(this->m_mode & std::ios_base::in){ + base_t::gbump((int)read_pos); + } + } + } + + //!Calls clear() method of the internal vector. + //!Resets the stream to the first position. + void clear() + { m_vect.clear(); this->initialize_pointers(); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + //Maximizes high watermark to the initial vector size, + //initializes read and write iostream buffers to the capacity + //and resets stream positions + void initialize_pointers() + { + // The initial read position is the beginning of the vector. + if(!(m_mode & std::ios_base::out)){ + if(m_vect.empty()){ + this->setg(0, 0, 0); + } + else{ + this->setg(&m_vect[0], &m_vect[0], &m_vect[0] + m_vect.size()); + } + } + + // The initial write position is the beginning of the vector. + if(m_mode & std::ios_base::out){ + //First get real size + int real_size = (int)m_vect.size(); + //Then maximize size for high watermarking + m_vect.resize(m_vect.capacity()); + BOOST_ASSERT(m_vect.size() == m_vect.capacity()); + //Set high watermarking with the expanded size + mp_high_water = m_vect.size() ? (&m_vect[0] + real_size) : 0; + //Now set formatting pointers + if(m_vect.empty()){ + this->setp(0, 0); + if(m_mode & std::ios_base::in) + this->setg(0, 0, 0); + } + else{ + char_type *p = &m_vect[0]; + this->setp(p, p + m_vect.size()); + if(m_mode & std::ios_base::in) + this->setg(p, p, p + real_size); + } + if (m_mode & (std::ios_base::app | std::ios_base::ate)){ + base_t::pbump((int)real_size); + } + } + } + + protected: + virtual int_type underflow() + { + if (base_t::gptr() == 0) + return CharTraits::eof(); + if(m_mode & std::ios_base::out){ + if (mp_high_water < base_t::pptr()) + mp_high_water = base_t::pptr(); + if (base_t::egptr() < mp_high_water) + base_t::setg(base_t::eback(), base_t::gptr(), mp_high_water); + } + if (base_t::gptr() < base_t::egptr()) + return CharTraits::to_int_type(*base_t::gptr()); + return CharTraits::eof(); + } + + virtual int_type pbackfail(int_type c = CharTraits::eof()) + { + if(this->gptr() != this->eback()) { + if(!CharTraits::eq_int_type(c, CharTraits::eof())) { + if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) { + this->gbump(-1); + return c; + } + else if(m_mode & std::ios_base::out) { + this->gbump(-1); + *this->gptr() = c; + return c; + } + else + return CharTraits::eof(); + } + else { + this->gbump(-1); + return CharTraits::not_eof(c); + } + } + else + return CharTraits::eof(); + } + + virtual int_type overflow(int_type c = CharTraits::eof()) + { + if(m_mode & std::ios_base::out) { + if(!CharTraits::eq_int_type(c, CharTraits::eof())) { + typedef typename vector_type::difference_type dif_t; + //The new output position is the previous one plus one + //because 'overflow' requires putting 'c' on the buffer + dif_t new_outpos = base_t::pptr() - base_t::pbase() + 1; + //Adjust high water if necessary + dif_t hipos = mp_high_water - base_t::pbase(); + if (hipos < new_outpos) + hipos = new_outpos; + //Insert the new data + m_vect.push_back(CharTraits::to_char_type(c)); + m_vect.resize(m_vect.capacity()); + BOOST_ASSERT(m_vect.size() == m_vect.capacity()); + char_type* p = const_cast(&m_vect[0]); + //A reallocation might have happened, update pointers + base_t::setp(p, p + (dif_t)m_vect.size()); + mp_high_water = p + hipos; + if (m_mode & std::ios_base::in) + base_t::setg(p, p + (base_t::gptr() - base_t::eback()), mp_high_water); + //Update write position to the old position + 1 + base_t::pbump((int)new_outpos); + return c; + } + else // c is EOF, so we don't have to do anything + return CharTraits::not_eof(c); + } + else // Overflow always fails if it's read-only. + return CharTraits::eof(); + } + + virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + { + //Get seek mode + bool in(0 != (mode & std::ios_base::in)), out(0 != (mode & std::ios_base::out)); + //Test for logic errors + if(!in & !out) + return pos_type(off_type(-1)); + else if((in && out) && (dir == std::ios_base::cur)) + return pos_type(off_type(-1)); + else if((in && (!(m_mode & std::ios_base::in) || (off != 0 && this->gptr() == 0) )) || + (out && (!(m_mode & std::ios_base::out) || (off != 0 && this->pptr() == 0)))) + return pos_type(off_type(-1)); + + off_type newoff; + //Just calculate the end of the stream. If the stream is read-only + //the limit is the size of the vector. Otherwise, the high water mark + //will mark the real size. + off_type limit; + if(m_mode & std::ios_base::out){ + //Update high water marking because pptr() is going to change and it might + //have been updated since last overflow() + if(mp_high_water < base_t::pptr()) + mp_high_water = base_t::pptr(); + //Update read limits in case high water mark was changed + if(m_mode & std::ios_base::in){ + if (base_t::egptr() < mp_high_water) + base_t::setg(base_t::eback(), base_t::gptr(), mp_high_water); + } + limit = static_cast(mp_high_water - base_t::pbase()); + } + else{ + limit = static_cast(m_vect.size()); + } + + switch(dir) { + case std::ios_base::beg: + newoff = 0; + break; + case std::ios_base::end: + newoff = limit; + break; + case std::ios_base::cur: + newoff = in ? static_cast(this->gptr() - this->eback()) + : static_cast(this->pptr() - this->pbase()); + break; + default: + return pos_type(off_type(-1)); + } + + newoff += off; + + if (newoff < 0 || newoff > limit) + return pos_type(-1); + if (m_mode & std::ios_base::app && mode & std::ios_base::out && newoff != limit) + return pos_type(-1); + //This can reassign pointers + //if(m_vect.size() != m_vect.capacity()) + //this->initialize_pointers(); + if (in) + base_t::setg(base_t::eback(), base_t::eback() + newoff, base_t::egptr()); + if (out){ + base_t::setp(base_t::pbase(), base_t::epptr()); + base_t::pbump(newoff); + } + return pos_type(newoff); + } + + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + { return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode); } + + private: + std::ios_base::openmode m_mode; + mutable vector_type m_vect; + mutable char_type* mp_high_water; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//!A basic_istream class that holds a character vector specified by CharVector +//!template parameter as its formatting buffer. The vector must have +//!contiguous storage, like std::vector, boost::interprocess::vector or +//!boost::interprocess::basic_string +template +class basic_ivectorstream + : public std::basic_istream + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + , private basic_vectorbuf + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +{ + public: + typedef CharVector vector_type; + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef basic_vectorbuf vectorbuf_t; + typedef std::basic_ios basic_ios_t; + typedef std::basic_istream base_t; + + vectorbuf_t & get_buf() { return *this; } + const vectorbuf_t & get_buf() const{ return *this; } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + + //!Constructor. Throws if vector_type default + //!constructor throws. + basic_ivectorstream(std::ios_base::openmode mode = std::ios_base::in) + : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base + //(via basic_ios::init() call in base_t's constructor) without the risk of a + //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. + , vectorbuf_t(mode | std::ios_base::in) + { this->base_t::rdbuf(&get_buf()); } + + //!Constructor. Throws if vector_type(const VectorParameter ¶m) + //!throws. + template + basic_ivectorstream(const VectorParameter ¶m, + std::ios_base::openmode mode = std::ios_base::in) + : vectorbuf_t(param, mode | std::ios_base::in) + //basic_ios_t() is constructed uninitialized as virtual base + //and initialized inside base_t calling basic_ios::init() + , base_t(&get_buf()) + {} + + public: + //!Returns the address of the stored + //!stream buffer. + basic_vectorbuf* rdbuf() const + { return const_cast*>(&get_buf()); } + + //!Swaps the underlying vector with the passed vector. + //!This function resets the read position in the stream. + //!Does not throw. + void swap_vector(vector_type &vect) + { get_buf().swap_vector(vect); } + + //!Returns a const reference to the internal vector. + //!Does not throw. + const vector_type &vector() const + { return get_buf().vector(); } + + //!Calls reserve() method of the internal vector. + //!Resets the stream to the first position. + //!Throws if the internals vector's reserve throws. + void reserve(typename vector_type::size_type size) + { get_buf().reserve(size); } + + //!Calls clear() method of the internal vector. + //!Resets the stream to the first position. + void clear() + { get_buf().clear(); } +}; + +//!A basic_ostream class that holds a character vector specified by CharVector +//!template parameter as its formatting buffer. The vector must have +//!contiguous storage, like std::vector, boost::interprocess::vector or +//!boost::interprocess::basic_string +template +class basic_ovectorstream + : public std::basic_ostream + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + , private basic_vectorbuf + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +{ + public: + typedef CharVector vector_type; + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef basic_vectorbuf vectorbuf_t; + typedef std::basic_ios basic_ios_t; + typedef std::basic_ostream base_t; + + vectorbuf_t & get_buf() { return *this; } + const vectorbuf_t & get_buf()const { return *this; } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. Throws if vector_type default + //!constructor throws. + basic_ovectorstream(std::ios_base::openmode mode = std::ios_base::out) + : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base + //(via basic_ios::init() call in base_t's constructor) without the risk of a + //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. + , vectorbuf_t(mode | std::ios_base::out) + { this->base_t::rdbuf(&get_buf()); } + + //!Constructor. Throws if vector_type(const VectorParameter ¶m) + //!throws. + template + basic_ovectorstream(const VectorParameter ¶m, + std::ios_base::openmode mode = std::ios_base::out) + : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base + //(via basic_ios::init() call in base_t's constructor) without the risk of a + //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. + , vectorbuf_t(param, mode | std::ios_base::out) + { this->base_t::rdbuf(&get_buf()); } + + public: + //!Returns the address of the stored + //!stream buffer. + basic_vectorbuf* rdbuf() const + { return const_cast*>(&get_buf()); } + + //!Swaps the underlying vector with the passed vector. + //!This function resets the write position in the stream. + //!Does not throw. + void swap_vector(vector_type &vect) + { get_buf().swap_vector(vect); } + + //!Returns a const reference to the internal vector. + //!Does not throw. + const vector_type &vector() const + { return get_buf().vector(); } + + //!Calls reserve() method of the internal vector. + //!Resets the stream to the first position. + //!Throws if the internals vector's reserve throws. + void reserve(typename vector_type::size_type size) + { get_buf().reserve(size); } +}; + +//!A basic_iostream class that holds a character vector specified by CharVector +//!template parameter as its formatting buffer. The vector must have +//!contiguous storage, like std::vector, boost::interprocess::vector or +//!boost::interprocess::basic_string +template +class basic_vectorstream + : public std::basic_iostream + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + , private basic_vectorbuf + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +{ + public: + typedef CharVector vector_type; + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef basic_vectorbuf vectorbuf_t; + typedef std::basic_ios basic_ios_t; + typedef std::basic_iostream base_t; + + vectorbuf_t & get_buf() { return *this; } + const vectorbuf_t & get_buf() const{ return *this; } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructor. Throws if vector_type default + //!constructor throws. + basic_vectorstream(std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base + //(via basic_ios::init() call in base_t's constructor) without the risk of a + //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. + , vectorbuf_t(mode) + { this->base_t::rdbuf(&get_buf()); } + + //!Constructor. Throws if vector_type(const VectorParameter ¶m) + //!throws. + template + basic_vectorstream(const VectorParameter ¶m, std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base + //(via basic_ios::init() call in base_t's constructor) without the risk of a + //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. + , vectorbuf_t(param, mode) + { this->base_t::rdbuf(&get_buf()); } + + public: + //Returns the address of the stored stream buffer. + basic_vectorbuf* rdbuf() const + { return const_cast*>(&get_buf()); } + + //!Swaps the underlying vector with the passed vector. + //!This function resets the read/write position in the stream. + //!Does not throw. + void swap_vector(vector_type &vect) + { get_buf().swap_vector(vect); } + + //!Returns a const reference to the internal vector. + //!Does not throw. + const vector_type &vector() const + { return get_buf().vector(); } + + //!Calls reserve() method of the internal vector. + //!Resets the stream to the first position. + //!Throws if the internals vector's reserve throws. + void reserve(typename vector_type::size_type size) + { get_buf().reserve(size); } + + //!Calls clear() method of the internal vector. + //!Resets the stream to the first position. + void clear() + { get_buf().clear(); } +}; + +//Some typedefs to simplify usage +//! +//!typedef basic_vectorbuf > vectorbuf; +//!typedef basic_vectorstream > vectorstream; +//!typedef basic_ivectorstream > ivectorstream; +//!typedef basic_ovectorstream > ovectorstream; +//! +//!typedef basic_vectorbuf > wvectorbuf; +//!typedef basic_vectorstream > wvectorstream; +//!typedef basic_ivectorstream > wivectorstream; +//!typedef basic_ovectorstream > wovectorstream; + +}} //namespace boost { namespace interprocess { + +#include + +#endif /* BOOST_INTERPROCESS_VECTORSTREAM_HPP */ diff --git a/libraries/boost/boost/interprocess/sync/detail/common_algorithms.hpp b/libraries/boost/boost/interprocess/sync/detail/common_algorithms.hpp new file mode 100644 index 000000000..1a72d686b --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/detail/common_algorithms.hpp @@ -0,0 +1,81 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP +#define BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +bool try_based_timed_lock(MutexType &m, const boost::posix_time::ptime &abs_time) +{ + //Same as lock() + if(abs_time == boost::posix_time::pos_infin){ + m.lock(); + return true; + } + //Always try to lock to achieve POSIX guarantees: + // "Under no circumstance shall the function fail with a timeout if the mutex + // can be locked immediately. The validity of the abs_timeout parameter need not + // be checked if the mutex can be locked immediately." + else if(m.try_lock()){ + return true; + } + else{ + spin_wait swait; + while(microsec_clock::universal_time() < abs_time){ + if(m.try_lock()){ + return true; + } + swait.yield(); + } + return false; + } +} + +template +void try_based_lock(MutexType &m) +{ + if(!m.try_lock()){ + spin_wait swait; + do{ + if(m.try_lock()){ + break; + } + else{ + swait.yield(); + } + } + while(1); + } +} + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include + +#endif //BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP diff --git a/libraries/boost/boost/interprocess/sync/detail/condition_algorithm_8a.hpp b/libraries/boost/boost/interprocess/sync/detail/condition_algorithm_8a.hpp new file mode 100644 index 000000000..9978309b9 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/detail/condition_algorithm_8a.hpp @@ -0,0 +1,395 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP +#define BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// +// Condition variable algorithm taken from pthreads-win32 discussion. +// +// The algorithm was developed by Alexander Terekhov in colaboration with +// Louis Thomas. +// +// Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL +// +// semBlockLock - bin.semaphore +// semBlockQueue - semaphore +// mtxExternal - mutex or CS +// mtxUnblockLock - mutex or CS +// nWaitersGone - int +// nWaitersBlocked - int +// nWaitersToUnblock - int +// +// wait( timeout ) { +// +// [auto: register int result ] // error checking omitted +// [auto: register int nSignalsWasLeft ] +// [auto: register int nWaitersWasGone ] +// +// sem_wait( semBlockLock ); +// nWaitersBlocked++; +// sem_post( semBlockLock ); +// +// unlock( mtxExternal ); +// bTimedOut = sem_wait( semBlockQueue,timeout ); +// +// lock( mtxUnblockLock ); +// if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { +// if ( bTimedOut ) { // timeout (or canceled) +// if ( 0 != nWaitersBlocked ) { +// nWaitersBlocked--; +// } +// else { +// nWaitersGone++; // count spurious wakeups. +// } +// } +// if ( 0 == --nWaitersToUnblock ) { +// if ( 0 != nWaitersBlocked ) { +// sem_post( semBlockLock ); // open the gate. +// nSignalsWasLeft = 0; // do not open the gate +// // below again. +// } +// else if ( 0 != (nWaitersWasGone = nWaitersGone) ) { +// nWaitersGone = 0; +// } +// } +// } +// else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or +// // spurious semaphore :-) +// sem_wait( semBlockLock ); +// nWaitersBlocked -= nWaitersGone; // something is going on here +// // - test of timeouts? :-) +// sem_post( semBlockLock ); +// nWaitersGone = 0; +// } +// unlock( mtxUnblockLock ); +// +// if ( 1 == nSignalsWasLeft ) { +// if ( 0 != nWaitersWasGone ) { +// // sem_adjust( semBlockQueue,-nWaitersWasGone ); +// while ( nWaitersWasGone-- ) { +// sem_wait( semBlockQueue ); // better now than spurious later +// } +// } sem_post( semBlockLock ); // open the gate +// } +// +// lock( mtxExternal ); +// +// return ( bTimedOut ) ? ETIMEOUT : 0; +// } +// +// signal(bAll) { +// +// [auto: register int result ] +// [auto: register int nSignalsToIssue] +// +// lock( mtxUnblockLock ); +// +// if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! +// if ( 0 == nWaitersBlocked ) { // NO-OP +// return unlock( mtxUnblockLock ); +// } +// if (bAll) { +// nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; +// nWaitersBlocked = 0; +// } +// else { +// nSignalsToIssue = 1; +// nWaitersToUnblock++; +// nWaitersBlocked--; +// } +// } +// else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! +// sem_wait( semBlockLock ); // close the gate +// if ( 0 != nWaitersGone ) { +// nWaitersBlocked -= nWaitersGone; +// nWaitersGone = 0; +// } +// if (bAll) { +// nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; +// nWaitersBlocked = 0; +// } +// else { +// nSignalsToIssue = nWaitersToUnblock = 1; +// nWaitersBlocked--; +// } +// } +// else { // NO-OP +// return unlock( mtxUnblockLock ); +// } +// +// unlock( mtxUnblockLock ); +// sem_post( semBlockQueue,nSignalsToIssue ); +// return result; +// } +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + + +// Required interface for ConditionMembers +// class ConditionMembers +// { +// typedef implementation_defined semaphore_type; +// typedef implementation_defined mutex_type; +// typedef implementation_defined integer_type; +// +// integer_type &get_nwaiters_blocked() +// integer_type &get_nwaiters_gone() +// integer_type &get_nwaiters_to_unblock() +// semaphore_type &get_sem_block_queue() +// semaphore_type &get_sem_block_lock() +// mutex_type &get_mtx_unblock_lock() +// }; +// +// Must be initialized as following +// +// get_nwaiters_blocked() == 0 +// get_nwaiters_gone() == 0 +// get_nwaiters_to_unblock() == 0 +// get_sem_block_queue() == initial count 0 +// get_sem_block_lock() == initial count 1 +// get_mtx_unblock_lock() (unlocked) +// +template +class condition_algorithm_8a +{ + private: + condition_algorithm_8a(); + ~condition_algorithm_8a(); + condition_algorithm_8a(const condition_algorithm_8a &); + condition_algorithm_8a &operator=(const condition_algorithm_8a &); + + typedef typename ConditionMembers::semaphore_type semaphore_type; + typedef typename ConditionMembers::mutex_type mutex_type; + typedef typename ConditionMembers::integer_type integer_type; + + public: + template + static bool wait ( ConditionMembers &data, Lock &lock + , bool timeout_enabled, const boost::posix_time::ptime &abs_time); + static void signal(ConditionMembers &data, bool broadcast); +}; + +template +inline void condition_algorithm_8a::signal(ConditionMembers &data, bool broadcast) +{ + integer_type nsignals_to_issue; + + { + scoped_lock locker(data.get_mtx_unblock_lock()); + + if ( 0 != data.get_nwaiters_to_unblock() ) { // the gate is closed!!! + if ( 0 == data.get_nwaiters_blocked() ) { // NO-OP + //locker's destructor triggers data.get_mtx_unblock_lock().unlock() + return; + } + if (broadcast) { + data.get_nwaiters_to_unblock() += nsignals_to_issue = data.get_nwaiters_blocked(); + data.get_nwaiters_blocked() = 0; + } + else { + nsignals_to_issue = 1; + data.get_nwaiters_to_unblock()++; + data.get_nwaiters_blocked()--; + } + } + else if ( data.get_nwaiters_blocked() > data.get_nwaiters_gone() ) { // HARMLESS RACE CONDITION! + data.get_sem_block_lock().wait(); // close the gate + if ( 0 != data.get_nwaiters_gone() ) { + data.get_nwaiters_blocked() -= data.get_nwaiters_gone(); + data.get_nwaiters_gone() = 0; + } + if (broadcast) { + nsignals_to_issue = data.get_nwaiters_to_unblock() = data.get_nwaiters_blocked(); + data.get_nwaiters_blocked() = 0; + } + else { + nsignals_to_issue = data.get_nwaiters_to_unblock() = 1; + data.get_nwaiters_blocked()--; + } + } + else { // NO-OP + //locker's destructor triggers data.get_mtx_unblock_lock().unlock() + return; + } + //locker's destructor triggers data.get_mtx_unblock_lock().unlock() + } + data.get_sem_block_queue().post(nsignals_to_issue); +} + +template +template +inline bool condition_algorithm_8a::wait + ( ConditionMembers &data + , Lock &lock + , bool tout_enabled + , const boost::posix_time::ptime &abs_time + ) +{ + //Initialize to avoid warnings + integer_type nsignals_was_left = 0; + integer_type nwaiters_was_gone = 0; + + data.get_sem_block_lock().wait(); + ++data.get_nwaiters_blocked(); + data.get_sem_block_lock().post(); + + //Unlock external lock and program for relock + lock_inverter inverted_lock(lock); + scoped_lock > external_unlock(inverted_lock); + + bool bTimedOut = tout_enabled + ? !data.get_sem_block_queue().timed_wait(abs_time) + : (data.get_sem_block_queue().wait(), false); + + { + scoped_lock locker(data.get_mtx_unblock_lock()); + if ( 0 != (nsignals_was_left = data.get_nwaiters_to_unblock()) ) { + if ( bTimedOut ) { // timeout (or canceled) + if ( 0 != data.get_nwaiters_blocked() ) { + data.get_nwaiters_blocked()--; + } + else { + data.get_nwaiters_gone()++; // count spurious wakeups. + } + } + if ( 0 == --data.get_nwaiters_to_unblock() ) { + if ( 0 != data.get_nwaiters_blocked() ) { + data.get_sem_block_lock().post(); // open the gate. + nsignals_was_left = 0; // do not open the gate below again. + } + else if ( 0 != (nwaiters_was_gone = data.get_nwaiters_gone()) ) { + data.get_nwaiters_gone() = 0; + } + } + } + else if ( (std::numeric_limits::max)()/2 + == ++data.get_nwaiters_gone() ) { // timeout/canceled or spurious semaphore :-) + data.get_sem_block_lock().wait(); + data.get_nwaiters_blocked() -= data.get_nwaiters_gone(); // something is going on here - test of timeouts? :-) + data.get_sem_block_lock().post(); + data.get_nwaiters_gone() = 0; + } + //locker's destructor triggers data.get_mtx_unblock_lock().unlock() + } + + if ( 1 == nsignals_was_left ) { + if ( 0 != nwaiters_was_gone ) { + // sem_adjust( data.get_sem_block_queue(),-nwaiters_was_gone ); + while ( nwaiters_was_gone-- ) { + data.get_sem_block_queue().wait(); // better now than spurious later + } + } + data.get_sem_block_lock().post(); // open the gate + } + + //lock.lock(); called from unlocker destructor + + return ( bTimedOut ) ? false : true; +} + + +template +class condition_8a_wrapper +{ + //Non-copyable + condition_8a_wrapper(const condition_8a_wrapper &); + condition_8a_wrapper &operator=(const condition_8a_wrapper &); + + ConditionMembers m_data; + typedef ipcdetail::condition_algorithm_8a algo_type; + + public: + + condition_8a_wrapper(){} + + //Compiler-generated destructor is OK + //~condition_8a_wrapper(){} + + ConditionMembers & get_members() + { return m_data; } + + const ConditionMembers & get_members() const + { return m_data; } + + void notify_one() + { algo_type::signal(m_data, false); } + + void notify_all() + { algo_type::signal(m_data, true); } + + template + void wait(L& lock) + { + if (!lock) + throw lock_exception(); + algo_type::wait(m_data, lock, false, boost::posix_time::ptime()); + } + + template + void wait(L& lock, Pr pred) + { + if (!lock) + throw lock_exception(); + + while (!pred()) + algo_type::wait(m_data, lock, false, boost::posix_time::ptime()); + } + + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { + if (!lock) + throw lock_exception(); + return algo_type::wait(m_data, lock, true, abs_time); + } + + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { + if (!lock) + throw lock_exception(); + while (!pred()){ + if (!algo_type::wait(m_data, lock, true, abs_time)) + return pred(); + } + return true; + } +}; + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP diff --git a/libraries/boost/boost/interprocess/sync/detail/condition_any_algorithm.hpp b/libraries/boost/boost/interprocess/sync/detail/condition_any_algorithm.hpp new file mode 100644 index 000000000..6e94a8482 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/detail/condition_any_algorithm.hpp @@ -0,0 +1,224 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP +#define BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// +// Condition variable 'any' (able to use any type of external mutex) +// +// The code is based on Howard E. Hinnant's ISO C++ N2406 paper. +// Many thanks to Howard for his support and comments. +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +// Required interface for ConditionAnyMembers +// class ConditionAnyMembers +// { +// typedef implementation_defined mutex_type; +// typedef implementation_defined condvar_type; +// +// condvar &get_condvar() +// mutex_type &get_mutex() +// }; +// +// Must be initialized as following +// +// get_condvar() [no threads blocked] +// get_mutex() [unlocked] + +template +class condition_any_algorithm +{ + private: + condition_any_algorithm(); + ~condition_any_algorithm(); + condition_any_algorithm(const condition_any_algorithm &); + condition_any_algorithm &operator=(const condition_any_algorithm &); + + typedef typename ConditionAnyMembers::mutex_type mutex_type; + typedef typename ConditionAnyMembers::condvar_type condvar_type; + + template + static void do_wait(ConditionAnyMembers &data, Lock& lock); + + template + static bool do_timed_wait(ConditionAnyMembers &data, Lock& lock, const boost::posix_time::ptime &abs_time); + + public: + template + static bool wait ( ConditionAnyMembers &data, Lock &mut + , bool timeout_enabled, const boost::posix_time::ptime &abs_time); + static void signal( ConditionAnyMembers &data, bool broadcast); +}; + +template +void condition_any_algorithm::signal(ConditionAnyMembers &data, bool broadcast) +{ + scoped_lock internal_lock(data.get_mutex()); + if(broadcast){ + data.get_condvar().notify_all(); + } + else{ + data.get_condvar().notify_one(); + } +} + +template +template +bool condition_any_algorithm::wait + ( ConditionAnyMembers &data + , Lock &lock + , bool tout_enabled + , const boost::posix_time::ptime &abs_time) +{ + if(tout_enabled){ + return condition_any_algorithm::do_timed_wait(data, lock, abs_time); + } + else{ + condition_any_algorithm::do_wait(data, lock); + return true; + } +} + +template +template +void condition_any_algorithm::do_wait + (ConditionAnyMembers &data, Lock& lock) +{ + //lock internal before unlocking external to avoid race with a notifier + scoped_lock internal_lock(data.get_mutex()); + { + lock_inverter inverted_lock(lock); + scoped_lock > external_unlock(inverted_lock); + { //unlock internal first to avoid deadlock with near simultaneous waits + scoped_lock internal_unlock; + internal_lock.swap(internal_unlock); + data.get_condvar().wait(internal_unlock); + } + } +} + +template +template +bool condition_any_algorithm::do_timed_wait + (ConditionAnyMembers &data, Lock& lock, const boost::posix_time::ptime &abs_time) +{ + //lock internal before unlocking external to avoid race with a notifier + scoped_lock internal_lock(data.get_mutex()); + { + //Unlock external lock and program for relock + lock_inverter inverted_lock(lock); + scoped_lock > external_unlock(inverted_lock); + { //unlock internal first to avoid deadlock with near simultaneous waits + scoped_lock internal_unlock; + internal_lock.swap(internal_unlock); + return data.get_condvar().timed_wait(internal_unlock, abs_time); + } + } +} + + +template +class condition_any_wrapper +{ + //Non-copyable + condition_any_wrapper(const condition_any_wrapper &); + condition_any_wrapper &operator=(const condition_any_wrapper &); + + ConditionAnyMembers m_data; + typedef ipcdetail::condition_any_algorithm algo_type; + + public: + + condition_any_wrapper(){} + + ~condition_any_wrapper(){} + + ConditionAnyMembers & get_members() + { return m_data; } + + const ConditionAnyMembers & get_members() const + { return m_data; } + + void notify_one() + { algo_type::signal(m_data, false); } + + void notify_all() + { algo_type::signal(m_data, true); } + + template + void wait(L& lock) + { + if (!lock) + throw lock_exception(); + algo_type::wait(m_data, lock, false, boost::posix_time::ptime()); + } + + template + void wait(L& lock, Pr pred) + { + if (!lock) + throw lock_exception(); + + while (!pred()) + algo_type::wait(m_data, lock, false, boost::posix_time::ptime()); + } + + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { + if (!lock) + throw lock_exception(); + return algo_type::wait(m_data, lock, true, abs_time); + } + + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { + if (!lock) + throw lock_exception(); + while (!pred()){ + if (!algo_type::wait(m_data, lock, true, abs_time)) + return pred(); + } + return true; + } +}; + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP diff --git a/libraries/boost/boost/interprocess/sync/detail/locks.hpp b/libraries/boost/boost/interprocess/sync/detail/locks.hpp new file mode 100644 index 000000000..88d9c0cb4 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/detail/locks.hpp @@ -0,0 +1,101 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_LOCKS_HPP +#define BOOST_INTERPROCESS_DETAIL_LOCKS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +class internal_mutex_lock +{ + typedef void (internal_mutex_lock::*unspecified_bool_type)(); + public: + + typedef typename Lock::mutex_type::internal_mutex_type mutex_type; + + + internal_mutex_lock(Lock &l) + : l_(l) + {} + + mutex_type* mutex() const + { return l_ ? &l_.mutex()->internal_mutex() : 0; } + + void lock() { l_.lock(); } + + void unlock() { l_.unlock(); } + + operator unspecified_bool_type() const + { return l_ ? &internal_mutex_lock::lock : 0; } + + private: + Lock &l_; +}; + +template +class lock_inverter +{ + Lock &l_; + public: + lock_inverter(Lock &l) + : l_(l) + {} + void lock() { l_.unlock(); } + void unlock() { l_.lock(); } +}; + +template +class lock_to_sharable +{ + Lock &l_; + + public: + explicit lock_to_sharable(Lock &l) + : l_(l) + {} + void lock() { l_.lock_sharable(); } + bool try_lock(){ return l_.try_lock_sharable(); } + void unlock() { l_.unlock_sharable(); } +}; + +template +class lock_to_wait +{ + Lock &l_; + + public: + explicit lock_to_wait(Lock &l) + : l_(l) + {} + void lock() { l_.wait(); } + bool try_lock(){ return l_.try_wait(); } +}; + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_LOCKS_HPP diff --git a/libraries/boost/boost/interprocess/sync/file_lock.hpp b/libraries/boost/boost/interprocess/sync/file_lock.hpp new file mode 100644 index 000000000..a488b5ba5 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/file_lock.hpp @@ -0,0 +1,237 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_FILE_LOCK_HPP +#define BOOST_INTERPROCESS_FILE_LOCK_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes a class that wraps file locking capabilities. + +namespace boost { +namespace interprocess { + + +//!A file lock, is a mutual exclusion utility similar to a mutex using a +//!file. A file lock has sharable and exclusive locking capabilities and +//!can be used with scoped_lock and sharable_lock classes. +//!A file lock can't guarantee synchronization between threads of the same +//!process so just use file locks to synchronize threads from different processes. +class file_lock +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + BOOST_MOVABLE_BUT_NOT_COPYABLE(file_lock) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructs an empty file mapping. + //!Does not throw + file_lock() + : m_file_hnd(file_handle_t(ipcdetail::invalid_file())) + {} + + //!Opens a file lock. Throws interprocess_exception if the file does not + //!exist or there are no operating system resources. + file_lock(const char *name); + + //!Moves the ownership of "moved"'s file mapping object to *this. + //!After the call, "moved" does not represent any file mapping object. + //!Does not throw + file_lock(BOOST_RV_REF(file_lock) moved) + : m_file_hnd(file_handle_t(ipcdetail::invalid_file())) + { this->swap(moved); } + + //!Moves the ownership of "moved"'s file mapping to *this. + //!After the call, "moved" does not represent any file mapping. + //!Does not throw + file_lock &operator=(BOOST_RV_REF(file_lock) moved) + { + file_lock tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Closes a file lock. Does not throw. + ~file_lock(); + + //!Swaps two file_locks. + //!Does not throw. + void swap(file_lock &other) + { + file_handle_t tmp = m_file_hnd; + m_file_hnd = other.m_file_hnd; + other.m_file_hnd = tmp; + } + + //Exclusive locking + + //!Effects: The calling thread tries to obtain exclusive ownership of the mutex, + //! and if another thread has exclusive, or sharable ownership of + //! the mutex, it waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! without waiting. If no other thread has exclusive, or sharable + //! ownership of the mutex this succeeds. + //!Returns: If it can acquire exclusive ownership immediately returns true. + //! If it has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! waiting if necessary until no other thread has exclusive, or sharable + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The calling thread releases the exclusive ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock(); + + //Sharable locking + + //!Effects: The calling thread tries to obtain sharable ownership of the mutex, + //! and if another thread has exclusive ownership of the mutex, waits until + //! it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! without waiting. If no other thread has exclusive ownership of the + //! mutex this succeeds. + //!Returns: If it can acquire sharable ownership immediately returns true. If it + //! has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! waiting if necessary until no other thread has exclusive ownership of + //! the mutex or abs_time is reached. + //!Returns: If acquires sharable ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock_sharable(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The calling thread releases the sharable ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_sharable(); + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + file_handle_t m_file_hnd; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +inline file_lock::file_lock(const char *name) +{ + m_file_hnd = ipcdetail::open_existing_file(name, read_write); + + if(m_file_hnd == ipcdetail::invalid_file()){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } +} + +inline file_lock::~file_lock() +{ + if(m_file_hnd != ipcdetail::invalid_file()){ + ipcdetail::close_file(m_file_hnd); + m_file_hnd = ipcdetail::invalid_file(); + } +} + +inline void file_lock::lock() +{ + if(!ipcdetail::acquire_file_lock(m_file_hnd)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } +} + +inline bool file_lock::try_lock() +{ + bool result; + if(!ipcdetail::try_acquire_file_lock(m_file_hnd, result)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + return result; +} + +inline bool file_lock::timed_lock(const boost::posix_time::ptime &abs_time) +{ return ipcdetail::try_based_timed_lock(*this, abs_time); } + +inline void file_lock::unlock() +{ + if(!ipcdetail::release_file_lock(m_file_hnd)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } +} + +inline void file_lock::lock_sharable() +{ + if(!ipcdetail::acquire_file_lock_sharable(m_file_hnd)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } +} + +inline bool file_lock::try_lock_sharable() +{ + bool result; + if(!ipcdetail::try_acquire_file_lock_sharable(m_file_hnd, result)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + return result; +} + +inline bool file_lock::timed_lock_sharable(const boost::posix_time::ptime &abs_time) +{ + ipcdetail::lock_to_sharable lsh(*this); + return ipcdetail::try_based_timed_lock(lsh, abs_time); +} + +inline void file_lock::unlock_sharable() +{ + if(!ipcdetail::release_file_lock_sharable(m_file_hnd)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } +} + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_FILE_LOCK_HPP diff --git a/libraries/boost/boost/interprocess/sync/interprocess_condition.hpp b/libraries/boost/boost/interprocess/sync/interprocess_condition.hpp new file mode 100644 index 000000000..c98ece882 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/interprocess_condition.hpp @@ -0,0 +1,164 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONDITION_HPP +#define BOOST_INTERPROCESS_CONDITION_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#include +#include + +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) + #include + #define BOOST_INTERPROCESS_USE_POSIX +//Experimental... +#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + #include + #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION +#endif + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!\file +//!Describes process-shared variables interprocess_condition class + +namespace boost { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace posix_time +{ class ptime; } + +#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace interprocess { + +class named_condition; + +//!This class is a condition variable that can be placed in shared memory or +//!memory mapped files. +//!Destroys the object of type std::condition_variable_any +//! +//!Unlike std::condition_variable in C++11, it is NOT safe to invoke the destructor if all +//!threads have been only notified. It is required that they have exited their respective wait +//!functions. +class interprocess_condition +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + interprocess_condition(const interprocess_condition &); + interprocess_condition &operator=(const interprocess_condition &); + friend class named_condition; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Constructs a interprocess_condition. On error throws interprocess_exception. + interprocess_condition() + {} + + //!Destroys *this + //!liberating system resources. + ~interprocess_condition() + {} + + //!If there is a thread waiting on *this, change that + //!thread's state to ready. Otherwise there is no effect. + void notify_one() + { m_condition.notify_one(); } + + //!Change the state of all threads waiting on *this to ready. + //!If there are no waiting threads, notify_all() has no effect. + void notify_all() + { m_condition.notify_all(); } + + //!Releases the lock on the interprocess_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), and then reacquires the lock. + template + void wait(L& lock) + { + ipcdetail::internal_mutex_lock internal_lock(lock); + m_condition.wait(internal_lock); + } + + //!The same as: + //!while (!pred()) wait(lock) + template + void wait(L& lock, Pr pred) + { + ipcdetail::internal_mutex_lock internal_lock(lock); + m_condition.wait(internal_lock, pred); + } + + //!Releases the lock on the interprocess_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), or until time abs_time is reached, + //!and then reacquires the lock. + //!Returns: false if time abs_time is reached, otherwise true. + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { + ipcdetail::internal_mutex_lock internal_lock(lock); + return m_condition.timed_wait(internal_lock, abs_time); + } + + //!The same as: while (!pred()) { + //! if (!timed_wait(lock, abs_time)) return pred(); + //! } return true; + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { + ipcdetail::internal_mutex_lock internal_lock(lock); + return m_condition.timed_wait(internal_lock, abs_time, pred); + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + private: + #if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) + #undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION + ipcdetail::spin_condition m_condition; + #elif defined(BOOST_INTERPROCESS_USE_POSIX) + #undef BOOST_INTERPROCESS_USE_POSIX + ipcdetail::posix_condition m_condition; + #elif defined(BOOST_INTERPROCESS_USE_WINDOWS) + #undef BOOST_INTERPROCESS_USE_WINDOWS + ipcdetail::windows_condition m_condition; + #else + #error "Unknown platform for interprocess_mutex" + #endif + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} //namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_CONDITION_HPP diff --git a/libraries/boost/boost/interprocess/sync/interprocess_condition_any.hpp b/libraries/boost/boost/interprocess/sync/interprocess_condition_any.hpp new file mode 100644 index 000000000..899fd1d40 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/interprocess_condition_any.hpp @@ -0,0 +1,137 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONDITION_ANY_HPP +#define BOOST_INTERPROCESS_CONDITION_ANY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#include +#include + +#include +#include +#include +#include +#include + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!\file +//!Describes process-shared variables interprocess_condition_any class + +namespace boost { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace posix_time +{ class ptime; } + +#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace interprocess { + +//!This class is a condition variable that can be placed in shared memory or +//!memory mapped files. +//! +//!The interprocess_condition_any class is a generalization of interprocess_condition. +//!Whereas interprocess_condition works only on Locks with mutex_type == interprocess_mutex +//!interprocess_condition_any can operate on any user-defined lock that meets the BasicLockable +//!requirements (lock()/unlock() member functions). +//! +//!Unlike std::condition_variable_any in C++11, it is NOT safe to invoke the destructor if all +//!threads have been only notified. It is required that they have exited their respective wait +//!functions. +class interprocess_condition_any +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + interprocess_condition_any(const interprocess_condition_any &); + interprocess_condition_any &operator=(const interprocess_condition_any &); + + class members + { + public: + typedef interprocess_condition condvar_type; + typedef interprocess_mutex mutex_type; + + condvar_type &get_condvar() { return m_cond; } + mutex_type &get_mutex() { return m_mut; } + + private: + condvar_type m_cond; + mutex_type m_mut; + }; + + ipcdetail::condition_any_wrapper m_cond; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + //!Constructs a interprocess_condition_any. On error throws interprocess_exception. + interprocess_condition_any(){} + + //!Destroys *this + //!liberating system resources. + ~interprocess_condition_any(){} + + //!If there is a thread waiting on *this, change that + //!thread's state to ready. Otherwise there is no effect. + void notify_one() + { m_cond.notify_one(); } + + //!Change the state of all threads waiting on *this to ready. + //!If there are no waiting threads, notify_all() has no effect. + void notify_all() + { m_cond.notify_all(); } + + //!Releases the lock on the interprocess_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), and then reacquires the lock. + template + void wait(L& lock) + { m_cond.wait(lock); } + + //!The same as: + //!while (!pred()) wait(lock) + template + void wait(L& lock, Pr pred) + { m_cond.wait(lock, pred); } + + //!Releases the lock on the interprocess_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), or until time abs_time is reached, + //!and then reacquires the lock. + //!Returns: false if time abs_time is reached, otherwise true. + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { return m_cond.timed_wait(lock, abs_time); } + + //!The same as: while (!pred()) { + //! if (!timed_wait(lock, abs_time)) return pred(); + //! } return true; + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { return m_cond.timed_wait(lock, abs_time, pred); } +}; + +} //namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_CONDITION_ANY_HPP diff --git a/libraries/boost/boost/interprocess/sync/interprocess_mutex.hpp b/libraries/boost/boost/interprocess/sync/interprocess_mutex.hpp new file mode 100644 index 000000000..8bfc02c15 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/interprocess_mutex.hpp @@ -0,0 +1,188 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// Parts of the pthread code come from Boost Threads code. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MUTEX_HPP +#define BOOST_INTERPROCESS_MUTEX_HPP + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include + +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) + #include + #define BOOST_INTERPROCESS_USE_POSIX +//Experimental... +#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + #include + #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION + +namespace boost { +namespace interprocess { +namespace ipcdetail{ +namespace robust_emulation_helpers { + +template +class mutex_traits; + +}}}} + +#endif + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!\file +//!Describes a mutex class that can be placed in memory shared by +//!several processes. + +namespace boost { +namespace interprocess { + +class interprocess_condition; + +//!Wraps a interprocess_mutex that can be placed in shared memory and can be +//!shared between processes. Allows timed lock tries +class interprocess_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + interprocess_mutex(const interprocess_mutex &); + interprocess_mutex &operator=(const interprocess_mutex &); + friend class interprocess_condition; + + public: + #if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION) + #undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION + typedef ipcdetail::spin_mutex internal_mutex_type; + private: + friend class ipcdetail::robust_emulation_helpers::mutex_traits; + void take_ownership(){ m_mutex.take_ownership(); } + public: + #elif defined(BOOST_INTERPROCESS_USE_POSIX) + #undef BOOST_INTERPROCESS_USE_POSIX + typedef ipcdetail::posix_mutex internal_mutex_type; + #elif defined(BOOST_INTERPROCESS_USE_WINDOWS) + #undef BOOST_INTERPROCESS_USE_WINDOWS + typedef ipcdetail::windows_mutex internal_mutex_type; + #else + #error "Unknown platform for interprocess_mutex" + #endif + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + //!Constructor. + //!Throws interprocess_exception on error. + interprocess_mutex(); + + //!Destructor. If any process uses the mutex after the destructor is called + //!the result is undefined. Does not throw. + ~interprocess_mutex(); + + //!Effects: The calling thread tries to obtain ownership of the mutex, and + //! if another thread has ownership of the mutex, it waits until it can + //! obtain the ownership. If a thread takes ownership of the mutex the + //! mutex must be unlocked by the same mutex. + //!Throws: interprocess_exception on error. + void lock(); + + //!Effects: The calling thread tries to obtain ownership of the mutex, and + //! if another thread has ownership of the mutex returns immediately. + //!Returns: If the thread acquires ownership of the mutex, returns true, if + //! the another thread has ownership of the mutex, returns false. + //!Throws: interprocess_exception on error. + bool try_lock(); + + //!Effects: The calling thread will try to obtain exclusive ownership of the + //! mutex if it can do so in until the specified time is reached. If the + //! mutex supports recursive locking, the mutex must be unlocked the same + //! number of times it is locked. + //!Returns: If the thread acquires ownership of the mutex, returns true, if + //! the timeout expires returns false. + //!Throws: interprocess_exception on error. + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Effects: The calling thread releases the exclusive ownership of the mutex. + //!Throws: interprocess_exception on error. + void unlock(); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + internal_mutex_type &internal_mutex() + { return m_mutex; } + + const internal_mutex_type &internal_mutex() const + { return m_mutex; } + + private: + internal_mutex_type m_mutex; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} //namespace interprocess { +} //namespace boost { + + +namespace boost { +namespace interprocess { + +inline interprocess_mutex::interprocess_mutex(){} + +inline interprocess_mutex::~interprocess_mutex(){} + +inline void interprocess_mutex::lock() +{ + #ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING + boost::posix_time::ptime wait_time + = microsec_clock::universal_time() + + boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS); + if (!m_mutex.timed_lock(wait_time)) + { + throw interprocess_exception(timeout_when_locking_error + , "Interprocess mutex timeout when locking. Possible deadlock: " + "owner died without unlocking?"); + } + #else + m_mutex.lock(); + #endif +} + +inline bool interprocess_mutex::try_lock() +{ return m_mutex.try_lock(); } + +inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return m_mutex.timed_lock(abs_time); } + +inline void interprocess_mutex::unlock() +{ m_mutex.unlock(); } + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/libraries/boost/boost/interprocess/sync/interprocess_recursive_mutex.hpp new file mode 100644 index 000000000..e38257493 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -0,0 +1,181 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// Parts of the pthread code come from Boost Threads code: +// +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include + +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \ + (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined (BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES)) + #include + #define BOOST_INTERPROCESS_USE_POSIX +//Experimental... +#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + #include + #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION +#endif + +#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) +namespace boost { +namespace interprocess { +namespace ipcdetail{ +namespace robust_emulation_helpers { + +template +class mutex_traits; + +}}}} + +#endif + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!\file +//!Describes interprocess_recursive_mutex and shared_recursive_try_mutex classes + +namespace boost { +namespace interprocess { + +//!Wraps a interprocess_mutex that can be placed in shared memory and can be +//!shared between processes. Allows several locking calls by the same +//!process. Allows timed lock tries +class interprocess_recursive_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + interprocess_recursive_mutex(const interprocess_recursive_mutex &); + interprocess_recursive_mutex &operator=(const interprocess_recursive_mutex &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + //!Constructor. + //!Throws interprocess_exception on error. + interprocess_recursive_mutex(); + + //!Destructor. If any process uses the mutex after the destructor is called + //!the result is undefined. Does not throw. + ~interprocess_recursive_mutex(); + + //!Effects: The calling thread tries to obtain ownership of the mutex, and + //! if another thread has ownership of the mutex, it waits until it can + //! obtain the ownership. If a thread takes ownership of the mutex the + //! mutex must be unlocked by the same mutex. The mutex must be unlocked + //! the same number of times it is locked. + //!Throws: interprocess_exception on error. + void lock(); + + //!Tries to lock the interprocess_mutex, returns false when interprocess_mutex + //!is already locked, returns true when success. The mutex must be unlocked + //!the same number of times it is locked. + //!Throws: interprocess_exception if a severe error is found + bool try_lock(); + + //!Tries to lock the interprocess_mutex, if interprocess_mutex can't be locked before + //!abs_time time, returns false. The mutex must be unlocked + //! the same number of times it is locked. + //!Throws: interprocess_exception if a severe error is found + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Effects: The calling thread releases the exclusive ownership of the mutex. + //! If the mutex supports recursive locking, the mutex must be unlocked the + //! same number of times it is locked. + //!Throws: interprocess_exception on error. + void unlock(); + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + + #if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) + #undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION + void take_ownership(){ mutex.take_ownership(); } + friend class ipcdetail::robust_emulation_helpers::mutex_traits; + ipcdetail::spin_recursive_mutex mutex; + #elif defined(BOOST_INTERPROCESS_USE_POSIX) + #undef BOOST_INTERPROCESS_USE_POSIX + ipcdetail::posix_recursive_mutex mutex; + #elif defined(BOOST_INTERPROCESS_USE_WINDOWS) + #undef BOOST_INTERPROCESS_USE_WINDOWS + ipcdetail::windows_recursive_mutex mutex; + #else + #error "Unknown platform for interprocess_mutex" + #endif + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} //namespace interprocess { +} //namespace boost { + +namespace boost { +namespace interprocess { + +inline interprocess_recursive_mutex::interprocess_recursive_mutex(){} + +inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){} + +inline void interprocess_recursive_mutex::lock() +{ + #ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING + boost::posix_time::ptime wait_time + = microsec_clock::universal_time() + + boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS); + if (!mutex.timed_lock(wait_time)){ + throw interprocess_exception(timeout_when_locking_error, "Interprocess mutex timeout when locking. Possible deadlock: owner died without unlocking?"); + } + #else + mutex.lock(); + #endif +} + +inline bool interprocess_recursive_mutex::try_lock() +{ return mutex.try_lock(); } + +inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return mutex.timed_lock(abs_time); } + +inline void interprocess_recursive_mutex::unlock() +{ mutex.unlock(); } + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/interprocess_semaphore.hpp b/libraries/boost/boost/interprocess/sync/interprocess_semaphore.hpp new file mode 100644 index 000000000..bb828dfb0 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/interprocess_semaphore.hpp @@ -0,0 +1,149 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SEMAPHORE_HPP +#define BOOST_INTERPROCESS_SEMAPHORE_HPP + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include + +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \ + (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined(BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES)) + #include + #define BOOST_INTERPROCESS_USE_POSIX +//Experimental... +#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + #include + #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION +#endif + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!\file +//!Describes a interprocess_semaphore class for inter-process synchronization + +namespace boost { +namespace interprocess { + +//!Wraps a interprocess_semaphore that can be placed in shared memory and can be +//!shared between processes. Allows timed lock tries +class interprocess_semaphore +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + interprocess_semaphore(const interprocess_semaphore &); + interprocess_semaphore &operator=(const interprocess_semaphore &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + //!Creates a interprocess_semaphore with the given initial count. + //!interprocess_exception if there is an error.*/ + interprocess_semaphore(unsigned int initialCount); + + //!Destroys the interprocess_semaphore. + //!Does not throw + ~interprocess_semaphore(); + + //!Increments the interprocess_semaphore count. If there are processes/threads blocked waiting + //!for the interprocess_semaphore, then one of these processes will return successfully from + //!its wait function. If there is an error an interprocess_exception exception is thrown. + void post(); + + //!Decrements the interprocess_semaphore. If the interprocess_semaphore value is not greater than zero, + //!then the calling process/thread blocks until it can decrement the counter. + //!If there is an error an interprocess_exception exception is thrown. + void wait(); + + //!Decrements the interprocess_semaphore if the interprocess_semaphore's value is greater than zero + //!and returns true. If the value is not greater than zero returns false. + //!If there is an error an interprocess_exception exception is thrown. + bool try_wait(); + + //!Decrements the interprocess_semaphore if the interprocess_semaphore's value is greater + //!than zero and returns true. Otherwise, waits for the interprocess_semaphore + //!to the posted or the timeout expires. If the timeout expires, the + //!function returns false. If the interprocess_semaphore is posted the function + //!returns true. If there is an error throws sem_exception + bool timed_wait(const boost::posix_time::ptime &abs_time); + + //!Returns the interprocess_semaphore count +// int get_count() const; + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + #if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION) + #undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION + ipcdetail::spin_semaphore m_sem; + #elif defined(BOOST_INTERPROCESS_USE_WINDOWS) + #undef BOOST_INTERPROCESS_USE_WINDOWS + ipcdetail::windows_semaphore m_sem; + #else + #undef BOOST_INTERPROCESS_USE_POSIX + ipcdetail::posix_semaphore m_sem; + #endif //#if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} //namespace interprocess { +} //namespace boost { + +namespace boost { +namespace interprocess { + +inline interprocess_semaphore::interprocess_semaphore(unsigned int initialCount) + : m_sem(initialCount) +{} + +inline interprocess_semaphore::~interprocess_semaphore(){} + +inline void interprocess_semaphore::wait() +{ + #ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING + boost::posix_time::ptime wait_time + = microsec_clock::universal_time() + + boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS); + if (!m_sem.timed_wait(wait_time)) + { + throw interprocess_exception(timeout_when_waiting_error, "Interprocess semaphore timeout when waiting. Possible deadlock: owner died without posting?"); + } + #else + m_sem.wait(); + #endif +} +inline bool interprocess_semaphore::try_wait() +{ return m_sem.try_wait(); } + +inline bool interprocess_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +{ return m_sem.timed_wait(abs_time); } + +inline void interprocess_semaphore::post() +{ m_sem.post(); } + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_SEMAPHORE_HPP diff --git a/libraries/boost/boost/interprocess/sync/interprocess_sharable_mutex.hpp b/libraries/boost/boost/interprocess/sync/interprocess_sharable_mutex.hpp new file mode 100644 index 000000000..59823b0c9 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/interprocess_sharable_mutex.hpp @@ -0,0 +1,349 @@ +////////////////////////////////////////////////////////////////////////////// +// Code based on Howard Hinnant's shared_mutex class +// +// (C) Copyright Howard Hinnant 2007-2010. Distributed under the Boost +// Software License, Version 1.0. (see http://www.boost.org/LICENSE_1_0.txt) +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SHARABLE_MUTEX_HPP +#define BOOST_INTERPROCESS_SHARABLE_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + + +//!\file +//!Describes interprocess_sharable_mutex class + +namespace boost { +namespace interprocess { + +//!Wraps a interprocess_sharable_mutex that can be placed in shared memory and can be +//!shared between processes. Allows timed lock tries +class interprocess_sharable_mutex +{ + //Non-copyable + interprocess_sharable_mutex(const interprocess_sharable_mutex &); + interprocess_sharable_mutex &operator=(const interprocess_sharable_mutex &); + + friend class interprocess_condition; + public: + + //!Constructs the sharable lock. + //!Throws interprocess_exception on error. + interprocess_sharable_mutex(); + + //!Destroys the sharable lock. + //!Does not throw. + ~interprocess_sharable_mutex(); + + //Exclusive locking + + //!Effects: The calling thread tries to obtain exclusive ownership of the mutex, + //! and if another thread has exclusive or sharable ownership of + //! the mutex, it waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! without waiting. If no other thread has exclusive or sharable + //! ownership of the mutex this succeeds. + //!Returns: If it can acquire exclusive ownership immediately returns true. + //! If it has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! waiting if necessary until no other thread has exclusive or sharable + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The calling thread releases the exclusive ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock(); + + //Sharable locking + + //!Effects: The calling thread tries to obtain sharable ownership of the mutex, + //! and if another thread has exclusive ownership of the mutex, + //! waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! without waiting. If no other thread has exclusive ownership + //! of the mutex this succeeds. + //!Returns: If it can acquire sharable ownership immediately returns true. If it + //! has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! waiting if necessary until no other thread has exclusive + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires sharable ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock_sharable(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The calling thread releases the sharable ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_sharable(); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef scoped_lock scoped_lock_t; + + //Pack all the control data in a word to be able + //to use atomic instructions in the future + struct control_word_t + { + unsigned exclusive_in : 1; + unsigned num_shared : sizeof(unsigned)*CHAR_BIT-1; + } m_ctrl; + + interprocess_mutex m_mut; + interprocess_condition m_first_gate; + interprocess_condition m_second_gate; + + private: + //Rollback structures for exceptions or failure return values + struct exclusive_rollback + { + exclusive_rollback(control_word_t &ctrl + ,interprocess_condition &first_gate) + : mp_ctrl(&ctrl), m_first_gate(first_gate) + {} + + void release() + { mp_ctrl = 0; } + + ~exclusive_rollback() + { + if(mp_ctrl){ + mp_ctrl->exclusive_in = 0; + m_first_gate.notify_all(); + } + } + control_word_t *mp_ctrl; + interprocess_condition &m_first_gate; + }; + + template + struct base_constants_t + { + static const unsigned max_readers + = ~(unsigned(1) << (sizeof(unsigned)*CHAR_BIT-1)); + }; + typedef base_constants_t<0> constants; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +template +const unsigned interprocess_sharable_mutex::base_constants_t::max_readers; + +inline interprocess_sharable_mutex::interprocess_sharable_mutex() +{ + this->m_ctrl.exclusive_in = 0; + this->m_ctrl.num_shared = 0; +} + +inline interprocess_sharable_mutex::~interprocess_sharable_mutex() +{} + +inline void interprocess_sharable_mutex::lock() +{ + scoped_lock_t lck(m_mut); + + //The exclusive lock must block in the first gate + //if an exclusive lock has been acquired + while (this->m_ctrl.exclusive_in){ + this->m_first_gate.wait(lck); + } + + //Mark that exclusive lock has been acquired + this->m_ctrl.exclusive_in = 1; + + //Prepare rollback + exclusive_rollback rollback(this->m_ctrl, this->m_first_gate); + + //Now wait until all readers are gone + while (this->m_ctrl.num_shared){ + this->m_second_gate.wait(lck); + } + rollback.release(); +} + +inline bool interprocess_sharable_mutex::try_lock() +{ + scoped_lock_t lck(m_mut, try_to_lock); + + //If we can't lock or any has there is any exclusive + //or sharable mark return false; + if(!lck.owns() + || this->m_ctrl.exclusive_in + || this->m_ctrl.num_shared){ + return false; + } + this->m_ctrl.exclusive_in = 1; + return true; +} + +inline bool interprocess_sharable_mutex::timed_lock + (const boost::posix_time::ptime &abs_time) +{ + scoped_lock_t lck(m_mut, abs_time); + if(!lck.owns()) return false; + + //The exclusive lock must block in the first gate + //if an exclusive lock has been acquired + while (this->m_ctrl.exclusive_in){ + //Mutexes and condvars handle just fine infinite abs_times + //so avoid checking it here + if(!this->m_first_gate.timed_wait(lck, abs_time)){ + if(this->m_ctrl.exclusive_in){ + return false; + } + break; + } + } + + //Mark that exclusive lock has been acquired + this->m_ctrl.exclusive_in = 1; + + //Prepare rollback + exclusive_rollback rollback(this->m_ctrl, this->m_first_gate); + + //Now wait until all readers are gone + while (this->m_ctrl.num_shared){ + //Mutexes and condvars handle just fine infinite abs_times + //so avoid checking it here + if(!this->m_second_gate.timed_wait(lck, abs_time)){ + if(this->m_ctrl.num_shared){ + return false; + } + break; + } + } + rollback.release(); + return true; +} + +inline void interprocess_sharable_mutex::unlock() +{ + scoped_lock_t lck(m_mut); + this->m_ctrl.exclusive_in = 0; + this->m_first_gate.notify_all(); +} + +//Sharable locking + +inline void interprocess_sharable_mutex::lock_sharable() +{ + scoped_lock_t lck(m_mut); + + //The sharable lock must block in the first gate + //if an exclusive lock has been acquired + //or there are too many sharable locks + while(this->m_ctrl.exclusive_in + || this->m_ctrl.num_shared == constants::max_readers){ + this->m_first_gate.wait(lck); + } + + //Increment sharable count + ++this->m_ctrl.num_shared; +} + +inline bool interprocess_sharable_mutex::try_lock_sharable() +{ + scoped_lock_t lck(m_mut, try_to_lock); + + //The sharable lock must fail + //if an exclusive lock has been acquired + //or there are too many sharable locks + if(!lck.owns() + || this->m_ctrl.exclusive_in + || this->m_ctrl.num_shared == constants::max_readers){ + return false; + } + + //Increment sharable count + ++this->m_ctrl.num_shared; + return true; +} + +inline bool interprocess_sharable_mutex::timed_lock_sharable + (const boost::posix_time::ptime &abs_time) +{ + scoped_lock_t lck(m_mut, abs_time); + if(!lck.owns()) return false; + + //The sharable lock must block in the first gate + //if an exclusive lock has been acquired + //or there are too many sharable locks + while (this->m_ctrl.exclusive_in + || this->m_ctrl.num_shared == constants::max_readers){ + //Mutexes and condvars handle just fine infinite abs_times + //so avoid checking it here + if(!this->m_first_gate.timed_wait(lck, abs_time)){ + if(this->m_ctrl.exclusive_in + || this->m_ctrl.num_shared == constants::max_readers){ + return false; + } + break; + } + } + + //Increment sharable count + ++this->m_ctrl.num_shared; + return true; +} + +inline void interprocess_sharable_mutex::unlock_sharable() +{ + scoped_lock_t lck(m_mut); + //Decrement sharable count + --this->m_ctrl.num_shared; + if (this->m_ctrl.num_shared == 0){ + this->m_second_gate.notify_one(); + } + //Check if there are blocked sharables because of + //there were too many sharables + else if(this->m_ctrl.num_shared == (constants::max_readers-1)){ + this->m_first_gate.notify_all(); + } +} + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_SHARABLE_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/interprocess_upgradable_mutex.hpp b/libraries/boost/boost/interprocess/sync/interprocess_upgradable_mutex.hpp new file mode 100644 index 000000000..15767d2c5 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/interprocess_upgradable_mutex.hpp @@ -0,0 +1,677 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Code based on Howard Hinnant's upgrade_mutex class +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP +#define BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + + +//!\file +//!Describes interprocess_upgradable_mutex class + +namespace boost { +namespace interprocess { + +//!Wraps a interprocess_upgradable_mutex that can be placed in shared memory and can be +//!shared between processes. Allows timed lock tries +class interprocess_upgradable_mutex +{ + //Non-copyable + interprocess_upgradable_mutex(const interprocess_upgradable_mutex &); + interprocess_upgradable_mutex &operator=(const interprocess_upgradable_mutex &); + + friend class interprocess_condition; + public: + + //!Constructs the upgradable lock. + //!Throws interprocess_exception on error. + interprocess_upgradable_mutex(); + + //!Destroys the upgradable lock. + //!Does not throw. + ~interprocess_upgradable_mutex(); + + //Exclusive locking + + //!Effects: The calling thread tries to obtain exclusive ownership of the mutex, + //! and if another thread has exclusive, sharable or upgradable ownership of + //! the mutex, it waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! without waiting. If no other thread has exclusive, sharable or upgradable + //! ownership of the mutex this succeeds. + //!Returns: If it can acquire exclusive ownership immediately returns true. + //! If it has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! waiting if necessary until no other thread has exclusive, sharable or + //! upgradable ownership of the mutex or abs_time is reached. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The calling thread releases the exclusive ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock(); + + //Sharable locking + + //!Effects: The calling thread tries to obtain sharable ownership of the mutex, + //! and if another thread has exclusive ownership of the mutex, + //! waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! without waiting. If no other thread has exclusive ownership + //! of the mutex this succeeds. + //!Returns: If it can acquire sharable ownership immediately returns true. If it + //! has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! waiting if necessary until no other thread has exclusive + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires sharable ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock_sharable(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The calling thread releases the sharable ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_sharable(); + + //Upgradable locking + + //!Effects: The calling thread tries to obtain upgradable ownership of the mutex, + //! and if another thread has exclusive or upgradable ownership of the mutex, + //! waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock_upgradable(); + + //!Effects: The calling thread tries to acquire upgradable ownership of the mutex + //! without waiting. If no other thread has exclusive or upgradable ownership + //! of the mutex this succeeds. + //!Returns: If it can acquire upgradable ownership immediately returns true. + //! If it has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock_upgradable(); + + //!Effects: The calling thread tries to acquire upgradable ownership of the mutex + //! waiting if necessary until no other thread has exclusive or upgradable + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The calling thread releases the upgradable ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_upgradable(); + + //Demotions + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The thread atomically releases exclusive ownership and acquires + //! upgradable ownership. This operation is non-blocking. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_and_lock_upgradable(); + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The thread atomically releases exclusive ownership and acquires + //! sharable ownership. This operation is non-blocking. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_and_lock_sharable(); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and acquires + //! sharable ownership. This operation is non-blocking. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_upgradable_and_lock_sharable(); + + //Promotions + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and acquires + //! exclusive ownership. This operation will block until all threads with + //! sharable ownership release their sharable lock. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_upgradable_and_lock(); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and tries to + //! acquire exclusive ownership. This operation will fail if there are threads + //! with sharable ownership, but it will maintain upgradable ownership. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. + bool try_unlock_upgradable_and_lock(); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and tries to acquire + //! exclusive ownership, waiting if necessary until abs_time. This operation will + //! fail if there are threads with sharable ownership or timeout reaches, but it + //! will maintain upgradable ownership. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. */ + bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The thread atomically releases sharable ownership and tries to acquire + //! exclusive ownership. This operation will fail if there are threads with sharable + //! or upgradable ownership, but it will maintain sharable ownership. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. + bool try_unlock_sharable_and_lock(); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The thread atomically releases sharable ownership and tries to acquire + //! upgradable ownership. This operation will fail if there are threads with sharable + //! or upgradable ownership, but it will maintain sharable ownership. + //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. + bool try_unlock_sharable_and_lock_upgradable(); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef scoped_lock scoped_lock_t; + + //Pack all the control data in a word to be able + //to use atomic instructions in the future + struct control_word_t + { + unsigned exclusive_in : 1; + unsigned upgradable_in : 1; + unsigned num_upr_shar : sizeof(unsigned)*CHAR_BIT-2; + } m_ctrl; + + interprocess_mutex m_mut; + interprocess_condition m_first_gate; + interprocess_condition m_second_gate; + + private: + //Rollback structures for exceptions or failure return values + struct exclusive_rollback + { + exclusive_rollback(control_word_t &ctrl + ,interprocess_condition &first_gate) + : mp_ctrl(&ctrl), m_first_gate(first_gate) + {} + + void release() + { mp_ctrl = 0; } + + ~exclusive_rollback() + { + if(mp_ctrl){ + mp_ctrl->exclusive_in = 0; + m_first_gate.notify_all(); + } + } + control_word_t *mp_ctrl; + interprocess_condition &m_first_gate; + }; + + struct upgradable_to_exclusive_rollback + { + upgradable_to_exclusive_rollback(control_word_t &ctrl) + : mp_ctrl(&ctrl) + {} + + void release() + { mp_ctrl = 0; } + + ~upgradable_to_exclusive_rollback() + { + if(mp_ctrl){ + //Recover upgradable lock + mp_ctrl->upgradable_in = 1; + ++mp_ctrl->num_upr_shar; + //Execute the second half of exclusive locking + mp_ctrl->exclusive_in = 0; + } + } + control_word_t *mp_ctrl; + }; + + template + struct base_constants_t + { + static const unsigned max_readers + = ~(unsigned(3) << (sizeof(unsigned)*CHAR_BIT-2)); + }; + typedef base_constants_t<0> constants; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +template +const unsigned interprocess_upgradable_mutex::base_constants_t::max_readers; + +inline interprocess_upgradable_mutex::interprocess_upgradable_mutex() +{ + this->m_ctrl.exclusive_in = 0; + this->m_ctrl.upgradable_in = 0; + this->m_ctrl.num_upr_shar = 0; +} + +inline interprocess_upgradable_mutex::~interprocess_upgradable_mutex() +{} + +inline void interprocess_upgradable_mutex::lock() +{ + scoped_lock_t lck(m_mut); + + //The exclusive lock must block in the first gate + //if an exclusive or upgradable lock has been acquired + while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){ + this->m_first_gate.wait(lck); + } + + //Mark that exclusive lock has been acquired + this->m_ctrl.exclusive_in = 1; + + //Prepare rollback + exclusive_rollback rollback(this->m_ctrl, this->m_first_gate); + + //Now wait until all readers are gone + while (this->m_ctrl.num_upr_shar){ + this->m_second_gate.wait(lck); + } + rollback.release(); +} + +inline bool interprocess_upgradable_mutex::try_lock() +{ + scoped_lock_t lck(m_mut, try_to_lock); + + //If we can't lock or any has there is any exclusive, upgradable + //or sharable mark return false; + if(!lck.owns() + || this->m_ctrl.exclusive_in + || this->m_ctrl.num_upr_shar){ + return false; + } + this->m_ctrl.exclusive_in = 1; + return true; +} + +inline bool interprocess_upgradable_mutex::timed_lock + (const boost::posix_time::ptime &abs_time) +{ + //Mutexes and condvars handle just fine infinite abs_times + //so avoid checking it here + scoped_lock_t lck(m_mut, abs_time); + if(!lck.owns()) return false; + + //The exclusive lock must block in the first gate + //if an exclusive or upgradable lock has been acquired + while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){ + if(!this->m_first_gate.timed_wait(lck, abs_time)){ + if(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){ + return false; + } + break; + } + } + + //Mark that exclusive lock has been acquired + this->m_ctrl.exclusive_in = 1; + + //Prepare rollback + exclusive_rollback rollback(this->m_ctrl, this->m_first_gate); + + //Now wait until all readers are gone + while (this->m_ctrl.num_upr_shar){ + if(!this->m_second_gate.timed_wait(lck, abs_time)){ + if(this->m_ctrl.num_upr_shar){ + return false; + } + break; + } + } + rollback.release(); + return true; +} + +inline void interprocess_upgradable_mutex::unlock() +{ + scoped_lock_t lck(m_mut); + this->m_ctrl.exclusive_in = 0; + this->m_first_gate.notify_all(); +} + +//Upgradable locking + +inline void interprocess_upgradable_mutex::lock_upgradable() +{ + scoped_lock_t lck(m_mut); + + //The upgradable lock must block in the first gate + //if an exclusive or upgradable lock has been acquired + //or there are too many sharable locks + while(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in + || this->m_ctrl.num_upr_shar == constants::max_readers){ + this->m_first_gate.wait(lck); + } + + //Mark that upgradable lock has been acquired + //And add upgradable to the sharable count + this->m_ctrl.upgradable_in = 1; + ++this->m_ctrl.num_upr_shar; +} + +inline bool interprocess_upgradable_mutex::try_lock_upgradable() +{ + scoped_lock_t lck(m_mut, try_to_lock); + + //The upgradable lock must fail + //if an exclusive or upgradable lock has been acquired + //or there are too many sharable locks + if(!lck.owns() + || this->m_ctrl.exclusive_in + || this->m_ctrl.upgradable_in + || this->m_ctrl.num_upr_shar == constants::max_readers){ + return false; + } + + //Mark that upgradable lock has been acquired + //And add upgradable to the sharable count + this->m_ctrl.upgradable_in = 1; + ++this->m_ctrl.num_upr_shar; + return true; +} + +inline bool interprocess_upgradable_mutex::timed_lock_upgradable + (const boost::posix_time::ptime &abs_time) +{ + //Mutexes and condvars handle just fine infinite abs_times + //so avoid checking it here + scoped_lock_t lck(m_mut, abs_time); + if(!lck.owns()) return false; + + //The upgradable lock must block in the first gate + //if an exclusive or upgradable lock has been acquired + //or there are too many sharable locks + while(this->m_ctrl.exclusive_in + || this->m_ctrl.upgradable_in + || this->m_ctrl.num_upr_shar == constants::max_readers){ + if(!this->m_first_gate.timed_wait(lck, abs_time)){ + if((this->m_ctrl.exclusive_in + || this->m_ctrl.upgradable_in + || this->m_ctrl.num_upr_shar == constants::max_readers)){ + return false; + } + break; + } + } + + //Mark that upgradable lock has been acquired + //And add upgradable to the sharable count + this->m_ctrl.upgradable_in = 1; + ++this->m_ctrl.num_upr_shar; + return true; +} + +inline void interprocess_upgradable_mutex::unlock_upgradable() +{ + scoped_lock_t lck(m_mut); + //Mark that upgradable lock has been acquired + //And add upgradable to the sharable count + this->m_ctrl.upgradable_in = 0; + --this->m_ctrl.num_upr_shar; + this->m_first_gate.notify_all(); +} + +//Sharable locking + +inline void interprocess_upgradable_mutex::lock_sharable() +{ + scoped_lock_t lck(m_mut); + + //The sharable lock must block in the first gate + //if an exclusive lock has been acquired + //or there are too many sharable locks + while(this->m_ctrl.exclusive_in + || this->m_ctrl.num_upr_shar == constants::max_readers){ + this->m_first_gate.wait(lck); + } + + //Increment sharable count + ++this->m_ctrl.num_upr_shar; +} + +inline bool interprocess_upgradable_mutex::try_lock_sharable() +{ + scoped_lock_t lck(m_mut, try_to_lock); + + //The sharable lock must fail + //if an exclusive lock has been acquired + //or there are too many sharable locks + if(!lck.owns() + || this->m_ctrl.exclusive_in + || this->m_ctrl.num_upr_shar == constants::max_readers){ + return false; + } + + //Increment sharable count + ++this->m_ctrl.num_upr_shar; + return true; +} + +inline bool interprocess_upgradable_mutex::timed_lock_sharable + (const boost::posix_time::ptime &abs_time) +{ + //Mutexes and condvars handle just fine infinite abs_times + //so avoid checking it here + scoped_lock_t lck(m_mut, abs_time); + if(!lck.owns()) return false; + + //The sharable lock must block in the first gate + //if an exclusive lock has been acquired + //or there are too many sharable locks + while (this->m_ctrl.exclusive_in + || this->m_ctrl.num_upr_shar == constants::max_readers){ + if(!this->m_first_gate.timed_wait(lck, abs_time)){ + if(this->m_ctrl.exclusive_in + || this->m_ctrl.num_upr_shar == constants::max_readers){ + return false; + } + break; + } + } + + //Increment sharable count + ++this->m_ctrl.num_upr_shar; + return true; +} + +inline void interprocess_upgradable_mutex::unlock_sharable() +{ + scoped_lock_t lck(m_mut); + //Decrement sharable count + --this->m_ctrl.num_upr_shar; + if (this->m_ctrl.num_upr_shar == 0){ + this->m_second_gate.notify_one(); + } + //Check if there are blocked sharables because of + //there were too many sharables + else if(this->m_ctrl.num_upr_shar == (constants::max_readers-1)){ + this->m_first_gate.notify_all(); + } +} + +//Downgrading + +inline void interprocess_upgradable_mutex::unlock_and_lock_upgradable() +{ + scoped_lock_t lck(m_mut); + //Unmark it as exclusive + this->m_ctrl.exclusive_in = 0; + //Mark it as upgradable + this->m_ctrl.upgradable_in = 1; + //The sharable count should be 0 so increment it + this->m_ctrl.num_upr_shar = 1; + //Notify readers that they can enter + m_first_gate.notify_all(); +} + +inline void interprocess_upgradable_mutex::unlock_and_lock_sharable() +{ + scoped_lock_t lck(m_mut); + //Unmark it as exclusive + this->m_ctrl.exclusive_in = 0; + //The sharable count should be 0 so increment it + this->m_ctrl.num_upr_shar = 1; + //Notify readers that they can enter + m_first_gate.notify_all(); +} + +inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock_sharable() +{ + scoped_lock_t lck(m_mut); + //Unmark it as upgradable (we don't have to decrement count) + this->m_ctrl.upgradable_in = 0; + //Notify readers/upgradable that they can enter + m_first_gate.notify_all(); +} + +//Upgrading + +inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock() +{ + scoped_lock_t lck(m_mut); + //Simulate unlock_upgradable() without + //notifying sharables. + this->m_ctrl.upgradable_in = 0; + --this->m_ctrl.num_upr_shar; + //Execute the second half of exclusive locking + this->m_ctrl.exclusive_in = 1; + + //Prepare rollback + upgradable_to_exclusive_rollback rollback(m_ctrl); + + while (this->m_ctrl.num_upr_shar){ + this->m_second_gate.wait(lck); + } + rollback.release(); +} + +inline bool interprocess_upgradable_mutex::try_unlock_upgradable_and_lock() +{ + scoped_lock_t lck(m_mut, try_to_lock); + //Check if there are no readers + if(!lck.owns() + || this->m_ctrl.num_upr_shar != 1){ + return false; + } + //Now unlock upgradable and mark exclusive + this->m_ctrl.upgradable_in = 0; + --this->m_ctrl.num_upr_shar; + this->m_ctrl.exclusive_in = 1; + return true; +} + +inline bool interprocess_upgradable_mutex::timed_unlock_upgradable_and_lock + (const boost::posix_time::ptime &abs_time) +{ + //Mutexes and condvars handle just fine infinite abs_times + //so avoid checking it here + scoped_lock_t lck(m_mut, abs_time); + if(!lck.owns()) return false; + + //Simulate unlock_upgradable() without + //notifying sharables. + this->m_ctrl.upgradable_in = 0; + --this->m_ctrl.num_upr_shar; + //Execute the second half of exclusive locking + this->m_ctrl.exclusive_in = 1; + + //Prepare rollback + upgradable_to_exclusive_rollback rollback(m_ctrl); + + while (this->m_ctrl.num_upr_shar){ + if(!this->m_second_gate.timed_wait(lck, abs_time)){ + if(this->m_ctrl.num_upr_shar){ + return false; + } + break; + } + } + rollback.release(); + return true; +} + +inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock() +{ + scoped_lock_t lck(m_mut, try_to_lock); + + //If we can't lock or any has there is any exclusive, upgradable + //or sharable mark return false; + if(!lck.owns() + || this->m_ctrl.exclusive_in + || this->m_ctrl.upgradable_in + || this->m_ctrl.num_upr_shar != 1){ + return false; + } + this->m_ctrl.exclusive_in = 1; + this->m_ctrl.num_upr_shar = 0; + return true; +} + +inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradable() +{ + scoped_lock_t lck(m_mut, try_to_lock); + + //The upgradable lock must fail + //if an exclusive or upgradable lock has been acquired + if(!lck.owns() + || this->m_ctrl.exclusive_in + || this->m_ctrl.upgradable_in){ + return false; + } + + //Mark that upgradable lock has been acquired + this->m_ctrl.upgradable_in = 1; + return true; +} + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + + +#include + +#endif //BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/lock_options.hpp b/libraries/boost/boost/interprocess/sync/lock_options.hpp new file mode 100644 index 000000000..981ff5b6d --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/lock_options.hpp @@ -0,0 +1,63 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_LOCK_OPTIONS_HPP +#define BOOST_INTERPROCESS_LOCK_OPTIONS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +//!\file +//!Describes the lock options with associated with interprocess_mutex lock constructors. + +namespace boost { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace posix_time +{ class ptime; } + +#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace interprocess { + +//!Type to indicate to a mutex lock constructor that must not lock the mutex. +struct defer_lock_type{}; +//!Type to indicate to a mutex lock constructor that must try to lock the mutex. +struct try_to_lock_type {}; +//!Type to indicate to a mutex lock constructor that the mutex is already locked. +struct accept_ownership_type{}; + +//!An object indicating that the locking +//!must be deferred. +static const defer_lock_type defer_lock = defer_lock_type(); + +//!An object indicating that a try_lock() +//!operation must be executed. +static const try_to_lock_type try_to_lock = try_to_lock_type(); + +//!An object indicating that the ownership of lockable +//!object must be accepted by the new owner. +static const accept_ownership_type accept_ownership = accept_ownership_type(); + +} // namespace interprocess { +} // namespace boost{ + +#include + +#endif // BOOST_INTERPROCESS_LOCK_OPTIONS_HPP diff --git a/libraries/boost/boost/interprocess/sync/mutex_family.hpp b/libraries/boost/boost/interprocess/sync/mutex_family.hpp new file mode 100644 index 000000000..b136ce441 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/mutex_family.hpp @@ -0,0 +1,60 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP +#define BOOST_INTERPROCESS_MUTEX_FAMILY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include + +//!\file +//!Describes a shared interprocess_mutex family fit algorithm used to allocate objects in shared memory. + +namespace boost { + +namespace interprocess { + +//!Describes interprocess_mutex family to use with Interprocess framework +//!based on boost::interprocess synchronization objects. +struct mutex_family +{ + typedef boost::interprocess::interprocess_mutex mutex_type; + typedef boost::interprocess::interprocess_recursive_mutex recursive_mutex_type; +}; + +//!Describes interprocess_mutex family to use with Interprocess frameworks +//!based on null operation synchronization objects. +struct null_mutex_family +{ + typedef boost::interprocess::null_mutex mutex_type; + typedef boost::interprocess::null_mutex recursive_mutex_type; +}; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP + + diff --git a/libraries/boost/boost/interprocess/sync/named_condition.hpp b/libraries/boost/boost/interprocess/sync/named_condition.hpp new file mode 100644 index 000000000..6d9b7570d --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/named_condition.hpp @@ -0,0 +1,201 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NAMED_CONDITION_HPP +#define BOOST_INTERPROCESS_NAMED_CONDITION_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#else + #include +#endif + +//!\file +//!Describes a named condition class for inter-process synchronization + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +namespace ipcdetail{ class interprocess_tester; } +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//! A global condition variable that can be created by name. +//! This condition variable is designed to work with named_mutex and +//! can't be placed in shared memory or memory mapped files. +class named_condition +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + named_condition(); + named_condition(const named_condition &); + named_condition &operator=(const named_condition &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + //!Creates a global condition with a name. + //!If the condition can't be created throws interprocess_exception + named_condition(create_only_t create_only, const char *name, const permissions &perm = permissions()); + + //!Opens or creates a global condition with a name. + //!If the condition is created, this call is equivalent to + //!named_condition(create_only_t, ... ) + //!If the condition is already created, this call is equivalent + //!named_condition(open_only_t, ... ) + //!Does not throw + named_condition(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()); + + //!Opens a global condition with a name if that condition is previously + //!created. If it is not previously created this function throws + //!interprocess_exception. + named_condition(open_only_t open_only, const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~named_condition(); + + //!If there is a thread waiting on *this, change that + //!thread's state to ready. Otherwise there is no effect.*/ + void notify_one(); + + //!Change the state of all threads waiting on *this to ready. + //!If there are no waiting threads, notify_all() has no effect. + void notify_all(); + + //!Releases the lock on the named_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), and then reacquires the lock. + template + void wait(L& lock); + + //!The same as: + //!while (!pred()) wait(lock) + template + void wait(L& lock, Pr pred); + + //!Releases the lock on the named_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), or until time abs_time is reached, + //!and then reacquires the lock. + //!Returns: false if time abs_time is reached, otherwise true. + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time); + + //!The same as: while (!pred()) { + //! if (!timed_wait(lock, abs_time)) return pred(); + //! } return true; + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred); + + //!Erases a named condition from the system. + //!Returns false on error. Never throws. + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + #if defined(BOOST_INTERPROCESS_USE_WINDOWS) + typedef ipcdetail::windows_named_condition condition_type; + #else + typedef ipcdetail::shm_named_condition condition_type; + #endif + condition_type m_cond; + + friend class ipcdetail::interprocess_tester; + void dont_close_on_destruction() + { ipcdetail::interprocess_tester::dont_close_on_destruction(m_cond); } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline named_condition::~named_condition() +{} + +inline named_condition::named_condition(create_only_t, const char *name, const permissions &perm) + : m_cond(create_only_t(), name, perm) +{} + +inline named_condition::named_condition(open_or_create_t, const char *name, const permissions &perm) + : m_cond(open_or_create_t(), name, perm) +{} + +inline named_condition::named_condition(open_only_t, const char *name) + : m_cond(open_only_t(), name) +{} + +inline void named_condition::notify_one() +{ m_cond.notify_one(); } + +inline void named_condition::notify_all() +{ m_cond.notify_all(); } + +template +inline void named_condition::wait(L& lock) +{ + ipcdetail::internal_mutex_lock internal_lock(lock); + m_cond.wait(internal_lock); +} + +template +inline void named_condition::wait(L& lock, Pr pred) +{ + ipcdetail::internal_mutex_lock internal_lock(lock); + m_cond.wait(internal_lock, pred); +} + +template +inline bool named_condition::timed_wait + (L& lock, const boost::posix_time::ptime &abs_time) +{ + ipcdetail::internal_mutex_lock internal_lock(lock); + return m_cond.timed_wait(internal_lock, abs_time); +} + +template +inline bool named_condition::timed_wait + (L& lock, const boost::posix_time::ptime &abs_time, Pr pred) +{ + ipcdetail::internal_mutex_lock internal_lock(lock); + return m_cond.timed_wait(internal_lock, abs_time, pred); +} + +inline bool named_condition::remove(const char *name) +{ + return condition_type::remove(name); +} + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess +} //namespace boost + +#include + +#endif // BOOST_INTERPROCESS_NAMED_CONDITION_HPP diff --git a/libraries/boost/boost/interprocess/sync/named_condition_any.hpp b/libraries/boost/boost/interprocess/sync/named_condition_any.hpp new file mode 100644 index 000000000..a62247078 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/named_condition_any.hpp @@ -0,0 +1,155 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NAMED_CONDITION_ANY_HPP +#define BOOST_INTERPROCESS_NAMED_CONDITION_ANY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#else + #include +#endif + +//!\file +//!Describes a named condition class for inter-process synchronization + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +namespace ipcdetail{ class interprocess_tester; } +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//! A global condition variable that can be created by name. +//! This condition variable is designed to work with named_mutex and +//! can't be placed in shared memory or memory mapped files. +class named_condition_any +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + named_condition_any(); + named_condition_any(const named_condition_any &); + named_condition_any &operator=(const named_condition_any &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + //!Creates a global condition with a name. + //!If the condition can't be created throws interprocess_exception + named_condition_any(create_only_t, const char *name, const permissions &perm = permissions()) + : m_cond(create_only_t(), name, perm) + {} + + //!Opens or creates a global condition with a name. + //!If the condition is created, this call is equivalent to + //!named_condition_any(create_only_t, ... ) + //!If the condition is already created, this call is equivalent + //!named_condition_any(open_only_t, ... ) + //!Does not throw + named_condition_any(open_or_create_t, const char *name, const permissions &perm = permissions()) + : m_cond(open_or_create_t(), name, perm) + {} + + //!Opens a global condition with a name if that condition is previously + //!created. If it is not previously created this function throws + //!interprocess_exception. + named_condition_any(open_only_t, const char *name) + : m_cond(open_only_t(), name) + {} + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~named_condition_any() + {} + + //!If there is a thread waiting on *this, change that + //!thread's state to ready. Otherwise there is no effect.*/ + void notify_one() + { m_cond.notify_one(); } + + //!Change the state of all threads waiting on *this to ready. + //!If there are no waiting threads, notify_all() has no effect. + void notify_all() + { m_cond.notify_all(); } + + //!Releases the lock on the named_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), and then reacquires the lock. + template + void wait(L& lock) + { return m_cond.wait(lock); } + + //!The same as: + //!while (!pred()) wait(lock) + template + void wait(L& lock, Pr pred) + { return m_cond.wait(lock, pred); } + + //!Releases the lock on the named_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), or until time abs_time is reached, + //!and then reacquires the lock. + //!Returns: false if time abs_time is reached, otherwise true. + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { return m_cond.timed_wait(lock, abs_time); } + + //!The same as: while (!pred()) { + //! if (!timed_wait(lock, abs_time)) return pred(); + //! } return true; + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { return m_cond.timed_wait(lock, abs_time, pred); } + + //!Erases a named condition from the system. + //!Returns false on error. Never throws. + static bool remove(const char *name) + { return condition_any_type::remove(name); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + #if defined(BOOST_INTERPROCESS_USE_WINDOWS) + typedef ipcdetail::windows_named_condition_any condition_any_type; + #else + typedef ipcdetail::shm_named_condition_any condition_any_type; + #endif + condition_any_type m_cond; + + friend class ipcdetail::interprocess_tester; + void dont_close_on_destruction() + { ipcdetail::interprocess_tester::dont_close_on_destruction(m_cond); } + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} //namespace interprocess +} //namespace boost + +#include + +#endif // BOOST_INTERPROCESS_NAMED_CONDITION_ANY_HPP diff --git a/libraries/boost/boost/interprocess/sync/named_mutex.hpp b/libraries/boost/boost/interprocess/sync/named_mutex.hpp new file mode 100644 index 000000000..127e8d8a8 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/named_mutex.hpp @@ -0,0 +1,175 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NAMED_MUTEX_HPP +#define BOOST_INTERPROCESS_NAMED_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES) + #include + #define BOOST_INTERPROCESS_USE_POSIX_SEMAPHORES +#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#else +#include +#endif + +//!\file +//!Describes a named mutex class for inter-process synchronization + +namespace boost { +namespace interprocess { + +class named_condition; + +//!A mutex with a global name, so it can be found from different +//!processes. This mutex can't be placed in shared memory, and +//!each process should have it's own named_mutex. +class named_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + named_mutex(); + named_mutex(const named_mutex &); + named_mutex &operator=(const named_mutex &); + friend class named_condition; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Creates a global mutex with a name. + //!Throws interprocess_exception on error. + named_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions()); + + //!Opens or creates a global mutex with a name. + //!If the mutex is created, this call is equivalent to + //!named_mutex(create_only_t, ... ) + //!If the mutex is already created, this call is equivalent + //!named_mutex(open_only_t, ... ) + //!Does not throw + named_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()); + + //!Opens a global mutex with a name if that mutex is previously + //!created. If it is not previously created this function throws + //!interprocess_exception. + named_mutex(open_only_t open_only, const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~named_mutex(); + + //!Unlocks a previously locked + //!mutex. + void unlock(); + + //!Locks the mutex, sleeps when the mutex is already locked. + //!Throws interprocess_exception if a severe error is found + void lock(); + + //!Tries to lock the mutex, returns false when the mutex + //!is already locked, returns true when success. + //!Throws interprocess_exception if a severe error is found + bool try_lock(); + + //!Tries to lock the the mutex until time abs_time, + //!Returns false when timeout expires, returns true when locks. + //!Throws interprocess_exception if a severe error is found + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Erases a named mutex from the system. + //!Returns false on error. Never throws. + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class ipcdetail::interprocess_tester; + void dont_close_on_destruction(); + + public: + #if defined(BOOST_INTERPROCESS_USE_POSIX_SEMAPHORES) + typedef ipcdetail::posix_named_mutex internal_mutex_type; + #undef BOOST_INTERPROCESS_USE_POSIX_SEMAPHORES + #elif defined(BOOST_INTERPROCESS_USE_WINDOWS) + typedef ipcdetail::windows_named_mutex internal_mutex_type; + #undef BOOST_INTERPROCESS_USE_WINDOWS + #else + typedef ipcdetail::shm_named_mutex internal_mutex_type; + #endif + internal_mutex_type &internal_mutex() + { return m_mut; } + + internal_mutex_type m_mut; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline named_mutex::named_mutex(create_only_t, const char *name, const permissions &perm) + : m_mut(create_only_t(), name, perm) +{} + +inline named_mutex::named_mutex(open_or_create_t, const char *name, const permissions &perm) + : m_mut(open_or_create_t(), name, perm) +{} + +inline named_mutex::named_mutex(open_only_t, const char *name) + : m_mut(open_only_t(), name) +{} + +inline void named_mutex::dont_close_on_destruction() +{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_mut); } + +inline named_mutex::~named_mutex() +{} + +inline void named_mutex::lock() +{ m_mut.lock(); } + +inline void named_mutex::unlock() +{ m_mut.unlock(); } + +inline bool named_mutex::try_lock() +{ return m_mut.try_lock(); } + +inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return m_mut.timed_lock(abs_time); } + +inline bool named_mutex::remove(const char *name) +{ return internal_mutex_type::remove(name); } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_NAMED_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/named_recursive_mutex.hpp b/libraries/boost/boost/interprocess/sync/named_recursive_mutex.hpp new file mode 100644 index 000000000..b2f1c200b --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/named_recursive_mutex.hpp @@ -0,0 +1,162 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NAMED_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_NAMED_RECURSIVE_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#else + #include +#endif + +//!\file +//!Describes a named named_recursive_mutex class for inter-process synchronization + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +namespace ipcdetail{ class interprocess_tester; } +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!A recursive mutex with a global name, so it can be found from different +//!processes. This mutex can't be placed in shared memory, and +//!each process should have it's own named_recursive_mutex. +class named_recursive_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + named_recursive_mutex(); + named_recursive_mutex(const named_recursive_mutex &); + named_recursive_mutex &operator=(const named_recursive_mutex &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + //!Creates a global recursive_mutex with a name. + //!If the recursive_mutex can't be created throws interprocess_exception + named_recursive_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions()); + + //!Opens or creates a global recursive_mutex with a name. + //!If the recursive_mutex is created, this call is equivalent to + //!named_recursive_mutex(create_only_t, ... ) + //!If the recursive_mutex is already created, this call is equivalent + //!named_recursive_mutex(open_only_t, ... ) + //!Does not throw + named_recursive_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()); + + //!Opens a global recursive_mutex with a name if that recursive_mutex is previously + //!created. If it is not previously created this function throws + //!interprocess_exception. + named_recursive_mutex(open_only_t open_only, const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~named_recursive_mutex(); + + //!Unlocks a previously locked + //!named_recursive_mutex. + void unlock(); + + //!Locks named_recursive_mutex, sleeps when named_recursive_mutex is already locked. + //!Throws interprocess_exception if a severe error is found. + void lock(); + + //!Tries to lock the named_recursive_mutex, returns false when named_recursive_mutex + //!is already locked, returns true when success. + //!Throws interprocess_exception if a severe error is found. + bool try_lock(); + + //!Tries to lock the named_recursive_mutex until time abs_time, + //!Returns false when timeout expires, returns true when locks. + //!Throws interprocess_exception if a severe error is found + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Erases a named recursive mutex + //!from the system + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class ipcdetail::interprocess_tester; + void dont_close_on_destruction(); + + #if defined(BOOST_INTERPROCESS_USE_WINDOWS) + typedef ipcdetail::windows_named_recursive_mutex impl_t; + #undef BOOST_INTERPROCESS_USE_WINDOWS + #else + typedef ipcdetail::shm_named_recursive_mutex impl_t; + #endif + impl_t m_mut; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline named_recursive_mutex::~named_recursive_mutex() +{} + +inline void named_recursive_mutex::dont_close_on_destruction() +{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_mut); } + +inline named_recursive_mutex::named_recursive_mutex(create_only_t, const char *name, const permissions &perm) + : m_mut (create_only, name, perm) +{} + +inline named_recursive_mutex::named_recursive_mutex(open_or_create_t, const char *name, const permissions &perm) + : m_mut (open_or_create, name, perm) +{} + +inline named_recursive_mutex::named_recursive_mutex(open_only_t, const char *name) + : m_mut (open_only, name) +{} + +inline void named_recursive_mutex::lock() +{ m_mut.lock(); } + +inline void named_recursive_mutex::unlock() +{ m_mut.unlock(); } + +inline bool named_recursive_mutex::try_lock() +{ return m_mut.try_lock(); } + +inline bool named_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return m_mut.timed_lock(abs_time); } + +inline bool named_recursive_mutex::remove(const char *name) +{ return impl_t::remove(name); } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_NAMED_RECURSIVE_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/named_semaphore.hpp b/libraries/boost/boost/interprocess/sync/named_semaphore.hpp new file mode 100644 index 000000000..1e56693a3 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/named_semaphore.hpp @@ -0,0 +1,173 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NAMED_SEMAPHORE_HPP +#define BOOST_INTERPROCESS_NAMED_SEMAPHORE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES) +#include +//Experimental... +#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#else +#include +#endif + +//!\file +//!Describes a named semaphore class for inter-process synchronization + +namespace boost { +namespace interprocess { + +//!A semaphore with a global name, so it can be found from different +//!processes. Allows several resource sharing patterns and efficient +//!acknowledgment mechanisms. +class named_semaphore +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + named_semaphore(); + named_semaphore(const named_semaphore &); + named_semaphore &operator=(const named_semaphore &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Creates a global semaphore with a name, and an initial count. + //!If the semaphore can't be created throws interprocess_exception + named_semaphore(create_only_t, const char *name, unsigned int initialCount, const permissions &perm = permissions()); + + //!Opens or creates a global semaphore with a name, and an initial count. + //!If the semaphore is created, this call is equivalent to + //!named_semaphore(create_only_t, ...) + //!If the semaphore is already created, this call is equivalent to + //!named_semaphore(open_only_t, ... ) + //!and initialCount is ignored. + named_semaphore(open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm = permissions()); + + //!Opens a global semaphore with a name if that semaphore is previously. + //!created. If it is not previously created this function throws + //!interprocess_exception. + named_semaphore(open_only_t, const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~named_semaphore(); + + //!Increments the semaphore count. If there are processes/threads blocked waiting + //!for the semaphore, then one of these processes will return successfully from + //!its wait function. If there is an error an interprocess_exception exception is thrown. + void post(); + + //!Decrements the semaphore. If the semaphore value is not greater than zero, + //!then the calling process/thread blocks until it can decrement the counter. + //!If there is an error an interprocess_exception exception is thrown. + void wait(); + + //!Decrements the semaphore if the semaphore's value is greater than zero + //!and returns true. If the value is not greater than zero returns false. + //!If there is an error an interprocess_exception exception is thrown. + bool try_wait(); + + //!Decrements the semaphore if the semaphore's value is greater + //!than zero and returns true. Otherwise, waits for the semaphore + //!to the posted or the timeout expires. If the timeout expires, the + //!function returns false. If the semaphore is posted the function + //!returns true. If there is an error throws sem_exception + bool timed_wait(const boost::posix_time::ptime &abs_time); + + //!Erases a named semaphore from the system. + //!Returns false on error. Never throws. + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class ipcdetail::interprocess_tester; + void dont_close_on_destruction(); + + #if defined(BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES) + typedef ipcdetail::posix_named_semaphore impl_t; + #elif defined(BOOST_INTERPROCESS_USE_WINDOWS) + #undef BOOST_INTERPROCESS_USE_WINDOWS + typedef ipcdetail::windows_named_semaphore impl_t; + #else + typedef ipcdetail::shm_named_semaphore impl_t; + #endif + impl_t m_sem; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline named_semaphore::named_semaphore + (create_only_t, const char *name, unsigned int initialCount, const permissions &perm) + : m_sem(create_only, name, initialCount, perm) +{} + +inline named_semaphore::named_semaphore + (open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm) + : m_sem(open_or_create, name, initialCount, perm) +{} + +inline named_semaphore::named_semaphore(open_only_t, const char *name) + : m_sem(open_only, name) +{} + +inline named_semaphore::~named_semaphore() +{} + +inline void named_semaphore::dont_close_on_destruction() +{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_sem); } + +inline void named_semaphore::wait() +{ m_sem.wait(); } + +inline void named_semaphore::post() +{ m_sem.post(); } + +inline bool named_semaphore::try_wait() +{ return m_sem.try_wait(); } + +inline bool named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +{ return m_sem.timed_wait(abs_time); } + +inline bool named_semaphore::remove(const char *name) +{ return impl_t::remove(name); } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + + +#include + +#endif //BOOST_INTERPROCESS_NAMED_SEMAPHORE_HPP diff --git a/libraries/boost/boost/interprocess/sync/named_sharable_mutex.hpp b/libraries/boost/boost/interprocess/sync/named_sharable_mutex.hpp new file mode 100644 index 000000000..a2dca1c41 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/named_sharable_mutex.hpp @@ -0,0 +1,234 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NAMED_SHARABLE_MUTEX_HPP +#define BOOST_INTERPROCESS_NAMED_SHARABLE_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes a named sharable mutex class for inter-process synchronization + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +namespace ipcdetail{ class interprocess_tester; } +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +class named_condition; + +//!A sharable mutex with a global name, so it can be found from different +//!processes. This mutex can't be placed in shared memory, and +//!each process should have it's own named sharable mutex. +class named_sharable_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + named_sharable_mutex(); + named_sharable_mutex(const named_sharable_mutex &); + named_sharable_mutex &operator=(const named_sharable_mutex &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + //!Creates a global sharable mutex with a name. + //!If the sharable mutex can't be created throws interprocess_exception + named_sharable_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions()); + + //!Opens or creates a global sharable mutex with a name. + //!If the sharable mutex is created, this call is equivalent to + //!named_sharable_mutex(create_only_t, ...) + //!If the sharable mutex is already created, this call is equivalent to + //!named_sharable_mutex(open_only_t, ... ). + named_sharable_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()); + + //!Opens a global sharable mutex with a name if that sharable mutex + //!is previously. + //!created. If it is not previously created this function throws + //!interprocess_exception. + named_sharable_mutex(open_only_t open_only, const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~named_sharable_mutex(); + + //Exclusive locking + + //!Effects: The calling thread tries to obtain exclusive ownership of the mutex, + //! and if another thread has exclusive or sharable ownership of + //! the mutex, it waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! without waiting. If no other thread has exclusive or sharable + //! ownership of the mutex this succeeds. + //!Returns: If it can acquire exclusive ownership immediately returns true. + //! If it has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! waiting if necessary until no other thread has exclusive, or sharable + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The calling thread releases the exclusive ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock(); + + //Sharable locking + + //!Effects: The calling thread tries to obtain sharable ownership of the mutex, + //! and if another thread has exclusive ownership of the mutex, + //! waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! without waiting. If no other thread has exclusive ownership + //! of the mutex this succeeds. + //!Returns: If it can acquire sharable ownership immediately returns true. If it + //! has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! waiting if necessary until no other thread has exclusive + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires sharable ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock_sharable(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The calling thread releases the sharable ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_sharable(); + + //!Erases a named sharable mutex from the system. + //!Returns false on error. Never throws. + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class ipcdetail::interprocess_tester; + void dont_close_on_destruction(); + + interprocess_sharable_mutex *mutex() const + { return static_cast(m_shmem.get_user_address()); } + + typedef ipcdetail::managed_open_or_create_impl open_create_impl_t; + open_create_impl_t m_shmem; + typedef ipcdetail::named_creation_functor construct_func_t; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline named_sharable_mutex::~named_sharable_mutex() +{} + +inline named_sharable_mutex::named_sharable_mutex + (create_only_t, const char *name, const permissions &perm) + : m_shmem (create_only + ,name + ,sizeof(interprocess_sharable_mutex) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoCreate) + ,perm) +{} + +inline named_sharable_mutex::named_sharable_mutex + (open_or_create_t, const char *name, const permissions &perm) + : m_shmem (open_or_create + ,name + ,sizeof(interprocess_sharable_mutex) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoOpenOrCreate) + ,perm) +{} + +inline named_sharable_mutex::named_sharable_mutex + (open_only_t, const char *name) + : m_shmem (open_only + ,name + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoOpen)) +{} + +inline void named_sharable_mutex::dont_close_on_destruction() +{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); } + +inline void named_sharable_mutex::lock() +{ this->mutex()->lock(); } + +inline void named_sharable_mutex::unlock() +{ this->mutex()->unlock(); } + +inline bool named_sharable_mutex::try_lock() +{ return this->mutex()->try_lock(); } + +inline bool named_sharable_mutex::timed_lock + (const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_lock(abs_time); } + +inline void named_sharable_mutex::lock_sharable() +{ this->mutex()->lock_sharable(); } + +inline void named_sharable_mutex::unlock_sharable() +{ this->mutex()->unlock_sharable(); } + +inline bool named_sharable_mutex::try_lock_sharable() +{ return this->mutex()->try_lock_sharable(); } + +inline bool named_sharable_mutex::timed_lock_sharable + (const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_lock_sharable(abs_time); } + +inline bool named_sharable_mutex::remove(const char *name) +{ return shared_memory_object::remove(name); } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_NAMED_SHARABLE_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/named_upgradable_mutex.hpp b/libraries/boost/boost/interprocess/sync/named_upgradable_mutex.hpp new file mode 100644 index 000000000..b285d1a42 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/named_upgradable_mutex.hpp @@ -0,0 +1,363 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_named_upgradable_mutex_HPP +#define BOOST_INTERPROCESS_named_upgradable_mutex_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes a named upgradable mutex class for inter-process synchronization + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +namespace ipcdetail{ class interprocess_tester; } +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +class named_condition; + +//!A upgradable mutex with a global name, so it can be found from different +//!processes. This mutex can't be placed in shared memory, and +//!each process should have it's own named upgradable mutex. +class named_upgradable_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + named_upgradable_mutex(); + named_upgradable_mutex(const named_upgradable_mutex &); + named_upgradable_mutex &operator=(const named_upgradable_mutex &); + friend class named_condition; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + //!Creates a global upgradable mutex with a name. + //!If the upgradable mutex can't be created throws interprocess_exception + named_upgradable_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions()); + + //!Opens or creates a global upgradable mutex with a name. + //!If the upgradable mutex is created, this call is equivalent to + //!named_upgradable_mutex(create_only_t, ...) + //!If the upgradable mutex is already created, this call is equivalent to + //!named_upgradable_mutex(open_only_t, ... ). + named_upgradable_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()); + + //!Opens a global upgradable mutex with a name if that upgradable mutex + //!is previously. + //!created. If it is not previously created this function throws + //!interprocess_exception. + named_upgradable_mutex(open_only_t open_only, const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~named_upgradable_mutex(); + + //Exclusive locking + + //!Effects: The calling thread tries to obtain exclusive ownership of the mutex, + //! and if another thread has exclusive, sharable or upgradable ownership of + //! the mutex, it waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! without waiting. If no other thread has exclusive, sharable or upgradable + //! ownership of the mutex this succeeds. + //!Returns: If it can acquire exclusive ownership immediately returns true. + //! If it has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! waiting if necessary until no other thread has exclusive, sharable or + //! upgradable ownership of the mutex or abs_time is reached. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The calling thread releases the exclusive ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock(); + + //Sharable locking + + //!Effects: The calling thread tries to obtain sharable ownership of the mutex, + //! and if another thread has exclusive ownership of the mutex, + //! waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! without waiting. If no other thread has exclusive ownership + //! of the mutex this succeeds. + //!Returns: If it can acquire sharable ownership immediately returns true. If it + //! has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! waiting if necessary until no other thread has exclusive + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires sharable ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock_sharable(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The calling thread releases the sharable ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_sharable(); + + //Upgradable locking + + //!Effects: The calling thread tries to obtain upgradable ownership of the mutex, + //! and if another thread has exclusive or upgradable ownership of the mutex, + //! waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock_upgradable(); + + //!Effects: The calling thread tries to acquire upgradable ownership of the mutex + //! without waiting. If no other thread has exclusive or upgradable ownership + //! of the mutex this succeeds. + //!Returns: If it can acquire upgradable ownership immediately returns true. + //! If it has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock_upgradable(); + + //!Effects: The calling thread tries to acquire upgradable ownership of the mutex + //! waiting if necessary until no other thread has exclusive or upgradable + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The calling thread releases the upgradable ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_upgradable(); + + //Demotions + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The thread atomically releases exclusive ownership and acquires + //! upgradable ownership. This operation is non-blocking. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_and_lock_upgradable(); + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The thread atomically releases exclusive ownership and acquires + //! sharable ownership. This operation is non-blocking. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_and_lock_sharable(); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and acquires + //! sharable ownership. This operation is non-blocking. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_upgradable_and_lock_sharable(); + + //Promotions + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and acquires + //! exclusive ownership. This operation will block until all threads with + //! sharable ownership release it. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_upgradable_and_lock(); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and tries to + //! acquire exclusive ownership. This operation will fail if there are threads + //! with sharable ownership, but it will maintain upgradable ownership. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. + bool try_unlock_upgradable_and_lock(); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and tries to acquire + //! exclusive ownership, waiting if necessary until abs_time. This operation will + //! fail if there are threads with sharable ownership or timeout reaches, but it + //! will maintain upgradable ownership. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. + bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The thread atomically releases sharable ownership and tries to acquire + //! exclusive ownership. This operation will fail if there are threads with sharable + //! or upgradable ownership, but it will maintain sharable ownership. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. + bool try_unlock_sharable_and_lock(); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The thread atomically releases sharable ownership and tries to acquire + //! upgradable ownership. This operation will fail if there are threads with sharable + //! or upgradable ownership, but it will maintain sharable ownership. + //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. + bool try_unlock_sharable_and_lock_upgradable(); + + //!Erases a named upgradable mutex from the system. + //!Returns false on error. Never throws. + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class ipcdetail::interprocess_tester; + void dont_close_on_destruction(); + + interprocess_upgradable_mutex *mutex() const + { return static_cast(m_shmem.get_user_address()); } + + typedef ipcdetail::managed_open_or_create_impl open_create_impl_t; + open_create_impl_t m_shmem; + typedef ipcdetail::named_creation_functor construct_func_t; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline named_upgradable_mutex::~named_upgradable_mutex() +{} + +inline named_upgradable_mutex::named_upgradable_mutex + (create_only_t, const char *name, const permissions &perm) + : m_shmem (create_only + ,name + ,sizeof(interprocess_upgradable_mutex) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoCreate) + ,perm) +{} + +inline named_upgradable_mutex::named_upgradable_mutex + (open_or_create_t, const char *name, const permissions &perm) + : m_shmem (open_or_create + ,name + ,sizeof(interprocess_upgradable_mutex) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoOpenOrCreate) + ,perm) +{} + +inline named_upgradable_mutex::named_upgradable_mutex + (open_only_t, const char *name) + : m_shmem (open_only + ,name + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoOpen)) +{} + +inline void named_upgradable_mutex::dont_close_on_destruction() +{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); } + +inline void named_upgradable_mutex::lock() +{ this->mutex()->lock(); } + +inline void named_upgradable_mutex::unlock() +{ this->mutex()->unlock(); } + +inline bool named_upgradable_mutex::try_lock() +{ return this->mutex()->try_lock(); } + +inline bool named_upgradable_mutex::timed_lock + (const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_lock(abs_time); } + +inline void named_upgradable_mutex::lock_upgradable() +{ this->mutex()->lock_upgradable(); } + +inline void named_upgradable_mutex::unlock_upgradable() +{ this->mutex()->unlock_upgradable(); } + +inline bool named_upgradable_mutex::try_lock_upgradable() +{ return this->mutex()->try_lock_upgradable(); } + +inline bool named_upgradable_mutex::timed_lock_upgradable + (const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_lock_upgradable(abs_time); } + +inline void named_upgradable_mutex::lock_sharable() +{ this->mutex()->lock_sharable(); } + +inline void named_upgradable_mutex::unlock_sharable() +{ this->mutex()->unlock_sharable(); } + +inline bool named_upgradable_mutex::try_lock_sharable() +{ return this->mutex()->try_lock_sharable(); } + +inline bool named_upgradable_mutex::timed_lock_sharable + (const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_lock_sharable(abs_time); } + +inline void named_upgradable_mutex::unlock_and_lock_upgradable() +{ this->mutex()->unlock_and_lock_upgradable(); } + +inline void named_upgradable_mutex::unlock_and_lock_sharable() +{ this->mutex()->unlock_and_lock_sharable(); } + +inline void named_upgradable_mutex::unlock_upgradable_and_lock_sharable() +{ this->mutex()->unlock_upgradable_and_lock_sharable(); } + +inline void named_upgradable_mutex::unlock_upgradable_and_lock() +{ this->mutex()->unlock_upgradable_and_lock(); } + +inline bool named_upgradable_mutex::try_unlock_upgradable_and_lock() +{ return this->mutex()->try_unlock_upgradable_and_lock(); } + +inline bool named_upgradable_mutex::timed_unlock_upgradable_and_lock + (const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_unlock_upgradable_and_lock(abs_time); } + +inline bool named_upgradable_mutex::try_unlock_sharable_and_lock() +{ return this->mutex()->try_unlock_sharable_and_lock(); } + +inline bool named_upgradable_mutex::try_unlock_sharable_and_lock_upgradable() +{ return this->mutex()->try_unlock_sharable_and_lock_upgradable(); } + +inline bool named_upgradable_mutex::remove(const char *name) +{ return shared_memory_object::remove(name); } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_named_upgradable_mutex_HPP diff --git a/libraries/boost/boost/interprocess/sync/null_mutex.hpp b/libraries/boost/boost/interprocess/sync/null_mutex.hpp new file mode 100644 index 000000000..f3c29eb25 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/null_mutex.hpp @@ -0,0 +1,155 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NULL_MUTEX_HPP +#define BOOST_INTERPROCESS_NULL_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + + +//!\file +//!Describes null_mutex classes + +namespace boost { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace posix_time +{ class ptime; } + +#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +namespace interprocess { + +//!Implements a mutex that simulates a mutex without doing any operation and +//!simulates a successful operation. +class null_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + null_mutex(const null_mutex&); + null_mutex &operator= (const null_mutex&); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + //!Constructor. + //!Empty. + null_mutex(){} + + //!Destructor. + //!Empty. + ~null_mutex(){} + + //!Simulates a mutex lock() operation. Empty function. + void lock(){} + + //!Simulates a mutex try_lock() operation. + //!Equivalent to "return true;" + bool try_lock() + { return true; } + + //!Simulates a mutex timed_lock() operation. + //!Equivalent to "return true;" + bool timed_lock(const boost::posix_time::ptime &) + { return true; } + + //!Simulates a mutex unlock() operation. + //!Empty function. + void unlock(){} + + //!Simulates a mutex lock_sharable() operation. + //!Empty function. + void lock_sharable(){} + + //!Simulates a mutex try_lock_sharable() operation. + //!Equivalent to "return true;" + bool try_lock_sharable() + { return true; } + + //!Simulates a mutex timed_lock_sharable() operation. + //!Equivalent to "return true;" + bool timed_lock_sharable(const boost::posix_time::ptime &) + { return true; } + + //!Simulates a mutex unlock_sharable() operation. + //!Empty function. + void unlock_sharable(){} + + //!Simulates a mutex lock_upgradable() operation. + //!Empty function. + void lock_upgradable(){} + + //!Simulates a mutex try_lock_upgradable() operation. + //!Equivalent to "return true;" + bool try_lock_upgradable() + { return true; } + + //!Simulates a mutex timed_lock_upgradable() operation. + //!Equivalent to "return true;" + bool timed_lock_upgradable(const boost::posix_time::ptime &) + { return true; } + + //!Simulates a mutex unlock_upgradable() operation. + //!Empty function. + void unlock_upgradable(){} + + //!Simulates unlock_and_lock_upgradable(). + //!Empty function. + void unlock_and_lock_upgradable(){} + + //!Simulates unlock_and_lock_sharable(). + //!Empty function. + void unlock_and_lock_sharable(){} + + //!Simulates unlock_upgradable_and_lock_sharable(). + //!Empty function. + void unlock_upgradable_and_lock_sharable(){} + + //Promotions + + //!Simulates unlock_upgradable_and_lock(). + //!Empty function. + void unlock_upgradable_and_lock(){} + + //!Simulates try_unlock_upgradable_and_lock(). + //!Equivalent to "return true;" + bool try_unlock_upgradable_and_lock() + { return true; } + + //!Simulates timed_unlock_upgradable_and_lock(). + //!Equivalent to "return true;" + bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &) + { return true; } + + //!Simulates try_unlock_sharable_and_lock(). + //!Equivalent to "return true;" + bool try_unlock_sharable_and_lock() + { return true; } + + //!Simulates try_unlock_sharable_and_lock_upgradable(). + //!Equivalent to "return true;" + bool try_unlock_sharable_and_lock_upgradable() + { return true; } +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_NULL_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/posix/condition.hpp b/libraries/boost/boost/interprocess/sync/posix/condition.hpp new file mode 100644 index 000000000..5372d9689 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/posix/condition.hpp @@ -0,0 +1,196 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_POSIX_CONDITION_HPP +#define BOOST_INTERPROCESS_POSIX_CONDITION_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class posix_condition +{ + //Non-copyable + posix_condition(const posix_condition &); + posix_condition &operator=(const posix_condition &); + + public: + //!Constructs a posix_condition. On error throws interprocess_exception. + posix_condition(); + + //!Destroys *this + //!liberating system resources. + ~posix_condition(); + + //!If there is a thread waiting on *this, change that + //!thread's state to ready. Otherwise there is no effect. + void notify_one(); + + //!Change the state of all threads waiting on *this to ready. + //!If there are no waiting threads, notify_all() has no effect. + void notify_all(); + + //!Releases the lock on the posix_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), and then reacquires the lock. + template + void wait(L& lock) + { + if (!lock) + throw lock_exception(); + this->do_wait(*lock.mutex()); + } + + //!The same as: + //!while (!pred()) wait(lock) + template + void wait(L& lock, Pr pred) + { + if (!lock) + throw lock_exception(); + + while (!pred()) + this->do_wait(*lock.mutex()); + } + + //!Releases the lock on the posix_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), or until time abs_time is reached, + //!and then reacquires the lock. + //!Returns: false if time abs_time is reached, otherwise true. + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { + if (!lock) + throw lock_exception(); + //Posix does not support infinity absolute time so handle it here + if(abs_time == boost::posix_time::pos_infin){ + this->wait(lock); + return true; + } + return this->do_timed_wait(abs_time, *lock.mutex()); + } + + //!The same as: while (!pred()) { + //! if (!timed_wait(lock, abs_time)) return pred(); + //! } return true; + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { + if (!lock) + throw lock_exception(); + //Posix does not support infinity absolute time so handle it here + if(abs_time == boost::posix_time::pos_infin){ + this->wait(lock, pred); + return true; + } + while (!pred()){ + if (!this->do_timed_wait(abs_time, *lock.mutex())) + return pred(); + } + return true; + } + + + void do_wait(posix_mutex &mut); + + bool do_timed_wait(const boost::posix_time::ptime &abs_time, posix_mutex &mut); + + private: + pthread_cond_t m_condition; +}; + +inline posix_condition::posix_condition() +{ + int res; + pthread_condattr_t cond_attr; + res = pthread_condattr_init(&cond_attr); + if(res != 0){ + throw interprocess_exception("pthread_condattr_init failed"); + } + res = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); + if(res != 0){ + pthread_condattr_destroy(&cond_attr); + throw interprocess_exception(res); + } + res = pthread_cond_init(&m_condition, &cond_attr); + pthread_condattr_destroy(&cond_attr); + if(res != 0){ + throw interprocess_exception(res); + } +} + +inline posix_condition::~posix_condition() +{ + int res = 0; + res = pthread_cond_destroy(&m_condition); + BOOST_ASSERT(res == 0); (void)res; +} + +inline void posix_condition::notify_one() +{ + int res = 0; + res = pthread_cond_signal(&m_condition); + BOOST_ASSERT(res == 0); (void)res; +} + +inline void posix_condition::notify_all() +{ + int res = 0; + res = pthread_cond_broadcast(&m_condition); + BOOST_ASSERT(res == 0); (void)res; +} + +inline void posix_condition::do_wait(posix_mutex &mut) +{ + pthread_mutex_t* pmutex = &mut.m_mut; + int res = 0; + res = pthread_cond_wait(&m_condition, pmutex); + BOOST_ASSERT(res == 0); (void)res; +} + +inline bool posix_condition::do_timed_wait + (const boost::posix_time::ptime &abs_time, posix_mutex &mut) +{ + timespec ts = ptime_to_timespec(abs_time); + pthread_mutex_t* pmutex = &mut.m_mut; + int res = 0; + res = pthread_cond_timedwait(&m_condition, pmutex, &ts); + BOOST_ASSERT(res == 0 || res == ETIMEDOUT); + + return res != ETIMEDOUT; +} + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include + +#endif //#ifndef BOOST_INTERPROCESS_POSIX_CONDITION_HPP diff --git a/libraries/boost/boost/interprocess/sync/posix/mutex.hpp b/libraries/boost/boost/interprocess/sync/posix/mutex.hpp new file mode 100644 index 000000000..70adc23c9 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/posix/mutex.hpp @@ -0,0 +1,143 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// Parts of the pthread code come from Boost Threads code: +// +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS +# include +# include +#endif +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class posix_condition; + +class posix_mutex +{ + posix_mutex(const posix_mutex &); + posix_mutex &operator=(const posix_mutex &); + public: + + posix_mutex(); + ~posix_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + + friend class posix_condition; + + private: + pthread_mutex_t m_mut; +}; + +inline posix_mutex::posix_mutex() +{ + mutexattr_wrapper mut_attr; + mutex_initializer mut(m_mut, mut_attr); + mut.release(); +} + +inline posix_mutex::~posix_mutex() +{ + int res = pthread_mutex_destroy(&m_mut); + BOOST_ASSERT(res == 0);(void)res; +} + +inline void posix_mutex::lock() +{ + if (pthread_mutex_lock(&m_mut) != 0) + throw lock_exception(); +} + +inline bool posix_mutex::try_lock() +{ + int res = pthread_mutex_trylock(&m_mut); + if (!(res == 0 || res == EBUSY)) + throw lock_exception(); + return res == 0; +} + +inline bool posix_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS + //Posix does not support infinity absolute time so handle it here + if(abs_time == boost::posix_time::pos_infin){ + this->lock(); + return true; + } + timespec ts = ptime_to_timespec(abs_time); + int res = pthread_mutex_timedlock(&m_mut, &ts); + if (res != 0 && res != ETIMEDOUT) + throw lock_exception(); + return res == 0; + + #else //BOOST_INTERPROCESS_POSIX_TIMEOUTS + + return ipcdetail::try_based_timed_lock(*this, abs_time); + + #endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS +} + +inline void posix_mutex::unlock() +{ + int res = 0; + res = pthread_mutex_unlock(&m_mut); + (void)res; + BOOST_ASSERT(res == 0); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/posix/named_mutex.hpp b/libraries/boost/boost/interprocess/sync/posix/named_mutex.hpp new file mode 100644 index 000000000..28fafa83e --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/posix/named_mutex.hpp @@ -0,0 +1,114 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_POSIX_NAMED_MUTEX_HPP +#define BOOST_INTERPROCESS_POSIX_NAMED_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class named_condition; + +class posix_named_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + posix_named_mutex(); + posix_named_mutex(const posix_named_mutex &); + posix_named_mutex &operator=(const posix_named_mutex &); + friend class named_condition; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + posix_named_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions()); + + posix_named_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()); + + posix_named_mutex(open_only_t open_only, const char *name); + + ~posix_named_mutex(); + + void unlock(); + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class interprocess_tester; + void dont_close_on_destruction(); + + posix_named_semaphore m_sem; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline posix_named_mutex::posix_named_mutex(create_only_t, const char *name, const permissions &perm) + : m_sem(create_only, name, 1, perm) +{} + +inline posix_named_mutex::posix_named_mutex(open_or_create_t, const char *name, const permissions &perm) + : m_sem(open_or_create, name, 1, perm) +{} + +inline posix_named_mutex::posix_named_mutex(open_only_t, const char *name) + : m_sem(open_only, name) +{} + +inline void posix_named_mutex::dont_close_on_destruction() +{ interprocess_tester::dont_close_on_destruction(m_sem); } + +inline posix_named_mutex::~posix_named_mutex() +{} + +inline void posix_named_mutex::lock() +{ m_sem.wait(); } + +inline void posix_named_mutex::unlock() +{ m_sem.post(); } + +inline bool posix_named_mutex::try_lock() +{ return m_sem.try_wait(); } + +inline bool posix_named_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return m_sem.timed_wait(abs_time); } + +inline bool posix_named_mutex::remove(const char *name) +{ return posix_named_semaphore::remove(name); } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_POSIX_NAMED_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/posix/named_semaphore.hpp b/libraries/boost/boost/interprocess/sync/posix/named_semaphore.hpp new file mode 100644 index 000000000..8180da1e4 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/posix/named_semaphore.hpp @@ -0,0 +1,88 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_POSIX_NAMED_CONDITION_HPP +#define BOOST_INTERPROCESS_POSIX_NAMED_CONDITION_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +namespace ipcdetail{ class interprocess_tester; } +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +namespace ipcdetail { + +class posix_named_semaphore +{ + posix_named_semaphore(); + posix_named_semaphore(const posix_named_semaphore&); + posix_named_semaphore &operator= (const posix_named_semaphore &); + + public: + posix_named_semaphore + (create_only_t, const char *name, unsigned int initialCount, const permissions &perm = permissions()) + { semaphore_open(mp_sem, DoCreate, name, initialCount, perm); } + + posix_named_semaphore(open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm = permissions()) + { semaphore_open(mp_sem, DoOpenOrCreate, name, initialCount, perm); } + + posix_named_semaphore(open_only_t, const char *name) + { semaphore_open(mp_sem, DoOpen, name); } + + ~posix_named_semaphore() + { + if(mp_sem != BOOST_INTERPROCESS_POSIX_SEM_FAILED) + semaphore_close(mp_sem); + } + + void post() + { semaphore_post(mp_sem); } + + void wait() + { semaphore_wait(mp_sem); } + + bool try_wait() + { return semaphore_try_wait(mp_sem); } + + bool timed_wait(const boost::posix_time::ptime &abs_time) + { return semaphore_timed_wait(mp_sem, abs_time); } + + static bool remove(const char *name) + { return semaphore_unlink(name); } + + private: + friend class ipcdetail::interprocess_tester; + void dont_close_on_destruction() + { mp_sem = BOOST_INTERPROCESS_POSIX_SEM_FAILED; } + + sem_t *mp_sem; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_POSIX_NAMED_CONDITION_HPP diff --git a/libraries/boost/boost/interprocess/sync/posix/pthread_helpers.hpp b/libraries/boost/boost/interprocess/sync/posix/pthread_helpers.hpp new file mode 100644 index 000000000..c615c851e --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/posix/pthread_helpers.hpp @@ -0,0 +1,172 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP +#define BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + + #if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED + + //!Makes pthread_mutexattr_t cleanup easy when using exceptions + struct mutexattr_wrapper + { + //!Constructor + mutexattr_wrapper(bool recursive = false) + { + if(pthread_mutexattr_init(&m_attr)!=0 || + pthread_mutexattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0 || + (recursive && + pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE)!= 0 )) + throw interprocess_exception("pthread_mutexattr_xxxx failed"); + } + + //!Destructor + ~mutexattr_wrapper() { pthread_mutexattr_destroy(&m_attr); } + + //!This allows using mutexattr_wrapper as pthread_mutexattr_t + operator pthread_mutexattr_t&() { return m_attr; } + + pthread_mutexattr_t m_attr; + }; + + //!Makes pthread_condattr_t cleanup easy when using exceptions + struct condattr_wrapper + { + //!Constructor + condattr_wrapper() + { + if(pthread_condattr_init(&m_attr)!=0 || + pthread_condattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0) + throw interprocess_exception("pthread_condattr_xxxx failed"); + } + + //!Destructor + ~condattr_wrapper() { pthread_condattr_destroy(&m_attr); } + + //!This allows using condattr_wrapper as pthread_condattr_t + operator pthread_condattr_t&(){ return m_attr; } + + pthread_condattr_t m_attr; + }; + + //!Makes initialized pthread_mutex_t cleanup easy when using exceptions + class mutex_initializer + { + public: + //!Constructor. Takes interprocess_mutex attributes to initialize the interprocess_mutex + mutex_initializer(pthread_mutex_t &mut, pthread_mutexattr_t &mut_attr) + : mp_mut(&mut) + { + if(pthread_mutex_init(mp_mut, &mut_attr) != 0) + throw interprocess_exception("pthread_mutex_init failed"); + } + + ~mutex_initializer() { if(mp_mut) pthread_mutex_destroy(mp_mut); } + + void release() {mp_mut = 0; } + + private: + pthread_mutex_t *mp_mut; + }; + + //!Makes initialized pthread_cond_t cleanup easy when using exceptions + class condition_initializer + { + public: + condition_initializer(pthread_cond_t &cond, pthread_condattr_t &cond_attr) + : mp_cond(&cond) + { + if(pthread_cond_init(mp_cond, &cond_attr)!= 0) + throw interprocess_exception("pthread_cond_init failed"); + } + + ~condition_initializer() { if(mp_cond) pthread_cond_destroy(mp_cond); } + + void release() { mp_cond = 0; } + + private: + pthread_cond_t *mp_cond; + }; + + #endif // #if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED + + #if defined(BOOST_INTERPROCESS_POSIX_BARRIERS) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) + + //!Makes pthread_barrierattr_t cleanup easy when using exceptions + struct barrierattr_wrapper + { + //!Constructor + barrierattr_wrapper() + { + if(pthread_barrierattr_init(&m_attr)!=0 || + pthread_barrierattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0) + throw interprocess_exception("pthread_barrierattr_xxx failed"); + } + + //!Destructor + ~barrierattr_wrapper() { pthread_barrierattr_destroy(&m_attr); } + + //!This allows using mutexattr_wrapper as pthread_barrierattr_t + operator pthread_barrierattr_t&() { return m_attr; } + + pthread_barrierattr_t m_attr; + }; + + //!Makes initialized pthread_barrier_t cleanup easy when using exceptions + class barrier_initializer + { + public: + //!Constructor. Takes barrier attributes to initialize the barrier + barrier_initializer(pthread_barrier_t &mut, + pthread_barrierattr_t &mut_attr, + int count) + : mp_barrier(&mut) + { + if(pthread_barrier_init(mp_barrier, &mut_attr, count) != 0) + throw interprocess_exception("pthread_barrier_init failed"); + } + + ~barrier_initializer() { if(mp_barrier) pthread_barrier_destroy(mp_barrier); } + + void release() {mp_barrier = 0; } + + private: + pthread_barrier_t *mp_barrier; + }; + + #endif //#if defined(BOOST_INTERPROCESS_POSIX_BARRIERS) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) + +}//namespace ipcdetail + +}//namespace interprocess + +}//namespace boost + +#include + +#endif //ifdef BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP diff --git a/libraries/boost/boost/interprocess/sync/posix/ptime_to_timespec.hpp b/libraries/boost/boost/interprocess/sync/posix/ptime_to_timespec.hpp new file mode 100644 index 000000000..5aa09e0c1 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/posix/ptime_to_timespec.hpp @@ -0,0 +1,48 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP +#define BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include + +namespace boost { + +namespace interprocess { + +namespace ipcdetail { + +inline timespec ptime_to_timespec (const boost::posix_time::ptime &tm) +{ + const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); + //Avoid negative absolute times + boost::posix_time::time_duration duration = (tm <= epoch) ? boost::posix_time::time_duration(epoch - epoch) + : boost::posix_time::time_duration(tm - epoch); + timespec ts; + ts.tv_sec = duration.total_seconds(); + ts.tv_nsec = duration.total_nanoseconds() % 1000000000; + return ts; +} + +} //namespace ipcdetail { + +} //namespace interprocess { + +} //namespace boost { + +#endif //ifndef BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP diff --git a/libraries/boost/boost/interprocess/sync/posix/recursive_mutex.hpp b/libraries/boost/boost/interprocess/sync/posix/recursive_mutex.hpp new file mode 100644 index 000000000..9ef4f1278 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/posix/recursive_mutex.hpp @@ -0,0 +1,137 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// Parts of the pthread code come from Boost Threads code: +// +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS +# include +# include +#endif +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class posix_recursive_mutex +{ + posix_recursive_mutex(const posix_recursive_mutex &); + posix_recursive_mutex &operator=(const posix_recursive_mutex &); + public: + + posix_recursive_mutex(); + ~posix_recursive_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + + private: + pthread_mutex_t m_mut; +}; + +inline posix_recursive_mutex::posix_recursive_mutex() +{ + mutexattr_wrapper mut_attr(true); + mutex_initializer mut(m_mut, mut_attr); + mut.release(); +} + +inline posix_recursive_mutex::~posix_recursive_mutex() +{ + int res = pthread_mutex_destroy(&m_mut); + BOOST_ASSERT(res == 0);(void)res; +} + +inline void posix_recursive_mutex::lock() +{ + if (pthread_mutex_lock(&m_mut) != 0) + throw lock_exception(); +} + +inline bool posix_recursive_mutex::try_lock() +{ + int res = pthread_mutex_trylock(&m_mut); + if (!(res == 0 || res == EBUSY)) + throw lock_exception(); + return res == 0; +} + +inline bool posix_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS + //Posix does not support infinity absolute time so handle it here + if(abs_time == boost::posix_time::pos_infin){ + this->lock(); + return true; + } + + timespec ts = ptime_to_timespec(abs_time); + int res = pthread_mutex_timedlock(&m_mut, &ts); + if (res != 0 && res != ETIMEDOUT) + throw lock_exception(); + return res == 0; + + #else //BOOST_INTERPROCESS_POSIX_TIMEOUTS + + return ipcdetail::try_based_timed_lock(*this, abs_time); + + #endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS +} + +inline void posix_recursive_mutex::unlock() +{ + int res = 0; + res = pthread_mutex_unlock(&m_mut); + BOOST_ASSERT(res == 0); (void)res; +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/posix/semaphore.hpp b/libraries/boost/boost/interprocess/sync/posix/semaphore.hpp new file mode 100644 index 000000000..6fea766ed --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/posix/semaphore.hpp @@ -0,0 +1,67 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_HPP +#define BOOST_INTERPROCESS_POSIX_SEMAPHORE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class posix_semaphore +{ + posix_semaphore(); + posix_semaphore(const posix_semaphore&); + posix_semaphore &operator= (const posix_semaphore &); + + public: + posix_semaphore(unsigned int initialCount) + { semaphore_init(&m_sem, initialCount); } + + ~posix_semaphore() + { semaphore_destroy(&m_sem); } + + void post() + { semaphore_post(&m_sem); } + + void wait() + { semaphore_wait(&m_sem); } + + bool try_wait() + { return semaphore_try_wait(&m_sem); } + + bool timed_wait(const boost::posix_time::ptime &abs_time) + { return semaphore_timed_wait(&m_sem, abs_time); } + + private: + sem_t m_sem; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_HPP diff --git a/libraries/boost/boost/interprocess/sync/posix/semaphore_wrapper.hpp b/libraries/boost/boost/interprocess/sync/posix/semaphore_wrapper.hpp new file mode 100644 index 000000000..ca0f519b6 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/posix/semaphore_wrapper.hpp @@ -0,0 +1,253 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP +#define BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#include //O_CREAT, O_*... +#include //close +#include //std::string +#include //sem_* family, SEM_VALUE_MAX +#include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, +#include + +#ifdef SEM_FAILED +#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(SEM_FAILED)) +#else +#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(-1)) +#endif + +#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS +#include +#else +#include +#include +#include +#endif + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +#ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + +inline bool semaphore_open + (sem_t *&handle, create_enum_t type, const char *origname, + unsigned int count = 0, const permissions &perm = permissions()) +{ + std::string name; + #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES + add_leading_slash(origname, name); + #else + create_shared_dir_cleaning_old_and_get_filepath(origname, name); + #endif + + //Create new mapping + int oflag = 0; + switch(type){ + case DoOpen: + { + //No addition + handle = ::sem_open(name.c_str(), oflag); + } + break; + case DoOpenOrCreate: + case DoCreate: + { + while(1){ + oflag = (O_CREAT | O_EXCL); + handle = ::sem_open(name.c_str(), oflag, perm.get_permissions(), count); + if(handle != BOOST_INTERPROCESS_POSIX_SEM_FAILED){ + //We can't change semaphore permissions! + //::fchmod(handle, perm.get_permissions()); + break; + } + else if(errno == EEXIST && type == DoOpenOrCreate){ + oflag = 0; + if( (handle = ::sem_open(name.c_str(), oflag)) != BOOST_INTERPROCESS_POSIX_SEM_FAILED + || (errno != ENOENT) ){ + break; + } + } + else{ + break; + } + } + } + break; + default: + { + error_info err(other_error); + throw interprocess_exception(err); + } + } + + //Check for error + if(handle == BOOST_INTERPROCESS_POSIX_SEM_FAILED){ + throw interprocess_exception(error_info(errno)); + } + + return true; +} + +inline void semaphore_close(sem_t *handle) +{ + int ret = sem_close(handle); + if(ret != 0){ + BOOST_ASSERT(0); + } +} + +inline bool semaphore_unlink(const char *semname) +{ + try{ + std::string sem_str; + #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES + add_leading_slash(semname, sem_str); + #else + shared_filepath(semname, sem_str); + #endif + return 0 == sem_unlink(sem_str.c_str()); + } + catch(...){ + return false; + } +} + +#endif //BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + +#ifdef BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES + +inline void semaphore_init(sem_t *handle, unsigned int initialCount) +{ + int ret = sem_init(handle, 1, initialCount); + //According to SUSV3 version 2003 edition, the return value of a successful + //sem_init call is not defined, but -1 is returned on failure. + //In the future, a successful call might be required to return 0. + if(ret == -1){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } +} + +inline void semaphore_destroy(sem_t *handle) +{ + int ret = sem_destroy(handle); + if(ret != 0){ + BOOST_ASSERT(0); + } +} + +#endif //BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES + +inline void semaphore_post(sem_t *handle) +{ + int ret = sem_post(handle); + if(ret != 0){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } +} + +inline void semaphore_wait(sem_t *handle) +{ + int ret = sem_wait(handle); + if(ret != 0){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } +} + +inline bool semaphore_try_wait(sem_t *handle) +{ + int res = sem_trywait(handle); + if(res == 0) + return true; + if(system_error_code() == EAGAIN){ + return false; + } + error_info err = system_error_code(); + throw interprocess_exception(err); +} + +#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS + +struct semaphore_wrapper_try_wrapper +{ + explicit semaphore_wrapper_try_wrapper(sem_t *handle) + : m_handle(handle) + {} + + void wait() + { semaphore_wait(m_handle); } + + bool try_wait() + { return semaphore_try_wait(m_handle); } + + private: + sem_t *m_handle; +}; + +#endif + +inline bool semaphore_timed_wait(sem_t *handle, const boost::posix_time::ptime &abs_time) +{ + #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS + //Posix does not support infinity absolute time so handle it here + if(abs_time == boost::posix_time::pos_infin){ + semaphore_wait(handle); + return true; + } + + timespec tspec = ptime_to_timespec(abs_time); + for (;;){ + int res = sem_timedwait(handle, &tspec); + if(res == 0) + return true; + if (res > 0){ + //buggy glibc, copy the returned error code to errno + errno = res; + } + if(system_error_code() == ETIMEDOUT){ + return false; + } + error_info err = system_error_code(); + throw interprocess_exception(err); + } + return false; + #else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS + + semaphore_wrapper_try_wrapper swtw(handle); + ipcdetail::lock_to_wait lw(swtw); + return ipcdetail::try_based_timed_lock(lw, abs_time); + + #endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP diff --git a/libraries/boost/boost/interprocess/sync/scoped_lock.hpp b/libraries/boost/boost/interprocess/sync/scoped_lock.hpp new file mode 100644 index 000000000..97986f036 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/scoped_lock.hpp @@ -0,0 +1,377 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This interface is inspired by Howard Hinnant's lock proposal. +// http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SCOPED_LOCK_HPP +#define BOOST_INTERPROCESS_SCOPED_LOCK_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes the scoped_lock class. + +namespace boost { +namespace interprocess { + + +//!scoped_lock is meant to carry out the tasks for locking, unlocking, try-locking +//!and timed-locking (recursive or not) for the Mutex. The Mutex need not supply all +//!of this functionality. If the client of scoped_lock does not use +//!functionality which the Mutex does not supply, no harm is done. Mutex ownership +//!transfer is supported through the syntax of move semantics. Ownership transfer +//!is allowed both by construction and assignment. The scoped_lock does not support +//!copy semantics. A compile time error results if copy construction or copy +//!assignment is attempted. Mutex ownership can also be moved from an +//!upgradable_lock and sharable_lock via constructor. In this role, scoped_lock +//!shares the same functionality as a write_lock. +template +class scoped_lock +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef scoped_lock this_type; + BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_lock) + typedef bool this_type::*unspecified_bool_type; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + typedef Mutex mutex_type; + + //!Effects: Default constructs a scoped_lock. + //!Postconditions: owns() == false and mutex() == 0. + scoped_lock() + : mp_mutex(0), m_locked(false) + {} + + //!Effects: m.lock(). + //!Postconditions: owns() == true and mutex() == &m. + //!Notes: The constructor will take ownership of the mutex. If another thread + //! already owns the mutex, this thread will block until the mutex is released. + //! Whether or not this constructor handles recursive locking depends upon the mutex. + explicit scoped_lock(mutex_type& m) + : mp_mutex(&m), m_locked(false) + { mp_mutex->lock(); m_locked = true; } + + //!Postconditions: owns() == false, and mutex() == &m. + //!Notes: The constructor will not take ownership of the mutex. There is no effect + //! required on the referenced mutex. + scoped_lock(mutex_type& m, defer_lock_type) + : mp_mutex(&m), m_locked(false) + {} + + //!Postconditions: owns() == true, and mutex() == &m. + //!Notes: The constructor will suppose that the mutex is already locked. There + //! is no effect required on the referenced mutex. + scoped_lock(mutex_type& m, accept_ownership_type) + : mp_mutex(&m), m_locked(true) + {} + + //!Effects: m.try_lock(). + //!Postconditions: mutex() == &m. owns() == the return value of the + //! m.try_lock() executed within the constructor. + //!Notes: The constructor will take ownership of the mutex if it can do + //! so without waiting. Whether or not this constructor handles recursive + //! locking depends upon the mutex. If the mutex_type does not support try_lock, + //! this constructor will fail at compile time if instantiated, but otherwise + //! have no effect. + scoped_lock(mutex_type& m, try_to_lock_type) + : mp_mutex(&m), m_locked(mp_mutex->try_lock()) + {} + + //!Effects: m.timed_lock(abs_time). + //!Postconditions: mutex() == &m. owns() == the return value of the + //! m.timed_lock(abs_time) executed within the constructor. + //!Notes: The constructor will take ownership of the mutex if it can do + //! it until abs_time is reached. Whether or not this constructor + //! handles recursive locking depends upon the mutex. If the mutex_type + //! does not support try_lock, this constructor will fail at compile + //! time if instantiated, but otherwise have no effect. + scoped_lock(mutex_type& m, const boost::posix_time::ptime& abs_time) + : mp_mutex(&m), m_locked(mp_mutex->timed_lock(abs_time)) + {} + + //!Postconditions: mutex() == the value scop.mutex() had before the + //! constructor executes. s1.mutex() == 0. owns() == the value of + //! scop.owns() before the constructor executes. scop.owns(). + //!Notes: If the scop scoped_lock owns the mutex, ownership is moved + //! to thisscoped_lock with no blocking. If the scop scoped_lock does not + //! own the mutex, then neither will this scoped_lock. Only a moved + //! scoped_lock's will match this signature. An non-moved scoped_lock + //! can be moved with the expression: "boost::move(lock);". This + //! constructor does not alter the state of the mutex, only potentially + //! who owns it. + scoped_lock(BOOST_RV_REF(scoped_lock) scop) + : mp_mutex(0), m_locked(scop.owns()) + { mp_mutex = scop.release(); } + + //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock() on the + //! referenced mutex. upgr.release() is called. + //!Postconditions: mutex() == the value upgr.mutex() had before the construction. + //! upgr.mutex() == 0. owns() == upgr.owns() before the construction. + //! upgr.owns() == false after the construction. + //!Notes: If upgr is locked, this constructor will lock this scoped_lock while + //! unlocking upgr. If upgr is unlocked, then this scoped_lock will be + //! unlocked as well. Only a moved upgradable_lock's will match this + //! signature. An non-moved upgradable_lock can be moved with + //! the expression: "boost::move(lock);" This constructor may block if + //! other threads hold a sharable_lock on this mutex (sharable_lock's can + //! share ownership with an upgradable_lock). + template + explicit scoped_lock(BOOST_RV_REF(upgradable_lock) upgr + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + upgradable_lock &u_lock = upgr; + if(u_lock.owns()){ + u_lock.mutex()->unlock_upgradable_and_lock(); + m_locked = true; + } + mp_mutex = u_lock.release(); + } + + //!Effects: If upgr.owns() then calls try_unlock_upgradable_and_lock() on the + //!referenced mutex: + //! a)if try_unlock_upgradable_and_lock() returns true then mutex() obtains + //! the value from upgr.release() and owns() is set to true. + //! b)if try_unlock_upgradable_and_lock() returns false then upgr is + //! unaffected and this scoped_lock construction as the same effects as + //! a default construction. + //! c)Else upgr.owns() is false. mutex() obtains the value from upgr.release() + //! and owns() is set to false + //!Notes: This construction will not block. It will try to obtain mutex + //! ownership from upgr immediately, while changing the lock type from a + //! "read lock" to a "write lock". If the "read lock" isn't held in the + //! first place, the mutex merely changes type to an unlocked "write lock". + //! If the "read lock" is held, then mutex transfer occurs only if it can + //! do so in a non-blocking manner. + template + scoped_lock(BOOST_RV_REF(upgradable_lock) upgr, try_to_lock_type + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + upgradable_lock &u_lock = upgr; + if(u_lock.owns()){ + if((m_locked = u_lock.mutex()->try_unlock_upgradable_and_lock()) == true){ + mp_mutex = u_lock.release(); + } + } + else{ + u_lock.release(); + } + } + + //!Effects: If upgr.owns() then calls timed_unlock_upgradable_and_lock(abs_time) + //! on the referenced mutex: + //! a)if timed_unlock_upgradable_and_lock(abs_time) returns true then mutex() + //! obtains the value from upgr.release() and owns() is set to true. + //! b)if timed_unlock_upgradable_and_lock(abs_time) returns false then upgr + //! is unaffected and this scoped_lock construction as the same effects + //! as a default construction. + //! c)Else upgr.owns() is false. mutex() obtains the value from upgr.release() + //! and owns() is set to false + //!Notes: This construction will not block. It will try to obtain mutex ownership + //! from upgr immediately, while changing the lock type from a "read lock" to a + //! "write lock". If the "read lock" isn't held in the first place, the mutex + //! merely changes type to an unlocked "write lock". If the "read lock" is held, + //! then mutex transfer occurs only if it can do so in a non-blocking manner. + template + scoped_lock(BOOST_RV_REF(upgradable_lock) upgr, boost::posix_time::ptime &abs_time + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + upgradable_lock &u_lock = upgr; + if(u_lock.owns()){ + if((m_locked = u_lock.mutex()->timed_unlock_upgradable_and_lock(abs_time)) == true){ + mp_mutex = u_lock.release(); + } + } + else{ + u_lock.release(); + } + } + + //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock() on the + //!referenced mutex. + //! a)if try_unlock_sharable_and_lock() returns true then mutex() obtains + //! the value from shar.release() and owns() is set to true. + //! b)if try_unlock_sharable_and_lock() returns false then shar is + //! unaffected and this scoped_lock construction has the same + //! effects as a default construction. + //! c)Else shar.owns() is false. mutex() obtains the value from + //! shar.release() and owns() is set to false + //!Notes: This construction will not block. It will try to obtain mutex + //! ownership from shar immediately, while changing the lock type from a + //! "read lock" to a "write lock". If the "read lock" isn't held in the + //! first place, the mutex merely changes type to an unlocked "write lock". + //! If the "read lock" is held, then mutex transfer occurs only if it can + //! do so in a non-blocking manner. + template + scoped_lock(BOOST_RV_REF(sharable_lock) shar, try_to_lock_type + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + sharable_lock &s_lock = shar; + if(s_lock.owns()){ + if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock()) == true){ + mp_mutex = s_lock.release(); + } + } + else{ + s_lock.release(); + } + } + + //!Effects: if (owns()) mp_mutex->unlock(). + //!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/ + ~scoped_lock() + { + try{ if(m_locked && mp_mutex) mp_mutex->unlock(); } + catch(...){} + } + + //!Effects: If owns() before the call, then unlock() is called on mutex(). + //! *this gets the state of scop and scop gets set to a default constructed state. + //!Notes: With a recursive mutex it is possible that both this and scop own + //! the same mutex before the assignment. In this case, this will own the + //! mutex after the assignment (and scop will not), but the mutex's lock + //! count will be decremented by one. + scoped_lock &operator=(BOOST_RV_REF(scoped_lock) scop) + { + if(this->owns()) + this->unlock(); + m_locked = scop.owns(); + mp_mutex = scop.release(); + return *this; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls lock() on the referenced mutex. + //!Postconditions: owns() == true. + //!Notes: The scoped_lock changes from a state of not owning the mutex, to + //! owning the mutex, blocking if necessary. + void lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + mp_mutex->lock(); + m_locked = true; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls try_lock() on the referenced mutex. + //!Postconditions: owns() == the value returned from mutex()->try_lock(). + //!Notes: The scoped_lock changes from a state of not owning the mutex, to + //! owning the mutex, but only if blocking was not required. If the + //! mutex_type does not support try_lock(), this function will fail at + //! compile time if instantiated, but otherwise have no effect.*/ + bool try_lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock(); + return m_locked; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls timed_lock(abs_time) on the referenced mutex. + //!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time). + //!Notes: The scoped_lock changes from a state of not owning the mutex, to + //! owning the mutex, but only if it can obtain ownership by the specified + //! time. If the mutex_type does not support timed_lock (), this function + //! will fail at compile time if instantiated, but otherwise have no effect.*/ + bool timed_lock(const boost::posix_time::ptime& abs_time) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->timed_lock(abs_time); + return m_locked; + } + + //!Effects: If mutex() == 0 or if not locked, throws a lock_exception() + //! exception. Calls unlock() on the referenced mutex. + //!Postconditions: owns() == false. + //!Notes: The scoped_lock changes from a state of owning the mutex, to not + //! owning the mutex.*/ + void unlock() + { + if(!mp_mutex || !m_locked) + throw lock_exception(); + mp_mutex->unlock(); + m_locked = false; + } + + //!Effects: Returns true if this scoped_lock has acquired + //!the referenced mutex. + bool owns() const + { return m_locked && mp_mutex; } + + //!Conversion to bool. + //!Returns owns(). + operator unspecified_bool_type() const + { return m_locked? &this_type::m_locked : 0; } + + //!Effects: Returns a pointer to the referenced mutex, or 0 if + //!there is no mutex to reference. + mutex_type* mutex() const + { return mp_mutex; } + + //!Effects: Returns a pointer to the referenced mutex, or 0 if there is no + //! mutex to reference. + //!Postconditions: mutex() == 0 and owns() == false. + mutex_type* release() + { + mutex_type *mut = mp_mutex; + mp_mutex = 0; + m_locked = false; + return mut; + } + + //!Effects: Swaps state with moved lock. + //!Throws: Nothing. + void swap( scoped_lock &other) + { + (simple_swap)(mp_mutex, other.mp_mutex); + (simple_swap)(m_locked, other.m_locked); + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + mutex_type *mp_mutex; + bool m_locked; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_SCOPED_LOCK_HPP diff --git a/libraries/boost/boost/interprocess/sync/sharable_lock.hpp b/libraries/boost/boost/interprocess/sync/sharable_lock.hpp new file mode 100644 index 000000000..3df93ee1a --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/sharable_lock.hpp @@ -0,0 +1,310 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This interface is inspired by Howard Hinnant's lock proposal. +// http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SHARABLE_LOCK_HPP +#define BOOST_INTERPROCESS_SHARABLE_LOCK_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes the upgradable_lock class that serves to acquire the upgradable +//!lock of a mutex. + +namespace boost { +namespace interprocess { + + +//!sharable_lock is meant to carry out the tasks for sharable-locking +//!(such as read-locking), unlocking, try-sharable-locking and timed-sharable-locking +//!(recursive or not) for the Mutex. The Mutex need not supply all of this +//!functionality. If the client of sharable_lock does not use functionality which +//!the Mutex does not supply, no harm is done. Mutex ownership can be shared among +//!sharable_locks, and a single upgradable_lock. sharable_lock does not support +//!copy semantics. But sharable_lock supports ownership transfer from an sharable_lock, +//!upgradable_lock and scoped_lock via transfer_lock syntax.*/ +template +class sharable_lock +{ + public: + typedef SharableMutex mutex_type; + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef sharable_lock this_type; + explicit sharable_lock(scoped_lock&); + typedef bool this_type::*unspecified_bool_type; + BOOST_MOVABLE_BUT_NOT_COPYABLE(sharable_lock) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + //!Effects: Default constructs a sharable_lock. + //!Postconditions: owns() == false and mutex() == 0. + sharable_lock() + : mp_mutex(0), m_locked(false) + {} + + //!Effects: m.lock_sharable(). + //!Postconditions: owns() == true and mutex() == &m. + //!Notes: The constructor will take sharable-ownership of the mutex. If + //! another thread already owns the mutex with exclusive ownership + //! (scoped_lock), this thread will block until the mutex is released. + //! If another thread owns the mutex with sharable or upgradable ownership, + //! then no blocking will occur. Whether or not this constructor handles + //! recursive locking depends upon the mutex. + explicit sharable_lock(mutex_type& m) + : mp_mutex(&m), m_locked(false) + { mp_mutex->lock_sharable(); m_locked = true; } + + //!Postconditions: owns() == false, and mutex() == &m. + //!Notes: The constructor will not take ownership of the mutex. There is no effect + //! required on the referenced mutex. + sharable_lock(mutex_type& m, defer_lock_type) + : mp_mutex(&m), m_locked(false) + {} + + //!Postconditions: owns() == true, and mutex() == &m. + //!Notes: The constructor will suppose that the mutex is already sharable + //! locked. There is no effect required on the referenced mutex. + sharable_lock(mutex_type& m, accept_ownership_type) + : mp_mutex(&m), m_locked(true) + {} + + //!Effects: m.try_lock_sharable() + //!Postconditions: mutex() == &m. owns() == the return value of the + //! m.try_lock_sharable() executed within the constructor. + //!Notes: The constructor will take sharable-ownership of the mutex if it + //! can do so without waiting. Whether or not this constructor handles + //! recursive locking depends upon the mutex. If the mutex_type does not + //! support try_lock_sharable, this constructor will fail at compile + //! time if instantiated, but otherwise have no effect. + sharable_lock(mutex_type& m, try_to_lock_type) + : mp_mutex(&m), m_locked(false) + { m_locked = mp_mutex->try_lock_sharable(); } + + //!Effects: m.timed_lock_sharable(abs_time) + //!Postconditions: mutex() == &m. owns() == the return value of the + //! m.timed_lock_sharable() executed within the constructor. + //!Notes: The constructor will take sharable-ownership of the mutex if it + //! can do so within the time specified. Whether or not this constructor + //! handles recursive locking depends upon the mutex. If the mutex_type + //! does not support timed_lock_sharable, this constructor will fail at + //! compile time if instantiated, but otherwise have no effect. + sharable_lock(mutex_type& m, const boost::posix_time::ptime& abs_time) + : mp_mutex(&m), m_locked(false) + { m_locked = mp_mutex->timed_lock_sharable(abs_time); } + + //!Postconditions: mutex() == upgr.mutex(). owns() == the value of upgr.owns() + //! before the construction. upgr.owns() == false after the construction. + //!Notes: If the upgr sharable_lock owns the mutex, ownership is moved to this + //! sharable_lock with no blocking. If the upgr sharable_lock does not own the mutex, then + //! neither will this sharable_lock. Only a moved sharable_lock's will match this + //! signature. An non-moved sharable_lock can be moved with the expression: + //! "boost::move(lock);". This constructor does not alter the state of the mutex, + //! only potentially who owns it. + sharable_lock(BOOST_RV_REF(sharable_lock) upgr) + : mp_mutex(0), m_locked(upgr.owns()) + { mp_mutex = upgr.release(); } + + //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock_sharable() on the + //! referenced mutex. + //!Postconditions: mutex() == the value upgr.mutex() had before the construction. + //! upgr.mutex() == 0 owns() == the value of upgr.owns() before construction. + //! upgr.owns() == false after the construction. + //!Notes: If upgr is locked, this constructor will lock this sharable_lock while + //! unlocking upgr. Only a moved sharable_lock's will match this + //! signature. An non-moved upgradable_lock can be moved with the expression: + //! "boost::move(lock);".*/ + template + sharable_lock(BOOST_RV_REF(upgradable_lock) upgr + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + upgradable_lock &u_lock = upgr; + if(u_lock.owns()){ + u_lock.mutex()->unlock_upgradable_and_lock_sharable(); + m_locked = true; + } + mp_mutex = u_lock.release(); + } + + //!Effects: If scop.owns() then calls unlock_and_lock_sharable() on the + //! referenced mutex. + //!Postconditions: mutex() == the value scop.mutex() had before the construction. + //! scop.mutex() == 0 owns() == scop.owns() before the constructor. After the + //! construction, scop.owns() == false. + //!Notes: If scop is locked, this constructor will transfer the exclusive ownership + //! to a sharable-ownership of this sharable_lock. + //! Only a moved scoped_lock's will match this + //! signature. An non-moved scoped_lock can be moved with the expression: + //! "boost::move(lock);". + template + sharable_lock(BOOST_RV_REF(scoped_lock) scop + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + scoped_lock &e_lock = scop; + if(e_lock.owns()){ + e_lock.mutex()->unlock_and_lock_sharable(); + m_locked = true; + } + mp_mutex = e_lock.release(); + } + + //!Effects: if (owns()) mp_mutex->unlock_sharable(). + //!Notes: The destructor behavior ensures that the mutex lock is not leaked. + ~sharable_lock() + { + try{ + if(m_locked && mp_mutex) mp_mutex->unlock_sharable(); + } + catch(...){} + } + + //!Effects: If owns() before the call, then unlock_sharable() is called on mutex(). + //! *this gets the state of upgr and upgr gets set to a default constructed state. + //!Notes: With a recursive mutex it is possible that both this and upgr own the mutex + //! before the assignment. In this case, this will own the mutex after the assignment + //! (and upgr will not), but the mutex's lock count will be decremented by one. + sharable_lock &operator=(BOOST_RV_REF(sharable_lock) upgr) + { + if(this->owns()) + this->unlock(); + m_locked = upgr.owns(); + mp_mutex = upgr.release(); + return *this; + } + + //!Effects: If mutex() == 0 or already locked, throws a lock_exception() + //! exception. Calls lock_sharable() on the referenced mutex. + //!Postconditions: owns() == true. + //!Notes: The sharable_lock changes from a state of not owning the + //! mutex, to owning the mutex, blocking if necessary. + void lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + mp_mutex->lock_sharable(); + m_locked = true; + } + + //!Effects: If mutex() == 0 or already locked, throws a lock_exception() + //! exception. Calls try_lock_sharable() on the referenced mutex. + //!Postconditions: owns() == the value returned from + //! mutex()->try_lock_sharable(). + //!Notes: The sharable_lock changes from a state of not owning the mutex, + //! to owning the mutex, but only if blocking was not required. If the + //! mutex_type does not support try_lock_sharable(), this function will + //! fail at compile time if instantiated, but otherwise have no effect. + bool try_lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock_sharable(); + return m_locked; + } + + //!Effects: If mutex() == 0 or already locked, throws a lock_exception() + //! exception. Calls timed_lock_sharable(abs_time) on the referenced mutex. + //!Postconditions: owns() == the value returned from + //! mutex()->timed_lock_sharable(elps_time). + //!Notes: The sharable_lock changes from a state of not owning the mutex, + //! to owning the mutex, but only if it can obtain ownership within the + //! specified time interval. If the mutex_type does not support + //! timed_lock_sharable(), this function will fail at compile time if + //! instantiated, but otherwise have no effect. + bool timed_lock(const boost::posix_time::ptime& abs_time) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->timed_lock_sharable(abs_time); + return m_locked; + } + + //!Effects: If mutex() == 0 or not locked, throws a lock_exception() exception. + //! Calls unlock_sharable() on the referenced mutex. + //!Postconditions: owns() == false. + //!Notes: The sharable_lock changes from a state of owning the mutex, to + //! not owning the mutex. + void unlock() + { + if(!mp_mutex || !m_locked) + throw lock_exception(); + mp_mutex->unlock_sharable(); + m_locked = false; + } + + //!Effects: Returns true if this scoped_lock has + //!acquired the referenced mutex. + bool owns() const + { return m_locked && mp_mutex; } + + //!Conversion to bool. + //!Returns owns(). + operator unspecified_bool_type() const + { return m_locked? &this_type::m_locked : 0; } + + //!Effects: Returns a pointer to the referenced mutex, or 0 if + //!there is no mutex to reference. + mutex_type* mutex() const + { return mp_mutex; } + + //!Effects: Returns a pointer to the referenced mutex, or 0 if there is no + //! mutex to reference. + //!Postconditions: mutex() == 0 and owns() == false. + mutex_type* release() + { + mutex_type *mut = mp_mutex; + mp_mutex = 0; + m_locked = false; + return mut; + } + + //!Effects: Swaps state with moved lock. + //!Throws: Nothing. + void swap(sharable_lock &other) + { + (simple_swap)(mp_mutex, other.mp_mutex); + (simple_swap)(m_locked, other.m_locked); + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + mutex_type *mp_mutex; + bool m_locked; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_SHARABLE_LOCK_HPP diff --git a/libraries/boost/boost/interprocess/sync/shm/named_condition.hpp b/libraries/boost/boost/interprocess/sync/shm/named_condition.hpp new file mode 100644 index 000000000..e58f5ded7 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/shm/named_condition.hpp @@ -0,0 +1,239 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SHM_NAMED_CONDITION_HPP +#define BOOST_INTERPROCESS_SHM_NAMED_CONDITION_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined (BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES) + #include + #include + #include +#else + #include +#endif + + +//!\file +//!Describes process-shared variables interprocess_condition class + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +class interprocess_tester; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//! A global condition variable that can be created by name. +//! This condition variable is designed to work with named_mutex and +//! can't be placed in shared memory or memory mapped files. +class shm_named_condition +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + shm_named_condition(); + shm_named_condition(const shm_named_condition &); + shm_named_condition &operator=(const shm_named_condition &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + //!Creates a global condition with a name. + //!If the condition can't be created throws interprocess_exception + shm_named_condition(create_only_t create_only, const char *name, const permissions &perm = permissions()); + + //!Opens or creates a global condition with a name. + //!If the condition is created, this call is equivalent to + //!shm_named_condition(create_only_t, ... ) + //!If the condition is already created, this call is equivalent + //!shm_named_condition(open_only_t, ... ) + //!Does not throw + shm_named_condition(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()); + + //!Opens a global condition with a name if that condition is previously + //!created. If it is not previously created this function throws + //!interprocess_exception. + shm_named_condition(open_only_t open_only, const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~shm_named_condition(); + + //!If there is a thread waiting on *this, change that + //!thread's state to ready. Otherwise there is no effect.*/ + void notify_one(); + + //!Change the state of all threads waiting on *this to ready. + //!If there are no waiting threads, notify_all() has no effect. + void notify_all(); + + //!Releases the lock on the named_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), and then reacquires the lock. + template + void wait(L& lock); + + //!The same as: + //!while (!pred()) wait(lock) + template + void wait(L& lock, Pr pred); + + //!Releases the lock on the named_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), or until time abs_time is reached, + //!and then reacquires the lock. + //!Returns: false if time abs_time is reached, otherwise true. + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time); + + //!The same as: while (!pred()) { + //! if (!timed_wait(lock, abs_time)) return pred(); + //! } return true; + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred); + + //!Erases a named condition from the system. + //!Returns false on error. Never throws. + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + + #if defined (BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES) + class internal_condition_members + { + public: + typedef interprocess_mutex mutex_type; + typedef interprocess_condition condvar_type; + + condvar_type& get_condvar() { return m_cond; } + mutex_type& get_mutex() { return m_mtx; } + + private: + mutex_type m_mtx; + condvar_type m_cond; + }; + + typedef ipcdetail::condition_any_wrapper internal_condition; + #else //defined (BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES) + typedef interprocess_condition internal_condition; + #endif //defined (BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES) + + internal_condition &internal_cond() + { return *static_cast(m_shmem.get_user_address()); } + + friend class boost::interprocess::ipcdetail::interprocess_tester; + void dont_close_on_destruction(); + + typedef ipcdetail::managed_open_or_create_impl open_create_impl_t; + open_create_impl_t m_shmem; + + template friend class boost::interprocess::ipcdetail::named_creation_functor; + typedef boost::interprocess::ipcdetail::named_creation_functor construct_func_t; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline shm_named_condition::~shm_named_condition() +{} + +inline shm_named_condition::shm_named_condition(create_only_t, const char *name, const permissions &perm) + : m_shmem (create_only + ,name + ,sizeof(internal_condition) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(DoCreate) + ,perm) +{} + +inline shm_named_condition::shm_named_condition(open_or_create_t, const char *name, const permissions &perm) + : m_shmem (open_or_create + ,name + ,sizeof(internal_condition) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(DoOpenOrCreate) + ,perm) +{} + +inline shm_named_condition::shm_named_condition(open_only_t, const char *name) + : m_shmem (open_only + ,name + ,read_write + ,0 + ,construct_func_t(DoOpen)) +{} + +inline void shm_named_condition::dont_close_on_destruction() +{ interprocess_tester::dont_close_on_destruction(m_shmem); } + +inline void shm_named_condition::notify_one() +{ this->internal_cond().notify_one(); } + +inline void shm_named_condition::notify_all() +{ this->internal_cond().notify_all(); } + +template +inline void shm_named_condition::wait(L& lock) +{ this->internal_cond().wait(lock); } + +template +inline void shm_named_condition::wait(L& lock, Pr pred) +{ this->internal_cond().wait(lock, pred); } + +template +inline bool shm_named_condition::timed_wait + (L& lock, const boost::posix_time::ptime &abs_time) +{ return this->internal_cond().timed_wait(lock, abs_time); } + +template +inline bool shm_named_condition::timed_wait + (L& lock, const boost::posix_time::ptime &abs_time, Pr pred) +{ return this->internal_cond().timed_wait(lock, abs_time, pred); } + +inline bool shm_named_condition::remove(const char *name) +{ return shared_memory_object::remove(name); } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include + +#endif // BOOST_INTERPROCESS_SHM_NAMED_CONDITION_HPP diff --git a/libraries/boost/boost/interprocess/sync/shm/named_condition_any.hpp b/libraries/boost/boost/interprocess/sync/shm/named_condition_any.hpp new file mode 100644 index 000000000..6eb06b48e --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/shm/named_condition_any.hpp @@ -0,0 +1,195 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SHM_NAMED_CONDITION_ANY_HPP +#define BOOST_INTERPROCESS_SHM_NAMED_CONDITION_ANY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes process-shared variables interprocess_condition class + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +class interprocess_tester; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//! A global condition variable that can be created by name. +//! This condition variable is designed to work with named_mutex and +//! can't be placed in shared memory or memory mapped files. +class shm_named_condition_any +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + shm_named_condition_any(); + shm_named_condition_any(const shm_named_condition_any &); + shm_named_condition_any &operator=(const shm_named_condition_any &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + //!Creates a global condition with a name. + //!If the condition can't be created throws interprocess_exception + shm_named_condition_any(create_only_t create_only, const char *name, const permissions &perm = permissions()) + : m_shmem (create_only + ,name + ,sizeof(internal_condition) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(DoCreate) + ,perm) + {} + + //!Opens or creates a global condition with a name. + //!If the condition is created, this call is equivalent to + //!shm_named_condition_any(create_only_t, ... ) + //!If the condition is already created, this call is equivalent + //!shm_named_condition_any(open_only_t, ... ) + //!Does not throw + shm_named_condition_any(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()) + : m_shmem (open_or_create + ,name + ,sizeof(internal_condition) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(DoOpenOrCreate) + ,perm) + {} + + //!Opens a global condition with a name if that condition is previously + //!created. If it is not previously created this function throws + //!interprocess_exception. + shm_named_condition_any(open_only_t open_only, const char *name) + : m_shmem (open_only + ,name + ,read_write + ,0 + ,construct_func_t(DoOpen)) + {} + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~shm_named_condition_any() + {} + + //!If there is a thread waiting on *this, change that + //!thread's state to ready. Otherwise there is no effect.*/ + void notify_one() + { m_cond.notify_one(); } + + //!Change the state of all threads waiting on *this to ready. + //!If there are no waiting threads, notify_all() has no effect. + void notify_all() + { m_cond.notify_all(); } + + //!Releases the lock on the named_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), and then reacquires the lock. + template + void wait(L& lock) + { m_cond.wait(lock); } + + //!The same as: + //!while (!pred()) wait(lock) + template + void wait(L& lock, Pr pred) + { m_cond.wait(lock, pred); } + + //!Releases the lock on the named_mutex object associated with lock, blocks + //!the current thread of execution until readied by a call to + //!this->notify_one() or this->notify_all(), or until time abs_time is reached, + //!and then reacquires the lock. + //!Returns: false if time abs_time is reached, otherwise true. + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { return m_cond.timed_wait(lock, abs_time); } + + //!The same as: while (!pred()) { + //! if (!timed_wait(lock, abs_time)) return pred(); + //! } return true; + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { return m_cond.timed_wait(lock, abs_time, pred); } + + //!Erases a named condition from the system. + //!Returns false on error. Never throws. + static bool remove(const char *name) + { return shared_memory_object::remove(name); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + + class internal_condition_members + { + public: + typedef interprocess_mutex mutex_type; + typedef interprocess_condition condvar_type; + + condvar_type& get_condvar() { return m_cond; } + mutex_type& get_mutex() { return m_mtx; } + + private: + mutex_type m_mtx; + condvar_type m_cond; + }; + + typedef ipcdetail::condition_any_wrapper internal_condition; + + internal_condition m_cond; + + friend class boost::interprocess::ipcdetail::interprocess_tester; + void dont_close_on_destruction() + { interprocess_tester::dont_close_on_destruction(m_shmem); } + + typedef ipcdetail::managed_open_or_create_impl open_create_impl_t; + open_create_impl_t m_shmem; + + template friend class boost::interprocess::ipcdetail::named_creation_functor; + typedef boost::interprocess::ipcdetail::named_creation_functor construct_func_t; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include + +#endif // BOOST_INTERPROCESS_SHM_NAMED_CONDITION_ANY_HPP diff --git a/libraries/boost/boost/interprocess/sync/shm/named_creation_functor.hpp b/libraries/boost/boost/interprocess/sync/shm/named_creation_functor.hpp new file mode 100644 index 000000000..137a1a8ea --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/shm/named_creation_functor.hpp @@ -0,0 +1,81 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP +#define BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +struct named_creation_functor_no_arg{}; + +template +class named_creation_functor +{ + typedef named_creation_functor_no_arg no_arg_t; + public: + named_creation_functor(create_enum_t type, Arg arg = Arg()) + : m_creation_type(type), m_arg(arg){} + + template + void construct(void *address, typename enable_if_c::value>::type * = 0) const + { ::new(address, boost_container_new_t())T; } + + template + void construct(void *address, typename enable_if_c::value>::type * = 0) const + { ::new(address, boost_container_new_t())T(m_arg); } + + bool operator()(void *address, std::size_t, bool created) const + { + switch(m_creation_type){ + case DoOpen: + return true; + break; + case DoCreate: + case DoOpenOrCreate: + if(created){ + construct(address); + } + return true; + break; + + default: + return false; + break; + } + } + + static std::size_t get_min_size() + { return sizeof(T); } + + private: + create_enum_t m_creation_type; + Arg m_arg; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#endif //BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP diff --git a/libraries/boost/boost/interprocess/sync/shm/named_mutex.hpp b/libraries/boost/boost/interprocess/sync/shm/named_mutex.hpp new file mode 100644 index 000000000..846727463 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/shm/named_mutex.hpp @@ -0,0 +1,181 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SHM_NAMED_MUTEX_HPP +#define BOOST_INTERPROCESS_SHM_NAMED_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +//!\file +//!Describes a named mutex class for inter-process synchronization + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class named_condition; + +//!A mutex with a global name, so it can be found from different +//!processes. This mutex can't be placed in shared memory, and +//!each process should have it's own named mutex. +class shm_named_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + shm_named_mutex(); + shm_named_mutex(const shm_named_mutex &); + shm_named_mutex &operator=(const shm_named_mutex &); + friend class named_condition; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Creates a global interprocess_mutex with a name. + //!Throws interprocess_exception on error. + shm_named_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions()); + + //!Opens or creates a global mutex with a name. + //!If the mutex is created, this call is equivalent to + //!shm_named_mutex(create_only_t, ... ) + //!If the mutex is already created, this call is equivalent + //!shm_named_mutex(open_only_t, ... ) + //!Does not throw + shm_named_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()); + + //!Opens a global mutex with a name if that mutex is previously + //!created. If it is not previously created this function throws + //!interprocess_exception. + shm_named_mutex(open_only_t open_only, const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~shm_named_mutex(); + + //!Unlocks a previously locked + //!interprocess_mutex. + void unlock(); + + //!Locks interprocess_mutex, sleeps when interprocess_mutex is already locked. + //!Throws interprocess_exception if a severe error is found + void lock(); + + //!Tries to lock the interprocess_mutex, returns false when interprocess_mutex + //!is already locked, returns true when success. + //!Throws interprocess_exception if a severe error is found + bool try_lock(); + + //!Tries to lock the interprocess_mutex until time abs_time, + //!Returns false when timeout expires, returns true when locks. + //!Throws interprocess_exception if a severe error is found + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Erases a named mutex from the system. + //!Returns false on error. Never throws. + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef interprocess_mutex internal_mutex_type; + interprocess_mutex &internal_mutex() + { return *static_cast(m_shmem.get_user_address()); } + + private: + friend class ipcdetail::interprocess_tester; + void dont_close_on_destruction(); + typedef ipcdetail::managed_open_or_create_impl open_create_impl_t; + open_create_impl_t m_shmem; + typedef ipcdetail::named_creation_functor construct_func_t; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline void shm_named_mutex::dont_close_on_destruction() +{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); } + +inline shm_named_mutex::~shm_named_mutex() +{} + +inline shm_named_mutex::shm_named_mutex(create_only_t, const char *name, const permissions &perm) + : m_shmem (create_only + ,name + ,sizeof(interprocess_mutex) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoCreate) + ,perm) +{} + +inline shm_named_mutex::shm_named_mutex(open_or_create_t, const char *name, const permissions &perm) + : m_shmem (open_or_create + ,name + ,sizeof(interprocess_mutex) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoOpenOrCreate) + ,perm) +{} + +inline shm_named_mutex::shm_named_mutex(open_only_t, const char *name) + : m_shmem (open_only + ,name + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoOpen)) +{} + +inline void shm_named_mutex::lock() +{ this->internal_mutex().lock(); } + +inline void shm_named_mutex::unlock() +{ this->internal_mutex().unlock(); } + +inline bool shm_named_mutex::try_lock() +{ return this->internal_mutex().try_lock(); } + +inline bool shm_named_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return this->internal_mutex().timed_lock(abs_time); } + +inline bool shm_named_mutex::remove(const char *name) +{ return shared_memory_object::remove(name); } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_SHM_NAMED_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/shm/named_recursive_mutex.hpp b/libraries/boost/boost/interprocess/sync/shm/named_recursive_mutex.hpp new file mode 100644 index 000000000..345eedaf5 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/shm/named_recursive_mutex.hpp @@ -0,0 +1,171 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SHM_NAMED_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_SHM_NAMED_RECURSIVE_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes a named shm_named_recursive_mutex class for inter-process synchronization + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +class interprocess_tester; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +class shm_named_recursive_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + shm_named_recursive_mutex(); + shm_named_recursive_mutex(const shm_named_recursive_mutex &); + shm_named_recursive_mutex &operator=(const shm_named_recursive_mutex &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + //!Creates a global recursive_mutex with a name. + //!If the recursive_mutex can't be created throws interprocess_exception + shm_named_recursive_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions()); + + //!Opens or creates a global recursive_mutex with a name. + //!If the recursive_mutex is created, this call is equivalent to + //!shm_named_recursive_mutex(create_only_t, ... ) + //!If the recursive_mutex is already created, this call is equivalent + //!shm_named_recursive_mutex(open_only_t, ... ) + //!Does not throw + shm_named_recursive_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()); + + //!Opens a global recursive_mutex with a name if that recursive_mutex is previously + //!created. If it is not previously created this function throws + //!interprocess_exception. + shm_named_recursive_mutex(open_only_t open_only, const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~shm_named_recursive_mutex(); + + //!Unlocks a previously locked + //!shm_named_recursive_mutex. + void unlock(); + + //!Locks shm_named_recursive_mutex, sleeps when shm_named_recursive_mutex is already locked. + //!Throws interprocess_exception if a severe error is found. + void lock(); + + //!Tries to lock the shm_named_recursive_mutex, returns false when shm_named_recursive_mutex + //!is already locked, returns true when success. + //!Throws interprocess_exception if a severe error is found. + bool try_lock(); + + //!Tries to lock the shm_named_recursive_mutex until time abs_time, + //!Returns false when timeout expires, returns true when locks. + //!Throws interprocess_exception if a severe error is found + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Erases a named recursive mutex + //!from the system + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class interprocess_tester; + void dont_close_on_destruction(); + + interprocess_recursive_mutex *mutex() const + { return static_cast(m_shmem.get_user_address()); } + typedef ipcdetail::managed_open_or_create_impl open_create_impl_t; + open_create_impl_t m_shmem; + typedef named_creation_functor construct_func_t; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +inline shm_named_recursive_mutex::~shm_named_recursive_mutex() +{} + +inline void shm_named_recursive_mutex::dont_close_on_destruction() +{ interprocess_tester::dont_close_on_destruction(m_shmem); } + +inline shm_named_recursive_mutex::shm_named_recursive_mutex(create_only_t, const char *name, const permissions &perm) + : m_shmem (create_only + ,name + ,sizeof(interprocess_recursive_mutex) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(DoCreate) + ,perm) +{} + +inline shm_named_recursive_mutex::shm_named_recursive_mutex(open_or_create_t, const char *name, const permissions &perm) + : m_shmem (open_or_create + ,name + ,sizeof(interprocess_recursive_mutex) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(DoOpenOrCreate) + ,perm) +{} + +inline shm_named_recursive_mutex::shm_named_recursive_mutex(open_only_t, const char *name) + : m_shmem (open_only + ,name + ,read_write + ,0 + ,construct_func_t(DoOpen)) +{} + +inline void shm_named_recursive_mutex::lock() +{ this->mutex()->lock(); } + +inline void shm_named_recursive_mutex::unlock() +{ this->mutex()->unlock(); } + +inline bool shm_named_recursive_mutex::try_lock() +{ return this->mutex()->try_lock(); } + +inline bool shm_named_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_lock(abs_time); } + +inline bool shm_named_recursive_mutex::remove(const char *name) +{ return shared_memory_object::remove(name); } + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_SHM_NAMED_RECURSIVE_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/shm/named_semaphore.hpp b/libraries/boost/boost/interprocess/sync/shm/named_semaphore.hpp new file mode 100644 index 000000000..4ac93e08f --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/shm/named_semaphore.hpp @@ -0,0 +1,138 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SHM_NAMED_SEMAPHORE_HPP +#define BOOST_INTERPROCESS_SHM_NAMED_SEMAPHORE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class shm_named_semaphore +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + shm_named_semaphore(); + shm_named_semaphore(const shm_named_semaphore &); + shm_named_semaphore &operator=(const shm_named_semaphore &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + shm_named_semaphore(create_only_t, const char *name, unsigned int initialCount, const permissions &perm = permissions()); + + shm_named_semaphore(open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm = permissions()); + + shm_named_semaphore(open_only_t, const char *name); + + ~shm_named_semaphore(); + + void post(); + void wait(); + bool try_wait(); + bool timed_wait(const boost::posix_time::ptime &abs_time); + + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class interprocess_tester; + void dont_close_on_destruction(); + + interprocess_semaphore *semaphore() const + { return static_cast(m_shmem.get_user_address()); } + + typedef ipcdetail::managed_open_or_create_impl open_create_impl_t; + open_create_impl_t m_shmem; + typedef named_creation_functor construct_func_t; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +inline shm_named_semaphore::~shm_named_semaphore() +{} + +inline void shm_named_semaphore::dont_close_on_destruction() +{ interprocess_tester::dont_close_on_destruction(m_shmem); } + +inline shm_named_semaphore::shm_named_semaphore + (create_only_t, const char *name, unsigned int initialCount, const permissions &perm) + : m_shmem (create_only + ,name + ,sizeof(interprocess_semaphore) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(DoCreate, initialCount) + ,perm) +{} + +inline shm_named_semaphore::shm_named_semaphore + (open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm) + : m_shmem (open_or_create + ,name + ,sizeof(interprocess_semaphore) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(DoOpenOrCreate, initialCount) + ,perm) +{} + +inline shm_named_semaphore::shm_named_semaphore + (open_only_t, const char *name) + : m_shmem (open_only + ,name + ,read_write + ,0 + ,construct_func_t(DoOpen, 0)) +{} + +inline void shm_named_semaphore::post() +{ semaphore()->post(); } + +inline void shm_named_semaphore::wait() +{ semaphore()->wait(); } + +inline bool shm_named_semaphore::try_wait() +{ return semaphore()->try_wait(); } + +inline bool shm_named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +{ return semaphore()->timed_wait(abs_time); } + +inline bool shm_named_semaphore::remove(const char *name) +{ return shared_memory_object::remove(name); } + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_SHM_NAMED_SEMAPHORE_HPP diff --git a/libraries/boost/boost/interprocess/sync/shm/named_upgradable_mutex.hpp b/libraries/boost/boost/interprocess/sync/shm/named_upgradable_mutex.hpp new file mode 100644 index 000000000..ced2243be --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/shm/named_upgradable_mutex.hpp @@ -0,0 +1,357 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NAMED_UPGRADABLE_MUTEX_HPP +#define BOOST_INTERPROCESS_NAMED_UPGRADABLE_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes a named upgradable mutex class for inter-process synchronization + +namespace boost { +namespace interprocess { + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +namespace ipcdetail{ class interprocess_tester; } +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +class named_condition; + +//!A upgradable mutex with a global name, so it can be found from different +//!processes. This mutex can't be placed in shared memory, and +//!each process should have it's own named upgradable mutex. +class named_upgradable_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable + named_upgradable_mutex(); + named_upgradable_mutex(const named_upgradable_mutex &); + named_upgradable_mutex &operator=(const named_upgradable_mutex &); + friend class named_condition; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + //!Creates a global upgradable mutex with a name. + //!If the upgradable mutex can't be created throws interprocess_exception + named_upgradable_mutex(create_only_t create_only, const char *name, const permissions &perm = permissions()); + + //!Opens or creates a global upgradable mutex with a name, and an initial count. + //!If the upgradable mutex is created, this call is equivalent to + //!named_upgradable_mutex(create_only_t, ...) + //!If the upgradable mutex is already created, this call is equivalent to + //!named_upgradable_mutex(open_only_t, ... ). + named_upgradable_mutex(open_or_create_t open_or_create, const char *name, const permissions &perm = permissions()); + + //!Opens a global upgradable mutex with a name if that upgradable mutex + //!is previously. + //!created. If it is not previously created this function throws + //!interprocess_exception. + named_upgradable_mutex(open_only_t open_only, const char *name); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~named_upgradable_mutex(); + + //Exclusive locking + + //!Effects: The calling thread tries to obtain exclusive ownership of the mutex, + //! and if another thread has exclusive, sharable or upgradable ownership of + //! the mutex, it waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! without waiting. If no other thread has exclusive, sharable or upgradable + //! ownership of the mutex this succeeds. + //!Returns: If it can acquire exclusive ownership immediately returns true. + //! If it has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock(); + + //!Effects: The calling thread tries to acquire exclusive ownership of the mutex + //! waiting if necessary until no other thread has exclusive, sharable or + //! upgradable ownership of the mutex or abs_time is reached. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The calling thread releases the exclusive ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock(); + + //Sharable locking + + //!Effects: The calling thread tries to obtain sharable ownership of the mutex, + //! and if another thread has exclusive ownership of the mutex, + //! waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! without waiting. If no other thread has exclusive ownership + //! of the mutex this succeeds. + //!Returns: If it can acquire sharable ownership immediately returns true. If it + //! has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock_sharable(); + + //!Effects: The calling thread tries to acquire sharable ownership of the mutex + //! waiting if necessary until no other thread has exclusive + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires sharable ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock_sharable(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The calling thread releases the sharable ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_sharable(); + + //Upgradable locking + + //!Effects: The calling thread tries to obtain upgradable ownership of the mutex, + //! and if another thread has exclusive or upgradable ownership of the mutex, + //! waits until it can obtain the ownership. + //!Throws: interprocess_exception on error. + void lock_upgradable(); + + //!Effects: The calling thread tries to acquire upgradable ownership of the mutex + //! without waiting. If no other thread has exclusive or upgradable ownership + //! of the mutex this succeeds. + //!Returns: If it can acquire upgradable ownership immediately returns true. + //! If it has to wait, returns false. + //!Throws: interprocess_exception on error. + bool try_lock_upgradable(); + + //!Effects: The calling thread tries to acquire upgradable ownership of the mutex + //! waiting if necessary until no other thread has exclusive or upgradable + //! ownership of the mutex or abs_time is reached. + //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false. + //!Throws: interprocess_exception on error. + bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The calling thread releases the upgradable ownership of the mutex. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_upgradable(); + + //Demotions + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The thread atomically releases exclusive ownership and acquires + //! upgradable ownership. This operation is non-blocking. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_and_lock_upgradable(); + + //!Precondition: The thread must have exclusive ownership of the mutex. + //!Effects: The thread atomically releases exclusive ownership and acquires + //! sharable ownership. This operation is non-blocking. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_and_lock_sharable(); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and acquires + //! sharable ownership. This operation is non-blocking. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_upgradable_and_lock_sharable(); + + //Promotions + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and acquires + //! exclusive ownership. This operation will block until all threads with + //! sharable ownership release it. + //!Throws: An exception derived from interprocess_exception on error. + void unlock_upgradable_and_lock(); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and tries to + //! acquire exclusive ownership. This operation will fail if there are threads + //! with sharable ownership, but it will maintain upgradable ownership. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. + bool try_unlock_upgradable_and_lock(); + + //!Precondition: The thread must have upgradable ownership of the mutex. + //!Effects: The thread atomically releases upgradable ownership and tries to acquire + //! exclusive ownership, waiting if necessary until abs_time. This operation will + //! fail if there are threads with sharable ownership or timeout reaches, but it + //! will maintain upgradable ownership. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. + bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time); + + //!Precondition: The thread must have sharable ownership of the mutex. + //!Effects: The thread atomically releases sharable ownership and tries to acquire + //! exclusive ownership. This operation will fail if there are threads with sharable + //! or upgradable ownership, but it will maintain sharable ownership. + //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. + //!Throws: An exception derived from interprocess_exception on error. + bool try_unlock_sharable_and_lock(); + + bool try_unlock_sharable_and_lock_upgradable(); + + //!Erases a named upgradable mutex from the system. + //!Returns false on error. Never throws. + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class ipcdetail::interprocess_tester; + void dont_close_on_destruction(); + + interprocess_upgradable_mutex *mutex() const + { return static_cast(m_shmem.get_user_address()); } + + typedef ipcdetail::managed_open_or_create_impl open_create_impl_t; + open_create_impl_t m_shmem; + typedef ipcdetail::named_creation_functor construct_func_t; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline named_upgradable_mutex::~named_upgradable_mutex() +{} + +inline named_upgradable_mutex::named_upgradable_mutex + (create_only_t, const char *name, const permissions &perm) + : m_shmem (create_only + ,name + ,sizeof(interprocess_upgradable_mutex) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoCreate) + ,perm) +{} + +inline named_upgradable_mutex::named_upgradable_mutex + (open_or_create_t, const char *name, const permissions &perm) + : m_shmem (open_or_create + ,name + ,sizeof(interprocess_upgradable_mutex) + + open_create_impl_t::ManagedOpenOrCreateUserOffset + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoOpenOrCreate) + ,perm) +{} + +inline named_upgradable_mutex::named_upgradable_mutex + (open_only_t, const char *name) + : m_shmem (open_only + ,name + ,read_write + ,0 + ,construct_func_t(ipcdetail::DoOpen)) +{} + +inline void named_upgradable_mutex::dont_close_on_destruction() +{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_shmem); } + +inline void named_upgradable_mutex::lock() +{ this->mutex()->lock(); } + +inline void named_upgradable_mutex::unlock() +{ this->mutex()->unlock(); } + +inline bool named_upgradable_mutex::try_lock() +{ return this->mutex()->try_lock(); } + +inline bool named_upgradable_mutex::timed_lock + (const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_lock(abs_time); } + +inline void named_upgradable_mutex::lock_upgradable() +{ this->mutex()->lock_upgradable(); } + +inline void named_upgradable_mutex::unlock_upgradable() +{ this->mutex()->unlock_upgradable(); } + +inline bool named_upgradable_mutex::try_lock_upgradable() +{ return this->mutex()->try_lock_upgradable(); } + +inline bool named_upgradable_mutex::timed_lock_upgradable + (const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_lock_upgradable(abs_time); } + +inline void named_upgradable_mutex::lock_sharable() +{ this->mutex()->lock_sharable(); } + +inline void named_upgradable_mutex::unlock_sharable() +{ this->mutex()->unlock_sharable(); } + +inline bool named_upgradable_mutex::try_lock_sharable() +{ return this->mutex()->try_lock_sharable(); } + +inline bool named_upgradable_mutex::timed_lock_sharable + (const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_lock_sharable(abs_time); } + +inline void named_upgradable_mutex::unlock_and_lock_upgradable() +{ this->mutex()->unlock_and_lock_upgradable(); } + +inline void named_upgradable_mutex::unlock_and_lock_sharable() +{ this->mutex()->unlock_and_lock_sharable(); } + +inline void named_upgradable_mutex::unlock_upgradable_and_lock_sharable() +{ this->mutex()->unlock_upgradable_and_lock_sharable(); } + +inline void named_upgradable_mutex::unlock_upgradable_and_lock() +{ this->mutex()->unlock_upgradable_and_lock(); } + +inline bool named_upgradable_mutex::try_unlock_upgradable_and_lock() +{ return this->mutex()->try_unlock_upgradable_and_lock(); } + +inline bool named_upgradable_mutex::timed_unlock_upgradable_and_lock + (const boost::posix_time::ptime &abs_time) +{ return this->mutex()->timed_unlock_upgradable_and_lock(abs_time); } + +inline bool named_upgradable_mutex::try_unlock_sharable_and_lock() +{ return this->mutex()->try_unlock_sharable_and_lock(); } + +inline bool named_upgradable_mutex::try_unlock_sharable_and_lock_upgradable() +{ return this->mutex()->try_unlock_sharable_and_lock_upgradable(); } + +inline bool named_upgradable_mutex::remove(const char *name) +{ return shared_memory_object::remove(name); } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_NAMED_UPGRADABLE_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/spin/condition.hpp b/libraries/boost/boost/interprocess/sync/spin/condition.hpp new file mode 100644 index 000000000..1a1878b8a --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/spin/condition.hpp @@ -0,0 +1,304 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_SPIN_CONDITION_HPP +#define BOOST_INTERPROCESS_DETAIL_SPIN_CONDITION_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class spin_condition +{ + spin_condition(const spin_condition &); + spin_condition &operator=(const spin_condition &); + public: + spin_condition(); + ~spin_condition(); + + void notify_one(); + void notify_all(); + + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { + if (!lock) + throw lock_exception(); + //Handle infinity absolute time here to avoid complications in do_timed_wait + if(abs_time == boost::posix_time::pos_infin){ + this->wait(lock); + return true; + } + return this->do_timed_wait(abs_time, *lock.mutex()); + } + + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { + if (!lock) + throw lock_exception(); + //Handle infinity absolute time here to avoid complications in do_timed_wait + if(abs_time == boost::posix_time::pos_infin){ + this->wait(lock, pred); + return true; + } + while (!pred()){ + if (!this->do_timed_wait(abs_time, *lock.mutex())) + return pred(); + } + return true; + } + + template + void wait(L& lock) + { + if (!lock) + throw lock_exception(); + do_wait(*lock.mutex()); + } + + template + void wait(L& lock, Pr pred) + { + if (!lock) + throw lock_exception(); + + while (!pred()) + do_wait(*lock.mutex()); + } + + template + void do_wait(InterprocessMutex &mut); + + template + bool do_timed_wait(const boost::posix_time::ptime &abs_time, InterprocessMutex &mut); + + private: + template + bool do_timed_wait(bool tout_enabled, const boost::posix_time::ptime &abs_time, InterprocessMutex &mut); + + enum { SLEEP = 0, NOTIFY_ONE, NOTIFY_ALL }; + spin_mutex m_enter_mut; + volatile boost::uint32_t m_command; + volatile boost::uint32_t m_num_waiters; + void notify(boost::uint32_t command); +}; + +inline spin_condition::spin_condition() +{ + //Note that this class is initialized to zero. + //So zeroed memory can be interpreted as an initialized + //condition variable + m_command = SLEEP; + m_num_waiters = 0; +} + +inline spin_condition::~spin_condition() +{ + //Notify all waiting threads + //to allow POSIX semantics on condition destruction + this->notify_all(); +} + +inline void spin_condition::notify_one() +{ + this->notify(NOTIFY_ONE); +} + +inline void spin_condition::notify_all() +{ + this->notify(NOTIFY_ALL); +} + +inline void spin_condition::notify(boost::uint32_t command) +{ + //This mutex guarantees that no other thread can enter to the + //do_timed_wait method logic, so that thread count will be + //constant until the function writes a NOTIFY_ALL command. + //It also guarantees that no other notification can be signaled + //on this spin_condition before this one ends + m_enter_mut.lock(); + + //Return if there are no waiters + if(!atomic_read32(&m_num_waiters)) { + m_enter_mut.unlock(); + return; + } + + //Notify that all threads should execute wait logic + spin_wait swait; + while(SLEEP != atomic_cas32(const_cast(&m_command), command, SLEEP)){ + swait.yield(); + } + //The enter mutex will rest locked until the last waiting thread unlocks it +} + +template +inline void spin_condition::do_wait(InterprocessMutex &mut) +{ + this->do_timed_wait(false, boost::posix_time::ptime(), mut); +} + +template +inline bool spin_condition::do_timed_wait + (const boost::posix_time::ptime &abs_time, InterprocessMutex &mut) +{ + return this->do_timed_wait(true, abs_time, mut); +} + +template +inline bool spin_condition::do_timed_wait(bool tout_enabled, + const boost::posix_time::ptime &abs_time, + InterprocessMutex &mut) +{ + boost::posix_time::ptime now = microsec_clock::universal_time(); + + if(tout_enabled){ + if(now >= abs_time) return false; + } + + typedef boost::interprocess::scoped_lock InternalLock; + //The enter mutex guarantees that while executing a notification, + //no other thread can execute the do_timed_wait method. + { + //--------------------------------------------------------------- + InternalLock lock; + if(tout_enabled){ + InternalLock dummy(m_enter_mut, abs_time); + lock = boost::move(dummy); + } + else{ + InternalLock dummy(m_enter_mut); + lock = boost::move(dummy); + } + + if(!lock) + return false; + //--------------------------------------------------------------- + //We increment the waiting thread count protected so that it will be + //always constant when another thread enters the notification logic. + //The increment marks this thread as "waiting on spin_condition" + atomic_inc32(const_cast(&m_num_waiters)); + + //We unlock the external mutex atomically with the increment + mut.unlock(); + } + + //By default, we suppose that no timeout has happened + bool timed_out = false, unlock_enter_mut= false; + + //Loop until a notification indicates that the thread should + //exit or timeout occurs + while(1){ + //The thread sleeps/spins until a spin_condition commands a notification + //Notification occurred, we will lock the checking mutex so that + spin_wait swait; + while(atomic_read32(&m_command) == SLEEP){ + swait.yield(); + + //Check for timeout + if(tout_enabled){ + now = microsec_clock::universal_time(); + + if(now >= abs_time){ + //If we can lock the mutex it means that no notification + //is being executed in this spin_condition variable + timed_out = m_enter_mut.try_lock(); + + //If locking fails, indicates that another thread is executing + //notification, so we play the notification game + if(!timed_out){ + //There is an ongoing notification, we will try again later + continue; + } + //No notification in execution, since enter mutex is locked. + //We will execute time-out logic, so we will decrement count, + //release the enter mutex and return false. + break; + } + } + } + + //If a timeout occurred, the mutex will not execute checking logic + if(tout_enabled && timed_out){ + //Decrement wait count + atomic_dec32(const_cast(&m_num_waiters)); + unlock_enter_mut = true; + break; + } + else{ + boost::uint32_t result = atomic_cas32 + (const_cast(&m_command), SLEEP, NOTIFY_ONE); + if(result == SLEEP){ + //Other thread has been notified and since it was a NOTIFY one + //command, this thread must sleep again + continue; + } + else if(result == NOTIFY_ONE){ + //If it was a NOTIFY_ONE command, only this thread should + //exit. This thread has atomically marked command as sleep before + //so no other thread will exit. + //Decrement wait count. + unlock_enter_mut = true; + atomic_dec32(const_cast(&m_num_waiters)); + break; + } + else{ + //If it is a NOTIFY_ALL command, all threads should return + //from do_timed_wait function. Decrement wait count. + unlock_enter_mut = 1 == atomic_dec32(const_cast(&m_num_waiters)); + //Check if this is the last thread of notify_all waiters + //Only the last thread will release the mutex + if(unlock_enter_mut){ + atomic_cas32(const_cast(&m_command), SLEEP, NOTIFY_ALL); + } + break; + } + } + } + + //Unlock the enter mutex if it is a single notification, if this is + //the last notified thread in a notify_all or a timeout has occurred + if(unlock_enter_mut){ + m_enter_mut.unlock(); + } + + //Lock external again before returning from the method + mut.lock(); + return !timed_out; +} + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_SPIN_CONDITION_HPP diff --git a/libraries/boost/boost/interprocess/sync/spin/interprocess_barrier.hpp b/libraries/boost/boost/interprocess/sync/spin/interprocess_barrier.hpp new file mode 100644 index 000000000..7a9580df2 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/spin/interprocess_barrier.hpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +namespace boost { +namespace interprocess { + +inline barrier::barrier(unsigned int count) + : m_threshold(count), m_count(count), m_generation(0) +{ + if (count == 0) + throw std::invalid_argument("count cannot be zero."); +} + +inline barrier::~barrier(){} + +inline bool barrier::wait() +{ + scoped_lock lock(m_mutex); + unsigned int gen = m_generation; + + if (--m_count == 0){ + m_generation++; + m_count = m_threshold; + m_cond.notify_all(); + return true; + } + + while (gen == m_generation){ + m_cond.wait(lock); + } + return false; +} + +} //namespace interprocess { +} //namespace boost { diff --git a/libraries/boost/boost/interprocess/sync/spin/mutex.hpp b/libraries/boost/boost/interprocess/sync/spin/mutex.hpp new file mode 100644 index 000000000..766367343 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/spin/mutex.hpp @@ -0,0 +1,87 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_SPIN_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_SPIN_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class spin_mutex +{ + spin_mutex(const spin_mutex &); + spin_mutex &operator=(const spin_mutex &); + public: + + spin_mutex(); + ~spin_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + void take_ownership(){}; + private: + volatile boost::uint32_t m_s; +}; + +inline spin_mutex::spin_mutex() + : m_s(0) +{ + //Note that this class is initialized to zero. + //So zeroed memory can be interpreted as an + //initialized mutex +} + +inline spin_mutex::~spin_mutex() +{ + //Trivial destructor +} + +inline void spin_mutex::lock(void) +{ return ipcdetail::try_based_lock(*this); } + +inline bool spin_mutex::try_lock(void) +{ + boost::uint32_t prev_s = ipcdetail::atomic_cas32(const_cast(&m_s), 1, 0); + return m_s == 1 && prev_s == 0; +} + +inline bool spin_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return ipcdetail::try_based_timed_lock(*this, abs_time); } + +inline void spin_mutex::unlock(void) +{ ipcdetail::atomic_cas32(const_cast(&m_s), 0, 1); } + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_SPIN_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/spin/recursive_mutex.hpp b/libraries/boost/boost/interprocess/sync/spin/recursive_mutex.hpp new file mode 100644 index 000000000..495efd900 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/spin/recursive_mutex.hpp @@ -0,0 +1,176 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// Parts of the pthread code come from Boost Threads code: +// +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class spin_recursive_mutex +{ + spin_recursive_mutex(const spin_recursive_mutex &); + spin_recursive_mutex &operator=(const spin_recursive_mutex &); + public: + + spin_recursive_mutex(); + ~spin_recursive_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + void take_ownership(); + private: + spin_mutex m_mutex; + unsigned int m_nLockCount; + volatile ipcdetail::OS_systemwide_thread_id_t m_nOwner; + volatile boost::uint32_t m_s; +}; + +inline spin_recursive_mutex::spin_recursive_mutex() + : m_nLockCount(0), m_nOwner(ipcdetail::get_invalid_systemwide_thread_id()){} + +inline spin_recursive_mutex::~spin_recursive_mutex(){} + +inline void spin_recursive_mutex::lock() +{ + typedef ipcdetail::OS_systemwide_thread_id_t handle_t; + const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); + handle_t old_id; + ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id); + if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)){ + if((unsigned int)(m_nLockCount+1) == 0){ + //Overflow, throw an exception + throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow"); + } + ++m_nLockCount; + } + else{ + m_mutex.lock(); + ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner); + m_nLockCount = 1; + } +} + +inline bool spin_recursive_mutex::try_lock() +{ + typedef ipcdetail::OS_systemwide_thread_id_t handle_t; + handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); + handle_t old_id; + ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id); + if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it + if((unsigned int)(m_nLockCount+1) == 0){ + //Overflow, throw an exception + throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow"); + } + ++m_nLockCount; + return true; + } + if(m_mutex.try_lock()){ + ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner); + m_nLockCount = 1; + return true; + } + return false; +} + +inline bool spin_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + typedef ipcdetail::OS_systemwide_thread_id_t handle_t; + const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); + handle_t old_id; + ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id); + if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it + if((unsigned int)(m_nLockCount+1) == 0){ + //Overflow, throw an exception + throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow"); + } + ++m_nLockCount; + return true; + } + //m_mutex supports abs_time so no need to check it + if(m_mutex.timed_lock(abs_time)){ + ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner); + m_nLockCount = 1; + return true; + } + return false; +} + +inline void spin_recursive_mutex::unlock() +{ + typedef ipcdetail::OS_systemwide_thread_id_t handle_t; + handle_t old_id; + ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id); + const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); + (void)old_id; + (void)thr_id; + BOOST_ASSERT(ipcdetail::equal_systemwide_thread_id(thr_id, old_id)); + --m_nLockCount; + if(!m_nLockCount){ + const handle_t new_id(ipcdetail::get_invalid_systemwide_thread_id()); + ipcdetail::systemwide_thread_id_copy(new_id, m_nOwner); + m_mutex.unlock(); + } +} + +inline void spin_recursive_mutex::take_ownership() +{ + typedef ipcdetail::OS_systemwide_thread_id_t handle_t; + this->m_nLockCount = 1; + const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); + ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/spin/semaphore.hpp b/libraries/boost/boost/interprocess/sync/spin/semaphore.hpp new file mode 100644 index 000000000..ad86c4d05 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/spin/semaphore.hpp @@ -0,0 +1,94 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_SPIN_SEMAPHORE_HPP +#define BOOST_INTERPROCESS_DETAIL_SPIN_SEMAPHORE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class spin_semaphore +{ + spin_semaphore(const spin_semaphore &); + spin_semaphore &operator=(const spin_semaphore &); + + public: + spin_semaphore(unsigned int initialCount); + ~spin_semaphore(); + + void post(); + void wait(); + bool try_wait(); + bool timed_wait(const boost::posix_time::ptime &abs_time); + +// int get_count() const; + private: + volatile boost::uint32_t m_count; +}; + + +inline spin_semaphore::~spin_semaphore() +{} + +inline spin_semaphore::spin_semaphore(unsigned int initialCount) +{ ipcdetail::atomic_write32(&this->m_count, boost::uint32_t(initialCount)); } + +inline void spin_semaphore::post() +{ + ipcdetail::atomic_inc32(&m_count); +} + +inline void spin_semaphore::wait() +{ + ipcdetail::lock_to_wait lw(*this); + return ipcdetail::try_based_lock(lw); +} + +inline bool spin_semaphore::try_wait() +{ + return ipcdetail::atomic_add_unless32(&m_count, boost::uint32_t(-1), boost::uint32_t(0)); +} + +inline bool spin_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +{ + ipcdetail::lock_to_wait lw(*this); + return ipcdetail::try_based_timed_lock(lw, abs_time); +} + +//inline int spin_semaphore::get_count() const +//{ + //return (int)ipcdetail::atomic_read32(&m_count); +//} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_SPIN_SEMAPHORE_HPP diff --git a/libraries/boost/boost/interprocess/sync/spin/wait.hpp b/libraries/boost/boost/interprocess/sync/spin/wait.hpp new file mode 100644 index 000000000..984f91ad0 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/spin/wait.hpp @@ -0,0 +1,185 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Peter Dimov 2008. +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//Parts of this file come from boost/smart_ptr/detail/yield_k.hpp +//Many thanks to Peter Dimov. + +#ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED +#define BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +//#define BOOST_INTERPROCESS_SPIN_WAIT_DEBUG +#ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG +#include +#endif + +// BOOST_INTERPROCESS_SMT_PAUSE + +#if defined(_MSC_VER) && ( defined(_M_IX86) || defined(_M_X64) ) + +extern "C" void _mm_pause(); +#pragma intrinsic( _mm_pause ) + +#define BOOST_INTERPROCESS_SMT_PAUSE _mm_pause(); + +#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) && !defined(_CRAYC) + +#define BOOST_INTERPROCESS_SMT_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" ); + +#endif + +namespace boost{ +namespace interprocess{ +namespace ipcdetail { + +template +class num_core_holder +{ + public: + static unsigned int get() + { + if(!num_cores){ + return ipcdetail::get_num_cores(); + } + else{ + return num_cores; + } + } + + private: + static unsigned int num_cores; +}; + +template +unsigned int num_core_holder::num_cores = ipcdetail::get_num_cores(); + +} //namespace ipcdetail { + +class spin_wait +{ + public: + + static const unsigned int nop_pause_limit = 32u; + spin_wait() + : m_count_start(), m_ul_yield_only_counts(), m_k() + {} + + #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG + ~spin_wait() + { + if(m_k){ + std::cout << "final m_k: " << m_k + << " system tick(us): " << ipcdetail::get_system_tick_us() << std::endl; + } + } + #endif + + unsigned int count() const + { return m_k; } + + void yield() + { + //Lazy initialization of limits + if( !m_k){ + this->init_limits(); + } + //Nop tries + if( m_k < (nop_pause_limit >> 2) ){ + + } + //Pause tries if the processor supports it + #if defined(BOOST_INTERPROCESS_SMT_PAUSE) + else if( m_k < nop_pause_limit ){ + BOOST_INTERPROCESS_SMT_PAUSE + } + #endif + //Yield/Sleep strategy + else{ + //Lazy initialization of tick information + if(m_k == nop_pause_limit){ + this->init_tick_info(); + } + else if( this->yield_or_sleep() ){ + ipcdetail::thread_yield(); + } + else{ + ipcdetail::thread_sleep_tick(); + } + } + ++m_k; + } + + void reset() + { + m_k = 0u; + } + + private: + + void init_limits() + { + unsigned int num_cores = ipcdetail::num_core_holder<0>::get(); + m_k = num_cores > 1u ? 0u : nop_pause_limit; + } + + void init_tick_info() + { + m_ul_yield_only_counts = ipcdetail::get_system_tick_in_highres_counts(); + m_count_start = ipcdetail::get_current_system_highres_count(); + } + + //Returns true if yield must be called, false is sleep must be called + bool yield_or_sleep() + { + if(!m_ul_yield_only_counts){ //If yield-only limit was reached then yield one in every two tries + return (m_k & 1u) != 0; + } + else{ //Try to see if we've reched yield-only time limit + const ipcdetail::OS_highres_count_t now = ipcdetail::get_current_system_highres_count(); + const ipcdetail::OS_highres_count_t elapsed = ipcdetail::system_highres_count_subtract(now, m_count_start); + if(!ipcdetail::system_highres_count_less_ul(elapsed, m_ul_yield_only_counts)){ + #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG + std::cout << "elapsed!\n" + << " m_ul_yield_only_counts: " << m_ul_yield_only_counts + << " system tick(us): " << ipcdetail::get_system_tick_us() << '\n' + << " m_k: " << m_k << " elapsed counts: "; + ipcdetail::ostream_highres_count(std::cout, elapsed) << std::endl; + #endif + //Yield-only time reached, now it's time to sleep + m_ul_yield_only_counts = 0ul; + return false; + } + } + return true; //Otherwise yield + } + + ipcdetail::OS_highres_count_t m_count_start; + unsigned long m_ul_yield_only_counts; + unsigned int m_k; +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED diff --git a/libraries/boost/boost/interprocess/sync/upgradable_lock.hpp b/libraries/boost/boost/interprocess/sync/upgradable_lock.hpp new file mode 100644 index 000000000..d06775167 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/upgradable_lock.hpp @@ -0,0 +1,313 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This interface is inspired by Howard Hinnant's lock proposal. +// http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_UPGRADABLE_LOCK_HPP +#define BOOST_INTERPROCESS_UPGRADABLE_LOCK_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +//!\file +//!Describes the upgradable_lock class that serves to acquire the upgradable +//!lock of a mutex. + +namespace boost { +namespace interprocess { + +//!upgradable_lock is meant to carry out the tasks for read-locking, unlocking, +//!try-read-locking and timed-read-locking (recursive or not) for the Mutex. +//!Additionally the upgradable_lock can transfer ownership to a scoped_lock +//!using transfer_lock syntax. The Mutex need not supply all of the functionality. +//!If the client of upgradable_lock does not use functionality which the +//!Mutex does not supply, no harm is done. Mutex ownership can be shared among +//!read_locks, and a single upgradable_lock. upgradable_lock does not support +//!copy semantics. However upgradable_lock supports ownership transfer from +//!a upgradable_locks or scoped_locks via transfer_lock syntax. +template +class upgradable_lock +{ + public: + typedef UpgradableMutex mutex_type; + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + typedef upgradable_lock this_type; + explicit upgradable_lock(scoped_lock&); + typedef bool this_type::*unspecified_bool_type; + BOOST_MOVABLE_BUT_NOT_COPYABLE(upgradable_lock) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + + //!Effects: Default constructs a upgradable_lock. + //!Postconditions: owns() == false and mutex() == 0. + upgradable_lock() + : mp_mutex(0), m_locked(false) + {} + + explicit upgradable_lock(mutex_type& m) + : mp_mutex(&m), m_locked(false) + { mp_mutex->lock_upgradable(); m_locked = true; } + + //!Postconditions: owns() == false, and mutex() == &m. + //!Notes: The constructor will not take ownership of the mutex. There is no effect + //! required on the referenced mutex. + upgradable_lock(mutex_type& m, defer_lock_type) + : mp_mutex(&m), m_locked(false) + {} + + //!Postconditions: owns() == true, and mutex() == &m. + //!Notes: The constructor will suppose that the mutex is already upgradable + //! locked. There is no effect required on the referenced mutex. + upgradable_lock(mutex_type& m, accept_ownership_type) + : mp_mutex(&m), m_locked(true) + {} + + //!Effects: m.try_lock_upgradable(). + //!Postconditions: mutex() == &m. owns() == the return value of the + //! m.try_lock_upgradable() executed within the constructor. + //!Notes: The constructor will take upgradable-ownership of the mutex + //! if it can do so without waiting. Whether or not this constructor + //! handles recursive locking depends upon the mutex. If the mutex_type + //! does not support try_lock_upgradable, this constructor will fail at + //! compile time if instantiated, but otherwise have no effect. + upgradable_lock(mutex_type& m, try_to_lock_type) + : mp_mutex(&m), m_locked(false) + { m_locked = mp_mutex->try_lock_upgradable(); } + + //!Effects: m.timed_lock_upgradable(abs_time) + //!Postconditions: mutex() == &m. owns() == the return value of the + //! m.timed_lock_upgradable() executed within the constructor. + //!Notes: The constructor will take upgradable-ownership of the mutex if it + //! can do so within the time specified. Whether or not this constructor + //! handles recursive locking depends upon the mutex. If the mutex_type + //! does not support timed_lock_upgradable, this constructor will fail + //! at compile time if instantiated, but otherwise have no effect. + upgradable_lock(mutex_type& m, const boost::posix_time::ptime& abs_time) + : mp_mutex(&m), m_locked(false) + { m_locked = mp_mutex->timed_lock_upgradable(abs_time); } + + //!Effects: No effects on the underlying mutex. + //!Postconditions: mutex() == the value upgr.mutex() had before the + //! construction. upgr.mutex() == 0. owns() == upgr.owns() before the + //! construction. upgr.owns() == false. + //!Notes: If upgr is locked, this constructor will lock this upgradable_lock + //! while unlocking upgr. If upgr is unlocked, then this upgradable_lock will + //! be unlocked as well. Only a moved upgradable_lock's will match this + //! signature. An non-moved upgradable_lock can be moved with the + //! expression: "boost::move(lock);". This constructor does not alter the + //! state of the mutex, only potentially who owns it. + upgradable_lock(BOOST_RV_REF(upgradable_lock) upgr) + : mp_mutex(0), m_locked(upgr.owns()) + { mp_mutex = upgr.release(); } + + //!Effects: If scop.owns(), m_.unlock_and_lock_upgradable(). + //!Postconditions: mutex() == the value scop.mutex() had before the construction. + //! scop.mutex() == 0. owns() == scop.owns() before the constructor. After the + //! construction, scop.owns() == false. + //!Notes: If scop is locked, this constructor will transfer the exclusive-ownership + //! to an upgradable-ownership of this upgradable_lock. + //! Only a moved sharable_lock's will match this + //! signature. An non-moved sharable_lock can be moved with the + //! expression: "boost::move(lock);". + template + upgradable_lock(BOOST_RV_REF(scoped_lock) scop + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + scoped_lock &u_lock = scop; + if(u_lock.owns()){ + u_lock.mutex()->unlock_and_lock_upgradable(); + m_locked = true; + } + mp_mutex = u_lock.release(); + } + + //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock_upgradable() + //! on the referenced mutex. + //! a)if try_unlock_sharable_and_lock_upgradable() returns true then mutex() + //! obtains the value from shar.release() and owns() is set to true. + //! b)if try_unlock_sharable_and_lock_upgradable() returns false then shar is + //! unaffected and this upgradable_lock construction has the same + //! effects as a default construction. + //! c)Else shar.owns() is false. mutex() obtains the value from shar.release() + //! and owns() is set to false. + //!Notes: This construction will not block. It will try to obtain mutex + //! ownership from shar immediately, while changing the lock type from a + //! "read lock" to an "upgradable lock". If the "read lock" isn't held + //! in the first place, the mutex merely changes type to an unlocked + //! "upgradable lock". If the "read lock" is held, then mutex transfer + //! occurs only if it can do so in a non-blocking manner. + template + upgradable_lock( BOOST_RV_REF(sharable_lock) shar, try_to_lock_type + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + sharable_lock &s_lock = shar; + if(s_lock.owns()){ + if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock_upgradable()) == true){ + mp_mutex = s_lock.release(); + } + } + else{ + s_lock.release(); + } + } + + //!Effects: if (owns()) m_->unlock_upgradable(). + //!Notes: The destructor behavior ensures that the mutex lock is not leaked. + ~upgradable_lock() + { + try{ + if(m_locked && mp_mutex) mp_mutex->unlock_upgradable(); + } + catch(...){} + } + + //!Effects: If owns(), then unlock_upgradable() is called on mutex(). + //! *this gets the state of upgr and upgr gets set to a default constructed state. + //!Notes: With a recursive mutex it is possible that both this and upgr own the + //! mutex before the assignment. In this case, this will own the mutex + //! after the assignment (and upgr will not), but the mutex's upgradable lock + //! count will be decremented by one. + upgradable_lock &operator=(BOOST_RV_REF(upgradable_lock) upgr) + { + if(this->owns()) + this->unlock(); + m_locked = upgr.owns(); + mp_mutex = upgr.release(); + return *this; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls lock_upgradable() on the referenced mutex. + //!Postconditions: owns() == true. + //!Notes: The sharable_lock changes from a state of not owning the mutex, + //! to owning the mutex, blocking if necessary. + void lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + mp_mutex->lock_upgradable(); + m_locked = true; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls try_lock_upgradable() on the referenced mutex. + //!Postconditions: owns() == the value returned from + //! mutex()->try_lock_upgradable(). + //!Notes: The upgradable_lock changes from a state of not owning the mutex, + //! to owning the mutex, but only if blocking was not required. If the + //! mutex_type does not support try_lock_upgradable(), this function will + //! fail at compile time if instantiated, but otherwise have no effect. + bool try_lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock_upgradable(); + return m_locked; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls timed_lock_upgradable(abs_time) on the referenced mutex. + //!Postconditions: owns() == the value returned from + //! mutex()->timed_lock_upgradable(abs_time). + //!Notes: The upgradable_lock changes from a state of not owning the mutex, + //! to owning the mutex, but only if it can obtain ownership within the + //! specified time. If the mutex_type does not support + //! timed_lock_upgradable(abs_time), this function will fail at compile + //! time if instantiated, but otherwise have no effect. + bool timed_lock(const boost::posix_time::ptime& abs_time) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->timed_lock_upgradable(abs_time); + return m_locked; + } + + //!Effects: If mutex() == 0 or if not locked, throws a lock_exception() + //! exception. Calls unlock_upgradable() on the referenced mutex. + //!Postconditions: owns() == false. + //!Notes: The upgradable_lock changes from a state of owning the mutex, + //! to not owning the mutex. + void unlock() + { + if(!mp_mutex || !m_locked) + throw lock_exception(); + mp_mutex->unlock_upgradable(); + m_locked = false; + } + + //!Effects: Returns true if this scoped_lock has acquired the + //!referenced mutex. + bool owns() const + { return m_locked && mp_mutex; } + + //!Conversion to bool. + //!Returns owns(). + operator unspecified_bool_type() const + { return m_locked? &this_type::m_locked : 0; } + + //!Effects: Returns a pointer to the referenced mutex, or 0 if + //!there is no mutex to reference. + mutex_type* mutex() const + { return mp_mutex; } + + //!Effects: Returns a pointer to the referenced mutex, or 0 if there is no + //! mutex to reference. + //!Postconditions: mutex() == 0 and owns() == false. + mutex_type* release() + { + mutex_type *mut = mp_mutex; + mp_mutex = 0; + m_locked = false; + return mut; + } + + //!Effects: Swaps state with moved lock. + //!Throws: Nothing. + void swap(upgradable_lock &other) + { + (simple_swap)(mp_mutex, other.mp_mutex); + (simple_swap)(m_locked, other.m_locked); + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + mutex_type *mp_mutex; + bool m_locked; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_UPGRADABLE_LOCK_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/condition.hpp b/libraries/boost/boost/interprocess/sync/windows/condition.hpp new file mode 100644 index 000000000..58a43e25a --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/condition.hpp @@ -0,0 +1,129 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_CONDITION_HPP +#define BOOST_INTERPROCESS_DETAIL_WINDOWS_CONDITION_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class windows_condition +{ + windows_condition(const windows_condition &); + windows_condition &operator=(const windows_condition &); + + public: + windows_condition() + : m_condition_data() + {} + + ~windows_condition() + { + //Notify all waiting threads + //to allow POSIX semantics on condition destruction + this->notify_all(); + } + + void notify_one() + { m_condition_data.notify_one(); } + + void notify_all() + { m_condition_data.notify_all(); } + + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { return m_condition_data.timed_wait(lock, abs_time); } + + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { return m_condition_data.timed_wait(lock, abs_time, pred); } + + template + void wait(L& lock) + { m_condition_data.wait(lock); } + + template + void wait(L& lock, Pr pred) + { m_condition_data.wait(lock, pred); } + + private: + + struct condition_data + { + typedef boost::int32_t integer_type; + typedef windows_semaphore semaphore_type; + typedef windows_mutex mutex_type; + + condition_data() + : m_nwaiters_blocked(0) + , m_nwaiters_gone(0) + , m_nwaiters_to_unblock(0) + , m_sem_block_queue(0) + , m_sem_block_lock(1) + , m_mtx_unblock_lock() + {} + + integer_type &get_nwaiters_blocked() + { return m_nwaiters_blocked; } + + integer_type &get_nwaiters_gone() + { return m_nwaiters_gone; } + + integer_type &get_nwaiters_to_unblock() + { return m_nwaiters_to_unblock; } + + semaphore_type &get_sem_block_queue() + { return m_sem_block_queue; } + + semaphore_type &get_sem_block_lock() + { return m_sem_block_lock; } + + mutex_type &get_mtx_unblock_lock() + { return m_mtx_unblock_lock; } + + boost::int32_t m_nwaiters_blocked; + boost::int32_t m_nwaiters_gone; + boost::int32_t m_nwaiters_to_unblock; + windows_semaphore m_sem_block_queue; + windows_semaphore m_sem_block_lock; + windows_mutex m_mtx_unblock_lock; + }; + + ipcdetail::condition_8a_wrapper m_condition_data; +}; + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_CONDITION_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/mutex.hpp b/libraries/boost/boost/interprocess/sync/windows/mutex.hpp new file mode 100644 index 000000000..4747d0cc6 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/mutex.hpp @@ -0,0 +1,118 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class windows_mutex +{ + windows_mutex(const windows_mutex &); + windows_mutex &operator=(const windows_mutex &); + public: + + windows_mutex(); + ~windows_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + void take_ownership(){}; + + private: + const sync_id id_; +}; + +inline windows_mutex::windows_mutex() + : id_(this) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //Create mutex with the initial count + bool open_or_created; + (void)handles.obtain_mutex(this->id_, &open_or_created); + //The mutex must be created, never opened + BOOST_ASSERT(open_or_created); + BOOST_ASSERT(open_or_created && winapi::get_last_error() != winapi::error_already_exists); + (void)open_or_created; +} + +inline windows_mutex::~windows_mutex() +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + handles.destroy_handle(this->id_); +} + +inline void windows_mutex::lock(void) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + mut.lock(); +} + +inline bool windows_mutex::try_lock(void) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + return mut.try_lock(); +} + +inline bool windows_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + return mut.timed_lock(abs_time); +} + +inline void windows_mutex::unlock(void) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + return mut.unlock(); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/named_condition.hpp b/libraries/boost/boost/interprocess/sync/windows/named_condition.hpp new file mode 100644 index 000000000..9f148a3fb --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/named_condition.hpp @@ -0,0 +1,38 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_WINDOWS_NAMED_CONDITION_HPP +#define BOOST_INTERPROCESS_WINDOWS_NAMED_CONDITION_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +typedef windows_named_condition_any windows_named_condition; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_WINDOWS_NAMED_CONDITION_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/named_condition_any.hpp b/libraries/boost/boost/interprocess/sync/windows/named_condition_any.hpp new file mode 100644 index 000000000..5dac8b77a --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/named_condition_any.hpp @@ -0,0 +1,244 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_WINDOWS_NAMED_CONDITION_ANY_HPP +#define BOOST_INTERPROCESS_WINDOWS_NAMED_CONDITION_ANY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class windows_named_condition_any +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + windows_named_condition_any(); + windows_named_condition_any(const windows_named_condition_any &); + windows_named_condition_any &operator=(const windows_named_condition_any &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + windows_named_condition_any + (create_only_t, const char *name, const permissions &perm) + : m_condition_data() + { + named_cond_callbacks callbacks(m_condition_data.get_members()); + m_named_sync.open_or_create(DoCreate, name, perm, callbacks); + } + + windows_named_condition_any + (open_or_create_t, const char *name, const permissions &perm) + : m_condition_data() + { + named_cond_callbacks callbacks(m_condition_data.get_members()); + m_named_sync.open_or_create(DoOpenOrCreate, name, perm, callbacks); + } + + windows_named_condition_any(open_only_t, const char *name) + : m_condition_data() + { + named_cond_callbacks callbacks(m_condition_data.get_members()); + m_named_sync.open_or_create(DoOpen, name, permissions(), callbacks); + } + + ~windows_named_condition_any() + { + named_cond_callbacks callbacks(m_condition_data.get_members()); + m_named_sync.close(callbacks); + } + + void notify_one() + { m_condition_data.notify_one(); } + + void notify_all() + { m_condition_data.notify_all(); } + + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { return m_condition_data.timed_wait(lock, abs_time); } + + template + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { return m_condition_data.timed_wait(lock, abs_time, pred); } + + template + void wait(L& lock) + { m_condition_data.wait(lock); } + + template + void wait(L& lock, Pr pred) + { m_condition_data.wait(lock, pred); } + + static bool remove(const char *name) + { return windows_named_sync::remove(name); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + + void dont_close_on_destruction() + {} + + friend class interprocess_tester; + + struct condition_data + { + typedef boost::int32_t integer_type; + typedef winapi_semaphore_wrapper semaphore_type; + typedef winapi_mutex_wrapper mutex_type; + + integer_type &get_nwaiters_blocked() + { return m_nwaiters_blocked; } + + integer_type &get_nwaiters_gone() + { return m_nwaiters_gone; } + + integer_type &get_nwaiters_to_unblock() + { return m_nwaiters_to_unblock; } + + semaphore_type &get_sem_block_queue() + { return m_sem_block_queue; } + + semaphore_type &get_sem_block_lock() + { return m_sem_block_lock; } + + mutex_type &get_mtx_unblock_lock() + { return m_mtx_unblock_lock; } + + integer_type m_nwaiters_blocked; + integer_type m_nwaiters_gone; + integer_type m_nwaiters_to_unblock; + winapi_semaphore_wrapper m_sem_block_queue; + winapi_semaphore_wrapper m_sem_block_lock; + winapi_mutex_wrapper m_mtx_unblock_lock; + }; + + class named_cond_callbacks : public windows_named_sync_interface + { + typedef __int64 sem_count_t; + mutable sem_count_t sem_counts [2]; + + public: + named_cond_callbacks(condition_data &cond_data) + : m_condition_data(cond_data) + {} + + virtual std::size_t get_data_size() const + { return sizeof(sem_counts); } + + virtual const void *buffer_with_final_data_to_file() + { + sem_counts[0] = m_condition_data.m_sem_block_queue.value(); + sem_counts[1] = m_condition_data.m_sem_block_lock.value(); + return &sem_counts; + } + + virtual const void *buffer_with_init_data_to_file() + { + sem_counts[0] = 0; + sem_counts[1] = 1; + return &sem_counts; + } + + virtual void *buffer_to_store_init_data_from_file() + { return &sem_counts; } + + virtual bool open(create_enum_t, const char *id_name) + { + m_condition_data.m_nwaiters_blocked = 0; + m_condition_data.m_nwaiters_gone = 0; + m_condition_data.m_nwaiters_to_unblock = 0; + + //Now open semaphores and mutex. + //Use local variables + swap to guarantee consistent + //initialization and cleanup in case any opening fails + permissions perm; + perm.set_unrestricted(); + std::string aux_str = "Global\\bipc.cond."; + aux_str += id_name; + std::size_t pos = aux_str.size(); + + //sem_block_queue + aux_str += "_bq"; + winapi_semaphore_wrapper sem_block_queue; + bool created; + if(!sem_block_queue.open_or_create + (aux_str.c_str(), sem_counts[0], winapi_semaphore_wrapper::MaxCount, perm, created)) + return false; + aux_str.erase(pos); + + //sem_block_lock + aux_str += "_bl"; + winapi_semaphore_wrapper sem_block_lock; + if(!sem_block_lock.open_or_create + (aux_str.c_str(), sem_counts[1], winapi_semaphore_wrapper::MaxCount, perm, created)) + return false; + aux_str.erase(pos); + + //mtx_unblock_lock + aux_str += "_ul"; + winapi_mutex_wrapper mtx_unblock_lock; + if(!mtx_unblock_lock.open_or_create(aux_str.c_str(), perm)) + return false; + + //All ok, commit data + m_condition_data.m_sem_block_queue.swap(sem_block_queue); + m_condition_data.m_sem_block_lock.swap(sem_block_lock); + m_condition_data.m_mtx_unblock_lock.swap(mtx_unblock_lock); + return true; + } + + virtual void close() + { + m_condition_data.m_sem_block_queue.close(); + m_condition_data.m_sem_block_lock.close(); + m_condition_data.m_mtx_unblock_lock.close(); + m_condition_data.m_nwaiters_blocked = 0; + m_condition_data.m_nwaiters_gone = 0; + m_condition_data.m_nwaiters_to_unblock = 0; + } + + virtual ~named_cond_callbacks() + {} + + private: + condition_data &m_condition_data; + }; + + windows_named_sync m_named_sync; + ipcdetail::condition_8a_wrapper m_condition_data; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_WINDOWS_NAMED_CONDITION_ANY_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/named_mutex.hpp b/libraries/boost/boost/interprocess/sync/windows/named_mutex.hpp new file mode 100644 index 000000000..64a83c94f --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/named_mutex.hpp @@ -0,0 +1,179 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_WINDOWS_NAMED_MUTEX_HPP +#define BOOST_INTERPROCESS_WINDOWS_NAMED_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + + + +class windows_named_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + windows_named_mutex(); + windows_named_mutex(const windows_named_mutex &); + windows_named_mutex &operator=(const windows_named_mutex &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + windows_named_mutex(create_only_t, const char *name, const permissions &perm = permissions()); + + windows_named_mutex(open_or_create_t, const char *name, const permissions &perm = permissions()); + + windows_named_mutex(open_only_t, const char *name); + + ~windows_named_mutex(); + + void unlock(); + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class interprocess_tester; + void dont_close_on_destruction(); + winapi_mutex_wrapper m_mtx_wrapper; + windows_named_sync m_named_sync; + + class named_mut_callbacks : public windows_named_sync_interface + { + public: + named_mut_callbacks(winapi_mutex_wrapper &mtx_wrapper) + : m_mtx_wrapper(mtx_wrapper) + {} + + virtual std::size_t get_data_size() const + { return 0u; } + + virtual const void *buffer_with_init_data_to_file() + { return 0; } + + virtual const void *buffer_with_final_data_to_file() + { return 0; } + + virtual void *buffer_to_store_init_data_from_file() + { return 0; } + + virtual bool open(create_enum_t, const char *id_name) + { + std::string aux_str = "Global\\bipc.mut."; + aux_str += id_name; + // + permissions mut_perm; + mut_perm.set_unrestricted(); + return m_mtx_wrapper.open_or_create(aux_str.c_str(), mut_perm); + } + + virtual void close() + { + m_mtx_wrapper.close(); + } + + virtual ~named_mut_callbacks() + {} + + private: + winapi_mutex_wrapper& m_mtx_wrapper; + }; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +inline windows_named_mutex::~windows_named_mutex() +{ + named_mut_callbacks callbacks(m_mtx_wrapper); + m_named_sync.close(callbacks); +} + +inline void windows_named_mutex::dont_close_on_destruction() +{} + +inline windows_named_mutex::windows_named_mutex + (create_only_t, const char *name, const permissions &perm) + : m_mtx_wrapper() +{ + named_mut_callbacks callbacks(m_mtx_wrapper); + m_named_sync.open_or_create(DoCreate, name, perm, callbacks); +} + +inline windows_named_mutex::windows_named_mutex + (open_or_create_t, const char *name, const permissions &perm) + : m_mtx_wrapper() +{ + named_mut_callbacks callbacks(m_mtx_wrapper); + m_named_sync.open_or_create(DoOpenOrCreate, name, perm, callbacks); +} + +inline windows_named_mutex::windows_named_mutex(open_only_t, const char *name) + : m_mtx_wrapper() +{ + named_mut_callbacks callbacks(m_mtx_wrapper); + m_named_sync.open_or_create(DoOpen, name, permissions(), callbacks); +} + +inline void windows_named_mutex::unlock() +{ + m_mtx_wrapper.unlock(); +} + +inline void windows_named_mutex::lock() +{ + m_mtx_wrapper.lock(); +} + +inline bool windows_named_mutex::try_lock() +{ + return m_mtx_wrapper.try_lock(); +} + +inline bool windows_named_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + return m_mtx_wrapper.timed_lock(abs_time); +} + +inline bool windows_named_mutex::remove(const char *name) +{ + return windows_named_sync::remove(name); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_WINDOWS_NAMED_MUTEX_HPP \ No newline at end of file diff --git a/libraries/boost/boost/interprocess/sync/windows/named_recursive_mutex.hpp b/libraries/boost/boost/interprocess/sync/windows/named_recursive_mutex.hpp new file mode 100644 index 000000000..2e591371a --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/named_recursive_mutex.hpp @@ -0,0 +1,62 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_WINDOWS_RECURSIVE_NAMED_MUTEX_HPP +#define BOOST_INTERPROCESS_WINDOWS_RECURSIVE_NAMED_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + + +class windows_named_recursive_mutex + //Windows mutexes based on CreateMutex are already recursive... + : public windows_named_mutex +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + windows_named_recursive_mutex(); + windows_named_recursive_mutex(const windows_named_mutex &); + windows_named_recursive_mutex &operator=(const windows_named_mutex &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + windows_named_recursive_mutex(create_only_t, const char *name, const permissions &perm = permissions()) + : windows_named_mutex(create_only_t(), name, perm) + {} + + windows_named_recursive_mutex(open_or_create_t, const char *name, const permissions &perm = permissions()) + : windows_named_mutex(open_or_create_t(), name, perm) + {} + + windows_named_recursive_mutex(open_only_t, const char *name) + : windows_named_mutex(open_only_t(), name) + {} +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_WINDOWS_RECURSIVE_NAMED_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/named_semaphore.hpp b/libraries/boost/boost/interprocess/sync/windows/named_semaphore.hpp new file mode 100644 index 000000000..e777a6689 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/named_semaphore.hpp @@ -0,0 +1,182 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_WINDOWS_NAMED_SEMAPHORE_HPP +#define BOOST_INTERPROCESS_WINDOWS_NAMED_SEMAPHORE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + + + +class windows_named_semaphore +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + windows_named_semaphore(); + windows_named_semaphore(const windows_named_semaphore &); + windows_named_semaphore &operator=(const windows_named_semaphore &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + windows_named_semaphore(create_only_t, const char *name, unsigned int initialCount, const permissions &perm = permissions()); + + windows_named_semaphore(open_or_create_t, const char *name, unsigned int initialCount, const permissions &perm = permissions()); + + windows_named_semaphore(open_only_t, const char *name); + + ~windows_named_semaphore(); + + void post(); + void wait(); + bool try_wait(); + bool timed_wait(const boost::posix_time::ptime &abs_time); + + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + friend class interprocess_tester; + void dont_close_on_destruction(); + winapi_semaphore_wrapper m_sem_wrapper; + windows_named_sync m_named_sync; + + class named_sem_callbacks : public windows_named_sync_interface + { + public: + typedef __int64 sem_count_t; + named_sem_callbacks(winapi_semaphore_wrapper &sem_wrapper, sem_count_t sem_cnt) + : m_sem_wrapper(sem_wrapper), m_sem_count(sem_cnt) + {} + + virtual std::size_t get_data_size() const + { return sizeof(sem_count_t); } + + virtual const void *buffer_with_final_data_to_file() + { return &m_sem_count; } + + virtual const void *buffer_with_init_data_to_file() + { return &m_sem_count; } + + virtual void *buffer_to_store_init_data_from_file() + { return &m_sem_count; } + + virtual bool open(create_enum_t, const char *id_name) + { + std::string aux_str = "Global\\bipc.sem."; + aux_str += id_name; + // + permissions sem_perm; + sem_perm.set_unrestricted(); + bool created; + return m_sem_wrapper.open_or_create + ( aux_str.c_str(), static_cast(m_sem_count) + , winapi_semaphore_wrapper::MaxCount, sem_perm, created); + } + + virtual void close() + { + m_sem_wrapper.close(); + } + + virtual ~named_sem_callbacks() + {} + + private: + sem_count_t m_sem_count; + winapi_semaphore_wrapper& m_sem_wrapper; + }; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +inline windows_named_semaphore::~windows_named_semaphore() +{ + named_sem_callbacks callbacks(m_sem_wrapper, m_sem_wrapper.value()); + m_named_sync.close(callbacks); +} + +inline void windows_named_semaphore::dont_close_on_destruction() +{} + +inline windows_named_semaphore::windows_named_semaphore + (create_only_t, const char *name, unsigned int initial_count, const permissions &perm) + : m_sem_wrapper() +{ + named_sem_callbacks callbacks(m_sem_wrapper, initial_count); + m_named_sync.open_or_create(DoCreate, name, perm, callbacks); +} + +inline windows_named_semaphore::windows_named_semaphore + (open_or_create_t, const char *name, unsigned int initial_count, const permissions &perm) + : m_sem_wrapper() +{ + named_sem_callbacks callbacks(m_sem_wrapper, initial_count); + m_named_sync.open_or_create(DoOpenOrCreate, name, perm, callbacks); +} + +inline windows_named_semaphore::windows_named_semaphore(open_only_t, const char *name) + : m_sem_wrapper() +{ + named_sem_callbacks callbacks(m_sem_wrapper, 0); + m_named_sync.open_or_create(DoOpen, name, permissions(), callbacks); +} + +inline void windows_named_semaphore::post() +{ + m_sem_wrapper.post(); +} + +inline void windows_named_semaphore::wait() +{ + m_sem_wrapper.wait(); +} + +inline bool windows_named_semaphore::try_wait() +{ + return m_sem_wrapper.try_wait(); +} + +inline bool windows_named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +{ + return m_sem_wrapper.timed_wait(abs_time); +} + +inline bool windows_named_semaphore::remove(const char *name) +{ + return windows_named_sync::remove(name); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_WINDOWS_NAMED_SEMAPHORE_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/named_sync.hpp b/libraries/boost/boost/interprocess/sync/windows/named_sync.hpp new file mode 100644 index 000000000..cf19335a3 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/named_sync.hpp @@ -0,0 +1,219 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_WINDOWS_NAMED_SYNC_HPP +#define BOOST_INTERPROCESS_WINDOWS_NAMED_SYNC_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class windows_named_sync_interface +{ + public: + virtual std::size_t get_data_size() const = 0; + virtual const void *buffer_with_final_data_to_file() = 0; + virtual const void *buffer_with_init_data_to_file() = 0; + virtual void *buffer_to_store_init_data_from_file() = 0; + virtual bool open(create_enum_t creation_type, const char *id_name) = 0; + virtual void close() = 0; + virtual ~windows_named_sync_interface() = 0; +}; + +inline windows_named_sync_interface::~windows_named_sync_interface() +{} + +class windows_named_sync +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + windows_named_sync(const windows_named_sync &); + windows_named_sync &operator=(const windows_named_sync &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + windows_named_sync(); + void open_or_create(create_enum_t creation_type, const char *name, const permissions &perm, windows_named_sync_interface &sync_interface); + void close(windows_named_sync_interface &sync_interface); + + static bool remove(const char *name); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + void *m_file_hnd; + + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +inline windows_named_sync::windows_named_sync() + : m_file_hnd(winapi::invalid_handle_value) +{} + +inline void windows_named_sync::close(windows_named_sync_interface &sync_interface) +{ + const std::size_t buflen = sync_interface.get_data_size(); + const std::size_t sizeof_file_info = sizeof(sync_id::internal_type) + buflen; + winapi::interprocess_overlapped overlapped; + if(winapi::lock_file_ex + (m_file_hnd, winapi::lockfile_exclusive_lock, 0, sizeof_file_info, 0, &overlapped)){ + if(winapi::set_file_pointer_ex(m_file_hnd, sizeof(sync_id::internal_type), 0, winapi::file_begin)){ + const void *buf = sync_interface.buffer_with_final_data_to_file(); + + unsigned long written_or_read = 0; + if(winapi::write_file(m_file_hnd, buf, buflen, &written_or_read, 0)){ + //... + } + } + } + sync_interface.close(); + if(m_file_hnd != winapi::invalid_handle_value){ + winapi::close_handle(m_file_hnd); + m_file_hnd = winapi::invalid_handle_value; + } +} + +inline void windows_named_sync::open_or_create + ( create_enum_t creation_type + , const char *name + , const permissions &perm + , windows_named_sync_interface &sync_interface) +{ + std::string aux_str(name); + m_file_hnd = winapi::invalid_handle_value; + //Use a file to emulate POSIX lifetime semantics. After this logic + //we'll obtain the ID of the native handle to open in aux_str + { + create_shared_dir_cleaning_old_and_get_filepath(name, aux_str); + //Create a file with required permissions. + m_file_hnd = winapi::create_file + ( aux_str.c_str() + , winapi::generic_read | winapi::generic_write + , creation_type == DoOpen ? winapi::open_existing : + (creation_type == DoCreate ? winapi::create_new : winapi::open_always) + , 0 + , (winapi::interprocess_security_attributes*)perm.get_permissions()); + + //Obtain OS error in case something has failed + error_info err; + bool success = false; + if(m_file_hnd != winapi::invalid_handle_value){ + //Now lock the file + const std::size_t buflen = sync_interface.get_data_size(); + typedef __int64 unique_id_type; + const std::size_t sizeof_file_info = sizeof(unique_id_type) + buflen; + winapi::interprocess_overlapped overlapped; + if(winapi::lock_file_ex + (m_file_hnd, winapi::lockfile_exclusive_lock, 0, sizeof_file_info, 0, &overlapped)){ + __int64 filesize = 0; + //Obtain the unique id to open the native semaphore. + //If file size was created + if(winapi::get_file_size(m_file_hnd, filesize)){ + unsigned long written_or_read = 0; + unique_id_type unique_id_val; + if(static_cast(filesize) != sizeof_file_info){ + winapi::set_end_of_file(m_file_hnd); + winapi::query_performance_counter(&unique_id_val); + const void *buf = sync_interface.buffer_with_init_data_to_file(); + //Write unique ID in file. This ID will be used to calculate the semaphore name + if(winapi::write_file(m_file_hnd, &unique_id_val, sizeof(unique_id_val), &written_or_read, 0) && + written_or_read == sizeof(unique_id_val) && + winapi::write_file(m_file_hnd, buf, buflen, &written_or_read, 0) && + written_or_read == buflen ){ + success = true; + } + winapi::get_file_size(m_file_hnd, filesize); + BOOST_ASSERT(std::size_t(filesize) == sizeof_file_info); + } + else{ + void *buf = sync_interface.buffer_to_store_init_data_from_file(); + if(winapi::read_file(m_file_hnd, &unique_id_val, sizeof(unique_id_val), &written_or_read, 0) && + written_or_read == sizeof(unique_id_val) && + winapi::read_file(m_file_hnd, buf, buflen, &written_or_read, 0) && + written_or_read == buflen ){ + success = true; + } + } + if(success){ + //Now create a global semaphore name based on the unique id + char unique_id_name[sizeof(unique_id_val)*2+1]; + std::size_t name_suffix_length = sizeof(unique_id_name); + bytes_to_str(&unique_id_val, sizeof(unique_id_val), &unique_id_name[0], name_suffix_length); + success = sync_interface.open(creation_type, unique_id_name); + } + } + + //Obtain OS error in case something has failed + err = system_error_code(); + + //If this fails we have no possible rollback so don't check the return + if(!winapi::unlock_file_ex(m_file_hnd, 0, sizeof_file_info, 0, &overlapped)){ + err = system_error_code(); + } + } + else{ + //Obtain OS error in case something has failed + err = system_error_code(); + } + } + else{ + err = system_error_code(); + } + + if(!success){ + if(m_file_hnd != winapi::invalid_handle_value){ + winapi::close_handle(m_file_hnd); + m_file_hnd = winapi::invalid_handle_value; + } + //Throw as something went wrong + throw interprocess_exception(err); + } + } +} + +inline bool windows_named_sync::remove(const char *name) +{ + try{ + //Make sure a temporary path is created for shared memory + std::string semfile; + ipcdetail::shared_filepath(name, semfile); + return winapi::unlink_file(semfile.c_str()); + } + catch(...){ + return false; + } +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_WINDOWS_NAMED_SYNC_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/recursive_mutex.hpp b/libraries/boost/boost/interprocess/sync/windows/recursive_mutex.hpp new file mode 100644 index 000000000..bf406f8fe --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/recursive_mutex.hpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +//Windows mutex is already recursive +class windows_recursive_mutex + : public windows_mutex +{ + windows_recursive_mutex(const windows_recursive_mutex &); + windows_recursive_mutex &operator=(const windows_recursive_mutex &); + public: + windows_recursive_mutex() : windows_mutex() {} +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/semaphore.hpp b/libraries/boost/boost/interprocess/sync/windows/semaphore.hpp new file mode 100644 index 000000000..7a29d962e --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/semaphore.hpp @@ -0,0 +1,117 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_SEMAPHORE_HPP +#define BOOST_INTERPROCESS_DETAIL_WINDOWS_SEMAPHORE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class windows_semaphore +{ + windows_semaphore(const windows_semaphore &); + windows_semaphore &operator=(const windows_semaphore &); + public: + + windows_semaphore(unsigned int initialCount); + ~windows_semaphore(); + + void post(long release_count = 1); + void wait(); + bool try_wait(); + bool timed_wait(const boost::posix_time::ptime &abs_time); + + private: + const sync_id id_; +}; + +inline windows_semaphore::windows_semaphore(unsigned int initialCount) + : id_(this) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //Force smeaphore creation with the initial count + bool open_or_created; + handles.obtain_semaphore(this->id_, initialCount, &open_or_created); + //The semaphore must be created, never opened + BOOST_ASSERT(open_or_created); + BOOST_ASSERT(open_or_created && winapi::get_last_error() != winapi::error_already_exists); + (void)open_or_created; +} + +inline windows_semaphore::~windows_semaphore() +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + handles.destroy_handle(this->id_); +} + +inline void windows_semaphore::wait(void) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, 0)); + sem.wait(); +} + +inline bool windows_semaphore::try_wait(void) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, 0)); + return sem.try_wait(); +} + +inline bool windows_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, 0)); + return sem.timed_wait(abs_time); +} + +inline void windows_semaphore::post(long release_count) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, 0)); + sem.post(release_count); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_SEMAPHORE_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/sync_utils.hpp b/libraries/boost/boost/interprocess/sync/windows/sync_utils.hpp new file mode 100644 index 000000000..8e054660c --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/sync_utils.hpp @@ -0,0 +1,240 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP +#define BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +//Shield against external warnings +#include + #include +#include + + +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +inline bool bytes_to_str(const void *mem, const std::size_t mem_length, char *out_str, std::size_t &out_length) +{ + const std::size_t need_mem = mem_length*2+1; + if(out_length < need_mem){ + out_length = need_mem; + return false; + } + + const char Characters [] = + { '0', '1', '2', '3', '4', '5', '6', '7' + , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + std::size_t char_counter = 0; + const char *buf = (const char *)mem; + for(std::size_t i = 0; i != mem_length; ++i){ + out_str[char_counter++] = Characters[(buf[i]&0xF0)>>4]; + out_str[char_counter++] = Characters[(buf[i]&0x0F)]; + } + out_str[char_counter] = 0; + return true; +} + +class sync_id +{ + public: + typedef __int64 internal_type; + sync_id(const void *map_addr) + : map_addr_(map_addr) + { winapi::query_performance_counter(&rand_); } + + explicit sync_id(internal_type val, const void *map_addr) + : map_addr_(map_addr) + { rand_ = val; } + + const internal_type &internal_pod() const + { return rand_; } + + internal_type &internal_pod() + { return rand_; } + + const void *map_address() const + { return map_addr_; } + + friend std::size_t hash_value(const sync_id &m) + { return boost::hash_value(m.rand_); } + + friend bool operator==(const sync_id &l, const sync_id &r) + { return l.rand_ == r.rand_ && l.map_addr_ == r.map_addr_; } + + private: + internal_type rand_; + const void * const map_addr_; +}; + +class sync_handles +{ + public: + enum type { MUTEX, SEMAPHORE }; + + private: + struct address_less + { + bool operator()(sync_id const * const l, sync_id const * const r) const + { return l->map_address() < r->map_address(); } + }; + + typedef boost::unordered_map umap_type; + typedef boost::container::map map_type; + static const std::size_t LengthOfGlobal = sizeof("Global\\boost.ipc")-1; + static const std::size_t StrSize = LengthOfGlobal + (sizeof(sync_id)*2+1); + typedef char NameBuf[StrSize]; + + + void fill_name(NameBuf &name, const sync_id &id) + { + const char *n = "Global\\boost.ipc"; + std::size_t i = 0; + do{ + name[i] = n[i]; + ++i; + } while(n[i]); + std::size_t len = sizeof(NameBuf) - LengthOfGlobal; + bytes_to_str(&id.internal_pod(), sizeof(id.internal_pod()), &name[LengthOfGlobal], len); + } + + void throw_if_error(void *hnd_val) + { + if(!hnd_val){ + error_info err(winapi::get_last_error()); + throw interprocess_exception(err); + } + } + + void* open_or_create_semaphore(const sync_id &id, unsigned int initial_count) + { + NameBuf name; + fill_name(name, id); + permissions unrestricted_security; + unrestricted_security.set_unrestricted(); + winapi_semaphore_wrapper sem_wrapper; + bool created; + sem_wrapper.open_or_create + (name, (long)initial_count, winapi_semaphore_wrapper::MaxCount, unrestricted_security, created); + throw_if_error(sem_wrapper.handle()); + return sem_wrapper.release(); + } + + void* open_or_create_mutex(const sync_id &id) + { + NameBuf name; + fill_name(name, id); + permissions unrestricted_security; + unrestricted_security.set_unrestricted(); + winapi_mutex_wrapper mtx_wrapper; + mtx_wrapper.open_or_create(name, unrestricted_security); + throw_if_error(mtx_wrapper.handle()); + return mtx_wrapper.release(); + } + + public: + void *obtain_mutex(const sync_id &id, bool *popen_created = 0) + { + umap_type::value_type v(id, (void*)0); + scoped_lock lock(mtx_); + umap_type::iterator it = umap_.insert(v).first; + void *&hnd_val = it->second; + if(!hnd_val){ + map_[&it->first] = it; + hnd_val = open_or_create_mutex(id); + if(popen_created) *popen_created = true; + } + else if(popen_created){ + *popen_created = false; + } + return hnd_val; + } + + void *obtain_semaphore(const sync_id &id, unsigned int initial_count, bool *popen_created = 0) + { + umap_type::value_type v(id, (void*)0); + scoped_lock lock(mtx_); + umap_type::iterator it = umap_.insert(v).first; + void *&hnd_val = it->second; + if(!hnd_val){ + map_[&it->first] = it; + hnd_val = open_or_create_semaphore(id, initial_count); + if(popen_created) *popen_created = true; + } + else if(popen_created){ + *popen_created = false; + } + return hnd_val; + } + + void destroy_handle(const sync_id &id) + { + scoped_lock lock(mtx_); + umap_type::iterator it = umap_.find(id); + umap_type::iterator itend = umap_.end(); + + if(it != itend){ + winapi::close_handle(it->second); + const map_type::key_type &k = &it->first; + map_.erase(k); + umap_.erase(it); + } + } + + void destroy_syncs_in_range(const void *addr, std::size_t size) + { + const sync_id low_id(addr); + const sync_id hig_id(static_cast(addr)+size); + scoped_lock lock(mtx_); + map_type::iterator itlow(map_.lower_bound(&low_id)), + ithig(map_.lower_bound(&hig_id)); + while(itlow != ithig){ + void * const hnd = umap_[*itlow->first]; + winapi::close_handle(hnd); + umap_.erase(*itlow->first); + itlow = map_.erase(itlow); + } + } + + private: + spin_mutex mtx_; + umap_type umap_; + map_type map_; +}; + + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp b/libraries/boost/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp new file mode 100644 index 000000000..983e33571 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp @@ -0,0 +1,134 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP +#define BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class winapi_mutex_functions +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + winapi_mutex_functions(const winapi_mutex_functions &); + winapi_mutex_functions &operator=(const winapi_mutex_functions &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + winapi_mutex_functions(void *mtx_hnd) + : m_mtx_hnd(mtx_hnd) + {} + + void unlock() + { winapi::release_mutex(m_mtx_hnd); } + + void lock() + { return winapi_wrapper_wait_for_single_object(m_mtx_hnd); } + + bool try_lock() + { return winapi_wrapper_try_wait_for_single_object(m_mtx_hnd); } + + bool timed_lock(const boost::posix_time::ptime &abs_time) + { return winapi_wrapper_timed_wait_for_single_object(m_mtx_hnd, abs_time); } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + protected: + void *m_mtx_hnd; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//Swappable mutex wrapper +class winapi_mutex_wrapper + : public winapi_mutex_functions +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + winapi_mutex_wrapper(const winapi_mutex_wrapper &); + winapi_mutex_wrapper &operator=(const winapi_mutex_wrapper &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //Note that Windows API does not return winapi::invalid_handle_value + //when failing to create/open a mutex, but a nullptr + + public: + winapi_mutex_wrapper(void *mtx_hnd = 0) + : winapi_mutex_functions(mtx_hnd) + {} + + ~winapi_mutex_wrapper() + { this->close(); } + + void *release() + { + void *hnd = m_mtx_hnd; + m_mtx_hnd = 0; + return hnd; + } + + void *handle() const + { return m_mtx_hnd; } + + bool open_or_create(const char *name, const permissions &perm) + { + if(m_mtx_hnd == 0){ + m_mtx_hnd = winapi::open_or_create_mutex + ( name + , false + , (winapi::interprocess_security_attributes*)perm.get_permissions() + ); + return m_mtx_hnd != 0; + } + else{ + return false; + } + } + + void close() + { + if(m_mtx_hnd != 0){ + winapi::close_handle(m_mtx_hnd); + m_mtx_hnd = 0; + } + } + + void swap(winapi_mutex_wrapper &other) + { void *tmp = m_mtx_hnd; m_mtx_hnd = other.m_mtx_hnd; other.m_mtx_hnd = tmp; } +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp b/libraries/boost/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp new file mode 100644 index 000000000..c98224f15 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp @@ -0,0 +1,168 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINAPI_SEMAPHORE_WRAPPER_HPP +#define BOOST_INTERPROCESS_DETAIL_WINAPI_SEMAPHORE_WRAPPER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class winapi_semaphore_functions +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //Non-copyable + winapi_semaphore_functions(const winapi_semaphore_functions &); + winapi_semaphore_functions &operator=(const winapi_semaphore_functions &); + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + winapi_semaphore_functions(void *hnd) + : m_sem_hnd(hnd) + {} + + void post(long count = 1) + { + long prev_count; + winapi::release_semaphore(m_sem_hnd, count, &prev_count); + } + + void wait() + { return winapi_wrapper_wait_for_single_object(m_sem_hnd); } + + bool try_wait() + { return winapi_wrapper_try_wait_for_single_object(m_sem_hnd); } + + bool timed_wait(const boost::posix_time::ptime &abs_time) + { return winapi_wrapper_timed_wait_for_single_object(m_sem_hnd, abs_time); } + + long value() const + { + long l_count, l_limit; + if(!winapi::get_semaphore_info(m_sem_hnd, l_count, l_limit)) + return 0; + return l_count; + } + + long limit() const + { + long l_count, l_limit; + if(!winapi::get_semaphore_info(m_sem_hnd, l_count, l_limit)) + return 0; + return l_limit; + } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + protected: + void *m_sem_hnd; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + + +//Swappable semaphore wrapper +class winapi_semaphore_wrapper + : public winapi_semaphore_functions +{ + winapi_semaphore_wrapper(const winapi_semaphore_wrapper &); + winapi_semaphore_wrapper &operator=(const winapi_semaphore_wrapper &); + + public: + + //Long is 32 bits in windows + static const long MaxCount = long(0x7FFFFFFF); + + winapi_semaphore_wrapper(void *hnd = winapi::invalid_handle_value) + : winapi_semaphore_functions(hnd) + {} + + ~winapi_semaphore_wrapper() + { this->close(); } + + void *release() + { + void *hnd = m_sem_hnd; + m_sem_hnd = winapi::invalid_handle_value; + return hnd; + } + + void *handle() const + { return m_sem_hnd; } + + bool open_or_create( const char *name + , long sem_count + , long max_count + , const permissions &perm + , bool &created) + { + if(m_sem_hnd == winapi::invalid_handle_value){ + m_sem_hnd = winapi::open_or_create_semaphore + ( name + , sem_count + , max_count + , (winapi::interprocess_security_attributes*)perm.get_permissions() + ); + created = winapi::get_last_error() != winapi::error_already_exists; + return m_sem_hnd != winapi::invalid_handle_value; + } + else{ + return false; + } + } + + bool open_semaphore(const char *name) + { + if(m_sem_hnd == winapi::invalid_handle_value){ + m_sem_hnd = winapi::open_semaphore(name); + return m_sem_hnd != winapi::invalid_handle_value; + } + else{ + return false; + } + } + + void close() + { + if(m_sem_hnd != winapi::invalid_handle_value){ + winapi::close_handle(m_sem_hnd); + m_sem_hnd = winapi::invalid_handle_value; + } + } + + void swap(winapi_semaphore_wrapper &other) + { void *tmp = m_sem_hnd; m_sem_hnd = other.m_sem_hnd; other.m_sem_hnd = tmp; } +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_SEMAPHORE_WRAPPER_HPP diff --git a/libraries/boost/boost/interprocess/sync/windows/winapi_wrapper_common.hpp b/libraries/boost/boost/interprocess/sync/windows/winapi_wrapper_common.hpp new file mode 100644 index 000000000..428a26eb6 --- /dev/null +++ b/libraries/boost/boost/interprocess/sync/windows/winapi_wrapper_common.hpp @@ -0,0 +1,97 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_WINAPI_WRAPPER_COMMON_HPP +#define BOOST_INTERPROCESS_DETAIL_WINAPI_WRAPPER_COMMON_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +inline void winapi_wrapper_wait_for_single_object(void *handle) +{ + unsigned long ret = winapi::wait_for_single_object(handle, winapi::infinite_time); + if(ret != winapi::wait_object_0){ + if(ret != winapi::wait_abandoned){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + else{ //Special case for orphaned mutexes + winapi::release_mutex(handle); + throw interprocess_exception(owner_dead_error); + } + } +} + +inline bool winapi_wrapper_try_wait_for_single_object(void *handle) +{ + unsigned long ret = winapi::wait_for_single_object(handle, 0); + if(ret == winapi::wait_object_0){ + return true; + } + else if(ret == winapi::wait_timeout){ + return false; + } + else{ + error_info err = system_error_code(); + throw interprocess_exception(err); + } +} + +inline bool winapi_wrapper_timed_wait_for_single_object(void *handle, const boost::posix_time::ptime &abs_time) +{ + //Windows does not support infinity abs_time so check it + if(abs_time == boost::posix_time::pos_infin){ + winapi_wrapper_wait_for_single_object(handle); + return true; + } + const boost::posix_time::ptime cur_time = microsec_clock::universal_time(); + //Windows uses relative wait times so check for negative waits + //and implement as 0 wait to allow try-semantics as POSIX mandates. + unsigned long ret = winapi::wait_for_single_object + ( handle + , (abs_time <= cur_time) ? 0u + : (abs_time - cur_time).total_milliseconds() + ); + if(ret == winapi::wait_object_0){ + return true; + } + else if(ret == winapi::wait_timeout){ + return false; + } + else{ + error_info err = system_error_code(); + throw interprocess_exception(err); + } +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP diff --git a/libraries/boost/boost/interprocess/windows_shared_memory.hpp b/libraries/boost/boost/interprocess/windows_shared_memory.hpp new file mode 100644 index 000000000..341674aec --- /dev/null +++ b/libraries/boost/boost/interprocess/windows_shared_memory.hpp @@ -0,0 +1,252 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_WINDOWS_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_WINDOWS_SHARED_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include + +#if !defined(BOOST_INTERPROCESS_WINDOWS) +#error "This header can only be used in Windows operating systems" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes a class representing a native windows shared memory. + +namespace boost { +namespace interprocess { + +//!A class that wraps the native Windows shared memory +//!that is implemented as a file mapping of the paging file. +//!Unlike shared_memory_object, windows_shared_memory has +//!no kernel persistence and the shared memory is destroyed +//!when all processes destroy all their windows_shared_memory +//!objects and mapped regions for the same shared memory +//!or the processes end/crash. +//! +//!Warning: Windows native shared memory and interprocess portable +//!shared memory (boost::interprocess::shared_memory_object) +//!can't communicate between them. +class windows_shared_memory +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable and non-assignable + BOOST_MOVABLE_BUT_NOT_COPYABLE(windows_shared_memory) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Default constructor. + //!Represents an empty windows_shared_memory. + windows_shared_memory(); + + //!Creates a new native shared memory with name "name" and at least size "size", + //!with the access mode "mode". + //!If the file previously exists, throws an error. + windows_shared_memory(create_only_t, const char *name, mode_t mode, std::size_t size, const permissions& perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoCreate, name, mode, size, perm); } + + //!Tries to create a shared memory object with name "name" and at least size "size", with the + //!access mode "mode". If the file previously exists, it tries to open it with mode "mode". + //!Otherwise throws an error. + windows_shared_memory(open_or_create_t, const char *name, mode_t mode, std::size_t size, const permissions& perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, size, perm); } + + //!Tries to open a shared memory object with name "name", with the access mode "mode". + //!If the file does not previously exist, it throws an error. + windows_shared_memory(open_only_t, const char *name, mode_t mode) + { this->priv_open_or_create(ipcdetail::DoOpen, name, mode, 0, permissions()); } + + //!Moves the ownership of "moved"'s shared memory object to *this. + //!After the call, "moved" does not represent any shared memory object. + //!Does not throw + windows_shared_memory(BOOST_RV_REF(windows_shared_memory) moved) + : m_handle(0) + { this->swap(moved); } + + //!Moves the ownership of "moved"'s shared memory to *this. + //!After the call, "moved" does not represent any shared memory. + //!Does not throw + windows_shared_memory &operator=(BOOST_RV_REF(windows_shared_memory) moved) + { + windows_shared_memory tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps to shared_memory_objects. Does not throw + void swap(windows_shared_memory &other); + + //!Destroys *this. All mapped regions are still valid after + //!destruction. When all mapped regions and windows_shared_memory + //!objects referring the shared memory are destroyed, the + //!operating system will destroy the shared memory. + ~windows_shared_memory(); + + //!Returns the name of the shared memory. + const char *get_name() const; + + //!Returns access mode + mode_t get_mode() const; + + //!Returns the mapping handle. Never throws + mapping_handle_t get_mapping_handle() const; + + //!Returns the size of the windows shared memory. It will be a 4K rounded + //!size of the "size" passed in the constructor. + offset_t get_size() const; + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + 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, std::size_t size, const permissions& perm = permissions()); + + void * m_handle; + mode_t m_mode; + std::string m_name; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline windows_shared_memory::windows_shared_memory() + : m_handle(0) +{} + +inline windows_shared_memory::~windows_shared_memory() +{ this->priv_close(); } + +inline const char *windows_shared_memory::get_name() const +{ return m_name.c_str(); } + +inline void windows_shared_memory::swap(windows_shared_memory &other) +{ + (simple_swap)(m_handle, other.m_handle); + (simple_swap)(m_mode, other.m_mode); + m_name.swap(other.m_name); +} + +inline mapping_handle_t windows_shared_memory::get_mapping_handle() const +{ mapping_handle_t mhnd = { m_handle, true}; return mhnd; } + +inline mode_t windows_shared_memory::get_mode() const +{ return m_mode; } + +inline offset_t windows_shared_memory::get_size() const +{ + offset_t size; //This shall never fail + return (m_handle && winapi::get_file_mapping_size(m_handle, size)) ? size : 0; +} + +inline bool windows_shared_memory::priv_open_or_create + (ipcdetail::create_enum_t type, const char *filename, mode_t mode, std::size_t size, const permissions& perm) +{ + m_name = filename ? filename : ""; + + unsigned long protection = 0; + unsigned long map_access = 0; + + switch(mode) + { + //"protection" is for "create_file_mapping" + //"map_access" is for "open_file_mapping" + //Add section query (strange that read or access does not grant it...) + //to obtain the size of the mapping. copy_on_write is equal to section_query. + case read_only: + protection |= winapi::page_readonly; + map_access |= winapi::file_map_read | winapi::section_query; + break; + case read_write: + protection |= winapi::page_readwrite; + map_access |= winapi::file_map_write | winapi::section_query; + break; + case copy_on_write: + protection |= winapi::page_writecopy; + map_access |= winapi::file_map_copy; + break; + default: + { + error_info err(mode_error); + throw interprocess_exception(err); + } + break; + } + + switch(type){ + case ipcdetail::DoOpen: + m_handle = winapi::open_file_mapping(map_access, filename); + break; + case ipcdetail::DoCreate: + case ipcdetail::DoOpenOrCreate: + { + m_handle = winapi::create_file_mapping + ( winapi::invalid_handle_value, protection, size, filename + , (winapi::interprocess_security_attributes*)perm.get_permissions()); + } + break; + default: + { + error_info err = other_error; + throw interprocess_exception(err); + } + } + + if(!m_handle || (type == ipcdetail::DoCreate && winapi::get_last_error() == winapi::error_already_exists)){ + error_info err = system_error_code(); + this->priv_close(); + throw interprocess_exception(err); + } + + m_mode = mode; + return true; +} + +inline void windows_shared_memory::priv_close() +{ + if(m_handle){ + winapi::close_handle(m_handle); + m_handle = 0; + } +} + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_WINDOWS_SHARED_MEMORY_HPP diff --git a/libraries/boost/boost/interprocess/xsi_key.hpp b/libraries/boost/boost/interprocess/xsi_key.hpp new file mode 100644 index 000000000..084411ed3 --- /dev/null +++ b/libraries/boost/boost/interprocess/xsi_key.hpp @@ -0,0 +1,95 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009. 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_KEY_HPP +#define BOOST_INTERPROCESS_XSI_KEY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#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 +#include +#include +#include + +//!\file +//!Describes a class representing a xsi key type. + +namespace boost { +namespace interprocess { + +//!A class that wraps XSI (System V) key_t type. +//!This type calculates key_t from path and id using ftok +//!or sets key to IPC_PRIVATE using the default constructor. +class xsi_key +{ + public: + + //!Default constructor. + //!Represents a private xsi_key. + xsi_key() + : m_key(IPC_PRIVATE) + {} + + //!Creates a new XSI shared memory with a key obtained from a call to ftok (with path + //!"path" and id "id"), of size "size" and permissions "perm". + //!If the shared memory previously exists, throws an error. + xsi_key(const char *path, boost::uint8_t id) + { + key_t key; + if(path){ + key = ::ftok(path, id); + if(((key_t)-1) == key){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + } + else{ + key = IPC_PRIVATE; + } + m_key = key; + } + + //!Returns the internal key_t value + key_t get_key() const + { return m_key; } + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + key_t m_key; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_XSI_KEY_HPP diff --git a/libraries/boost/boost/interprocess/xsi_shared_memory.hpp b/libraries/boost/boost/interprocess/xsi_shared_memory.hpp new file mode 100644 index 000000000..cb5db8f79 --- /dev/null +++ b/libraries/boost/boost/interprocess/xsi_shared_memory.hpp @@ -0,0 +1,215 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#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 +#include +// move +#include +// other boost +#include +// std +#include +// OS +#include + + +//!\file +//!Describes a class representing a native xsi shared memory. + +namespace boost { +namespace interprocess { + +//!A class that wraps XSI (System V) shared memory. +//!Unlike shared_memory_object, xsi_shared_memory needs a valid +//!xsi_key to identify a shared memory object. +//! +//!Warning: XSI shared memory and interprocess portable +//!shared memory (boost::interprocess::shared_memory_object) +//!can't communicate between them. +class xsi_shared_memory +{ + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //Non-copyable and non-assignable + BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory) + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //!Default constructor. + //!Represents an empty xsi_shared_memory. + xsi_shared_memory(); + + //!Initializes *this with a shmid previously obtained (possibly from another process) + //!This lower-level initializer allows shared memory mapping without having a key. + xsi_shared_memory(open_only_t, int shmid) + : m_shmid (shmid) + {} + + //!Creates a new XSI shared memory from 'key', with size "size" and permissions "perm". + //!If the shared memory previously exists, throws an error. + xsi_shared_memory(create_only_t, const xsi_key &key, std::size_t size, const permissions& perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoCreate, key, perm, size); } + + //!Opens an existing shared memory with identifier 'key' or creates a new XSI shared memory from + //!identifier 'key', with size "size" and permissions "perm". + xsi_shared_memory(open_or_create_t, const xsi_key &key, std::size_t size, const permissions& perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoOpenOrCreate, key, perm, size); } + + //!Tries to open a XSI shared memory with identifier 'key' + //!If the shared memory does not previously exist, it throws an error. + xsi_shared_memory(open_only_t, const xsi_key &key) + { this->priv_open_or_create(ipcdetail::DoOpen, key, permissions(), 0); } + + //!Moves the ownership of "moved"'s shared memory object to *this. + //!After the call, "moved" does not represent any shared memory object. + //!Does not throw + xsi_shared_memory(BOOST_RV_REF(xsi_shared_memory) moved) + : m_shmid(-1) + { this->swap(moved); } + + //!Moves the ownership of "moved"'s shared memory to *this. + //!After the call, "moved" does not represent any shared memory. + //!Does not throw + xsi_shared_memory &operator=(BOOST_RV_REF(xsi_shared_memory) moved) + { + xsi_shared_memory tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps two xsi_shared_memorys. Does not throw + void swap(xsi_shared_memory &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(); + + //!Returns the shared memory ID that + //!identifies the shared memory + int get_shmid() const; + + //!Returns the mapping handle. + //!Never throws + mapping_handle_t get_mapping_handle() const; + + //!Erases the XSI shared memory object identified by shmid + //!from the system. + //!Returns false on error. Never throws + static bool remove(int shmid); + + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + + //!Closes a previously opened file mapping. Never throws. + bool priv_open_or_create( ipcdetail::create_enum_t type + , const xsi_key &key + , const permissions& perm + , std::size_t size); + int m_shmid; + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline xsi_shared_memory::xsi_shared_memory() + : m_shmid(-1) +{} + +inline xsi_shared_memory::~xsi_shared_memory() +{} + +inline int xsi_shared_memory::get_shmid() const +{ return m_shmid; } + +inline void xsi_shared_memory::swap(xsi_shared_memory &other) +{ + (simple_swap)(m_shmid, other.m_shmid); +} + +inline mapping_handle_t xsi_shared_memory::get_mapping_handle() const +{ mapping_handle_t mhnd = { m_shmid, true}; return mhnd; } + +inline bool xsi_shared_memory::priv_open_or_create + (ipcdetail::create_enum_t type, const xsi_key &key, const permissions& permissions, std::size_t size) +{ + int perm = permissions.get_permissions(); + perm &= 0x01FF; + int shmflg = perm; + + switch(type){ + case ipcdetail::DoOpen: + shmflg |= 0; + break; + case ipcdetail::DoCreate: + shmflg |= IPC_CREAT | IPC_EXCL; + break; + case ipcdetail::DoOpenOrCreate: + shmflg |= IPC_CREAT; + break; + default: + { + error_info err = other_error; + throw interprocess_exception(err); + } + } + + int ret = ::shmget(key.get_key(), size, shmflg); + int shmid = ret; + if((type == ipcdetail::DoOpen) && (-1 != ret)){ + //Now get the size + ::shmid_ds xsi_ds; + ret = ::shmctl(ret, IPC_STAT, &xsi_ds); + size = xsi_ds.shm_segsz; + } + if(-1 == ret){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + + m_shmid = shmid; + return true; +} + +inline bool xsi_shared_memory::remove(int shmid) +{ return -1 != ::shmctl(shmid, IPC_RMID, 0); } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_HPP From b44965605eec953b82562066a02ce9e47d6dea92 Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Sun, 14 Jan 2018 15:25:59 -0800 Subject: [PATCH 3/5] Use boost for managind the shared memory to make it easier to port to other platforms. --- source/frontend/processrenderoptions.cpp | 1 + source/povms/povmsid.h | 2 + vfe/vfe.h | 13 +- vfe/vfedisplay.cpp | 58 ++++++++- vfe/win/console/winconsole.cpp | 151 +---------------------- 5 files changed, 70 insertions(+), 155 deletions(-) diff --git a/source/frontend/processrenderoptions.cpp b/source/frontend/processrenderoptions.cpp index 2187706f2..5fbb67ae5 100644 --- a/source/frontend/processrenderoptions.cpp +++ b/source/frontend/processrenderoptions.cpp @@ -311,6 +311,7 @@ struct ProcessOptions::Cmd_Parser_Table RenderOptions_Cmd_Table[] = { "SC", kPOVAttrib_Left, kPOVMSType_Float, kNoParameter }, { "SF0", kPOVAttrib_SubsetStartFrame, kPOVMSType_Float, kNoParameter }, { "SF", kPOVAttrib_SubsetStartFrame, kPOVMSType_Int, kNoParameter }, + { "SM", kPOVAttrib_SharedMemory, kPOVMSType_UCS2String, kNoParameter }, { "SP", kPOVAttrib_PreviewStartSize, kPOVMSType_Int, kNoParameter }, { "SR", kPOVAttrib_Top, kPOVMSType_Float, kNoParameter }, { "STP", kPOVAttrib_FrameStep, kPOVMSType_Int, kNoParameter }, diff --git a/source/povms/povmsid.h b/source/povms/povmsid.h index 98f0489dc..a61b0cc80 100644 --- a/source/povms/povmsid.h +++ b/source/povms/povmsid.h @@ -420,6 +420,8 @@ enum kPOVAttrib_MaxImageBufferMem = 'MIBM', // [JG] for file backed image + kPOVAttrib_SharedMemory = 'ShaM', + kPOVAttrib_CameraIndex = 'CIdx', // time statistics generated by frontend diff --git a/vfe/vfe.h b/vfe/vfe.h index 53bfbaef1..ecdb7e1d4 100644 --- a/vfe/vfe.h +++ b/vfe/vfe.h @@ -43,6 +43,11 @@ #include #include #include +#include +#include +#ifdef BOOST_WINDOWS +#include +#endif #include "povms/povmscpp.h" #include "povms/povmsid.h" @@ -212,8 +217,14 @@ namespace vfe protected: vfeSession *m_Session; - vector m_Pixels; + void *m_Buffer; bool m_VisibleOnCreation; +#ifdef BOOST_WINDOWS + boost::interprocess::windows_shared_memory *m_SharedMemory; +#else + boost::interprocess::shared_memory_object *m_SharedMemory; +#endif + boost::interprocess::mapped_region *m_MappedRegion; }; class VirtualFrontEnd diff --git a/vfe/vfedisplay.cpp b/vfe/vfedisplay.cpp index 287aded0a..26021e151 100644 --- a/vfe/vfedisplay.cpp +++ b/vfe/vfedisplay.cpp @@ -50,21 +50,55 @@ namespace vfe { +struct vfeDisplayBufferHeader +{ + uint32_t Version; + uint32_t Width; + uint32_t Height; + uint32_t PixelsWritten; + uint32_t PixelsRead; +}; + vfeDisplay::vfeDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeSession* session, bool visible) : Display(w, h, gamma), m_Session(session), - m_VisibleOnCreation(visible) + m_VisibleOnCreation(visible), + m_Buffer(NULL), + m_SharedMemory(NULL), + m_MappedRegion(NULL) { } vfeDisplay::~vfeDisplay() { + Clear(); } void vfeDisplay::Initialise() { - m_Pixels.clear(); - m_Pixels.resize(GetWidth() * GetHeight()); + POVMSUCS2String SharedMemoryName = m_Session->GetOptions().GetOptions().TryGetUCS2String(kPOVAttrib_SharedMemory, ""); + const size_t AllocSize = GetWidth() * GetHeight() * sizeof(RGBA8) + sizeof(vfeDisplayBufferHeader); + + if (SharedMemoryName.empty()) + m_Buffer = malloc(AllocSize); + else + { +#ifdef BOOST_WINDOWS + m_SharedMemory = new boost::interprocess::windows_shared_memory(boost::interprocess::open_or_create, UCS2toASCIIString(SharedMemoryName).c_str(), boost::interprocess::read_write, AllocSize); +#else + m_SharedMemory = new boost::interprocess::shared_memory_object(boost::interprocess::open_or_create, UCS2toASCIIString(SharedMemoryName).c_str(), boost::interprocess::read_write); + m_SharedMemory->truncate(AllocSize); +#endif + m_MappedRegion = new boost::interprocess::mapped_region(*m_SharedMemory, boost::interprocess::read_write); + m_Buffer = m_MappedRegion->get_address(); + + vfeDisplayBufferHeader* Header = (vfeDisplayBufferHeader*)m_Buffer; + Header->Version = 1; + Header->Width = GetWidth(); + Header->Height = GetHeight(); + Header->PixelsWritten = 0; + Header->PixelsRead = 0; + } } void vfeDisplay::Close() @@ -82,7 +116,10 @@ void vfeDisplay::Hide() void vfeDisplay::DrawPixel(unsigned int x, unsigned int y, const RGBA8& colour) { assert (x < GetWidth() && y < GetHeight()); - m_Pixels[y * GetHeight() + x] = colour; + vfeDisplayBufferHeader* Header = (vfeDisplayBufferHeader*)m_Buffer; + RGBA8* Pixels = (RGBA8*)(Header + 1); + Pixels[y * GetWidth() + x] = colour; + Header->PixelsWritten++; } void vfeDisplay::DrawRectangleFrame(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, const RGBA8& colour) @@ -102,7 +139,18 @@ void vfeDisplay::DrawPixelBlock(unsigned int x1, unsigned int y1, unsigned int x void vfeDisplay::Clear() { - m_Pixels.clear(); + if (!m_SharedMemory) + free(m_Buffer); + else + { + POVMSUCS2String SharedMemoryName = m_Session->GetOptions().GetOptions().TryGetUCS2String(kPOVAttrib_SharedMemory, ""); + boost::interprocess::shared_memory_object::remove(UCS2toASCIIString(SharedMemoryName).c_str()); + delete m_MappedRegion; + m_MappedRegion = NULL; + delete m_SharedMemory; + m_SharedMemory = NULL; + } + m_Buffer = NULL; } } diff --git a/vfe/win/console/winconsole.cpp b/vfe/win/console/winconsole.cpp index 61df148cd..e56d37d5a 100644 --- a/vfe/win/console/winconsole.cpp +++ b/vfe/win/console/winconsole.cpp @@ -86,127 +86,6 @@ void ErrorExit(vfeSession *session) exit (1); } -const char* gSharedMemoryName = "leocad-povray"; - -struct lcSharedMemoryHeader -{ - uint32_t Version; - uint32_t Width; - uint32_t Height; - uint32_t PixelsWritten; - uint32_t PixelsRead; -}; - -class WinSharedMemoryDisplay : public vfeDisplay -{ -public: - WinSharedMemoryDisplay(unsigned int width, unsigned int height, GammaCurvePtr gamma, vfeSession *session, bool visible = false) - : vfeDisplay( width, height, gamma, session, visible ) - { - mBuffer = NULL; - mMapFile = INVALID_HANDLE_VALUE; - } - - virtual ~WinSharedMemoryDisplay() - { - Close(); - } - - virtual void Initialise() - { - if (mMapFile != INVALID_HANDLE_VALUE) - return; - - int BufferSize = sizeof(lcSharedMemoryHeader) + GetWidth() * GetHeight() * sizeof(RGBA8); - - mMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BufferSize, gSharedMemoryName); - - if (!mMapFile) - return; - - mBuffer = MapViewOfFile(mMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BufferSize); - - if (!mBuffer) - { - CloseHandle(mMapFile); - mMapFile = INVALID_HANDLE_VALUE; - return; - } - - lcSharedMemoryHeader* Header = (lcSharedMemoryHeader*)mBuffer; - Header->Version = 1; - Header->Width = GetWidth(); - Header->Height = GetHeight(); - Header->PixelsWritten = 0; - Header->PixelsRead = 0; - } - - virtual void Close() - { - if (mBuffer) - { - lcSharedMemoryHeader* Header = (lcSharedMemoryHeader*)mBuffer; - if (Header->PixelsWritten != Header->PixelsRead) - Sleep(5000); - - UnmapViewOfFile(mBuffer); - mBuffer = NULL; - } - - if (mMapFile != INVALID_HANDLE_VALUE) - { - CloseHandle(mMapFile); - mMapFile = INVALID_HANDLE_VALUE; - } - } - - virtual void DrawPixel(unsigned int x, unsigned int y, const RGBA8& colour) - { - lcSharedMemoryHeader* Header = (lcSharedMemoryHeader*)mBuffer; - RGBA8* Pixels = (RGBA8*)(Header + 1); - Pixels[y * GetWidth() + x] = colour; - Header->PixelsWritten++; - } - - virtual void DrawRectangleFrame(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, const RGBA8& colour) - { - for (unsigned int x = x1; x <= x2; x++) - DrawPixel(x, y1, colour); - for (unsigned int x = x1; x <= x2; x++) - DrawPixel(x, y2, colour); - for (unsigned int y = y1; y <= y2; y++) - { - DrawPixel(x1, y, colour); - DrawPixel(x2, y, colour); - } - } - - virtual void DrawFilledRectangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, const RGBA8& colour) - { - for (unsigned int y = y1; y <= y2; y++) - for (unsigned int x = x1; x <= x2; x++) - DrawPixel(x, y, colour); - } - - virtual void DrawPixelBlock(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, const RGBA8 *colour) - { - for (int y = y1; y <= y2; y++) - for (int x = x1; x <= x2; x++) - DrawPixel(x, y, *colour++); - } - -protected: - HANDLE mMapFile; - void* mBuffer; -}; - -vfeDisplay *SharedMemoryDisplayCreator(unsigned int width, unsigned int height, GammaCurvePtr gamma, vfeSession *session, bool visible) -{ - return new WinSharedMemoryDisplay(width, height, gamma, session, visible); -} - -int pause = 0; - // this is an example of a minimal console version of POV-Ray using the VFE // (virtual front-end) library. it is NOT INTENDED TO BE A FULLY-FEATURED // CONSOLE IMPLEMENTATION OF POV-RAY and is not officially supported. see @@ -218,8 +97,6 @@ int main (int argc, char **argv) vfeStatusFlags flags; vfeRenderOptions opts; - session->SetDisplayCreator(SharedMemoryDisplayCreator); - fprintf(stderr, "This is an example of a minimal console build of POV-Ray under Windows.\n\n" "Persistence of Vision(tm) Ray Tracer Version " POV_RAY_VERSION_INFO ".\n" @@ -235,32 +112,8 @@ int main (int argc, char **argv) if ((s = getenv ("POVINC")) != NULL) opts.AddLibraryPath (s); - argv++; - while (*argv) - { - if (!strcmp(*argv, "-pause")) - { - pause = 1; - argv++; - } - else if (!strcmp(*argv, "-shared-memory")) - { - argv++; - if (*argv) - { - gSharedMemoryName = *argv; - argv++; - } - } - else - { - opts.AddCommand(*argv); - argv++; - } - } - - if (pause) - MessageBox(0, "", "", MB_OK); + while (*++argv) + opts.AddCommand(*argv); if (session->SetOptions(opts) != vfeNoError) ErrorExit(session); From 1465fb2e32bb39e937e8cfb8b49e826b2b0d1f7d Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Sun, 14 Jan 2018 21:46:49 -0800 Subject: [PATCH 4/5] Use a memory mapped file instead of shared memory, works better on all platforms. --- vfe/vfe.h | 11 ++--------- vfe/vfedisplay.cpp | 45 ++++++++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/vfe/vfe.h b/vfe/vfe.h index ecdb7e1d4..ecc3540b6 100644 --- a/vfe/vfe.h +++ b/vfe/vfe.h @@ -43,11 +43,8 @@ #include #include #include -#include +#include #include -#ifdef BOOST_WINDOWS -#include -#endif #include "povms/povmscpp.h" #include "povms/povmsid.h" @@ -219,11 +216,7 @@ namespace vfe vfeSession *m_Session; void *m_Buffer; bool m_VisibleOnCreation; -#ifdef BOOST_WINDOWS - boost::interprocess::windows_shared_memory *m_SharedMemory; -#else - boost::interprocess::shared_memory_object *m_SharedMemory; -#endif + boost::interprocess::file_mapping *m_FileMapping; boost::interprocess::mapped_region *m_MappedRegion; }; diff --git a/vfe/vfedisplay.cpp b/vfe/vfedisplay.cpp index 26021e151..1eec6bef0 100644 --- a/vfe/vfedisplay.cpp +++ b/vfe/vfedisplay.cpp @@ -37,6 +37,8 @@ #include "backend/frame.h" #include "vfe.h" +#include +#include // this must be the last file included #include "syspovdebug.h" @@ -64,7 +66,7 @@ vfeDisplay::vfeDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeS m_Session(session), m_VisibleOnCreation(visible), m_Buffer(NULL), - m_SharedMemory(NULL), + m_FileMapping(NULL), m_MappedRegion(NULL) { } @@ -83,21 +85,24 @@ void vfeDisplay::Initialise() m_Buffer = malloc(AllocSize); else { -#ifdef BOOST_WINDOWS - m_SharedMemory = new boost::interprocess::windows_shared_memory(boost::interprocess::open_or_create, UCS2toASCIIString(SharedMemoryName).c_str(), boost::interprocess::read_write, AllocSize); -#else - m_SharedMemory = new boost::interprocess::shared_memory_object(boost::interprocess::open_or_create, UCS2toASCIIString(SharedMemoryName).c_str(), boost::interprocess::read_write); - m_SharedMemory->truncate(AllocSize); -#endif - m_MappedRegion = new boost::interprocess::mapped_region(*m_SharedMemory, boost::interprocess::read_write); - m_Buffer = m_MappedRegion->get_address(); - - vfeDisplayBufferHeader* Header = (vfeDisplayBufferHeader*)m_Buffer; - Header->Version = 1; - Header->Width = GetWidth(); - Header->Height = GetHeight(); - Header->PixelsWritten = 0; - Header->PixelsRead = 0; + std::string FileName = UCS2toASCIIString(SharedMemoryName); + std::filebuf fbuf; + fbuf.open(FileName, std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary); + fbuf.pubseekoff(AllocSize, std::ios_base::beg); + fbuf.sputc(0); + fbuf.close(); + + m_FileMapping = new boost::interprocess::file_mapping(FileName.c_str(), boost::interprocess::read_write); + m_MappedRegion = new boost::interprocess::mapped_region(*m_FileMapping, boost::interprocess::read_write); + + m_Buffer = m_MappedRegion->get_address(); + + vfeDisplayBufferHeader* Header = (vfeDisplayBufferHeader*)m_Buffer; + Header->Version = 1; + Header->Width = GetWidth(); + Header->Height = GetHeight(); + Header->PixelsWritten = 0; + Header->PixelsRead = 0; } } @@ -139,16 +144,14 @@ void vfeDisplay::DrawPixelBlock(unsigned int x1, unsigned int y1, unsigned int x void vfeDisplay::Clear() { - if (!m_SharedMemory) + if (!m_FileMapping) free(m_Buffer); else { - POVMSUCS2String SharedMemoryName = m_Session->GetOptions().GetOptions().TryGetUCS2String(kPOVAttrib_SharedMemory, ""); - boost::interprocess::shared_memory_object::remove(UCS2toASCIIString(SharedMemoryName).c_str()); delete m_MappedRegion; m_MappedRegion = NULL; - delete m_SharedMemory; - m_SharedMemory = NULL; + delete m_FileMapping; + m_FileMapping = NULL; } m_Buffer = NULL; } From 3039594ec1c8ba0ebd6ed97f44c02f15171cadac Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Sun, 14 Jan 2018 22:13:34 -0800 Subject: [PATCH 5/5] Have UnixDisplay call vfeDisplay Initialise and DrawPixel methods. --- unix/disp_text.cpp | 14 ++++++++++---- unix/disp_text.h | 8 ++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/unix/disp_text.cpp b/unix/disp_text.cpp index 178f77921..5917a8645 100644 --- a/unix/disp_text.cpp +++ b/unix/disp_text.cpp @@ -60,8 +60,14 @@ namespace pov_frontend return true; } - void UnixTextDisplay::DrawPixel(unsigned int x, unsigned int y, const RGBA8& colour) - { - //fprintf(stderr, "DrawPixel(%d,%d)\n", x, y); - } + void UnixTextDisplay::Initialise() + { + vfeDisplay::Initialise(); + } + + void UnixTextDisplay::DrawPixel(unsigned int x, unsigned int y, const RGBA8& colour) + { + vfeDisplay::DrawPixel(x, y, colour); + //fprintf(stderr, "DrawPixel(%d,%d)\n", x, y); + } } diff --git a/unix/disp_text.h b/unix/disp_text.h index 83e1dbef5..8c9497daf 100644 --- a/unix/disp_text.h +++ b/unix/disp_text.h @@ -56,13 +56,13 @@ namespace pov_frontend UnixTextDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeSession *session, bool visible) : UnixDisplay(w, h, gamma, session, visible) {}; virtual ~UnixTextDisplay() {} ; - void Initialise() {}; - void Close() {}; + void Initialise(); + void Close() {}; void Show() {}; void Hide() {}; bool TakeOver(UnixDisplay *display) { return false; }; - void DrawPixel(unsigned int x, unsigned int y, const RGBA8& colour); - bool HandleEvents() { return false; }; + void DrawPixel(unsigned int x, unsigned int y, const RGBA8& colour); + bool HandleEvents() { return false; }; void UpdateScreen(bool Force = false) {}; void PauseWhenDoneNotifyStart() {}; bool PauseWhenDoneResumeIsRequested() { return true; };