simple_seq_fit_impl.hpp
来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 1,114 行 · 第 1/3 页
HPP
1,114 行
////////////////////////////////////////////////////////////////////////////////// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost// Software License, Version 1.0. (See accompanying file// LICENSE_1_0.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#if (defined _MSC_VER) && (_MSC_VER >= 1200)# pragma once#endif#include <boost/interprocess/detail/config_begin.hpp>#include <boost/interprocess/detail/workaround.hpp>#include <boost/interprocess/interprocess_fwd.hpp>#include <boost/interprocess/allocators/allocation_type.hpp>#include <boost/interprocess/offset_ptr.hpp>#include <boost/interprocess/sync/interprocess_mutex.hpp>#include <boost/interprocess/exceptions.hpp>#include <boost/interprocess/detail/utilities.hpp>#include <boost/interprocess/detail/min_max.hpp>#include <boost/interprocess/detail/type_traits.hpp>#include <boost/interprocess/sync/scoped_lock.hpp>#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>#include <algorithm>#include <utility>#include <cstring>#include <cassert>#include <new>//!\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 detail {//!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 MutexFamily, class VoidPointer>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 &); 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 detail::basic_multiallocation_iterator <void_pointer> multiallocation_iterator; typedef detail::basic_multiallocation_chain <void_pointer> multiallocation_chain; private: class block_ctrl; typedef typename detail:: pointer_to_other<void_pointer, block_ctrl>::type block_ctrl_ptr; class block_ctrl; friend class block_ctrl; //!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 std::size_t m_size; std::size_t get_user_bytes() const { return this->m_size*Alignment - BlockCtrlBytes; } std::size_t 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 std::size_t m_allocated; //!The size of the memory segment std::size_t m_size; //!The extra size required by the segment std::size_t m_extra_hdr_bytes; } m_header; friend class detail::basic_multiallocation_iterator<void_pointer>; friend class detail::memory_algorithm_common<simple_seq_fit_impl>; typedef detail::memory_algorithm_common<simple_seq_fit_impl> 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 (std::size_t size, std::size_t extra_hdr_bytes); //!Destructor ~simple_seq_fit_impl(); //!Obtains the minimum size needed by the algorithm static std::size_t get_min_size (std::size_t extra_hdr_bytes); //Functions for single segment management //!Allocates bytes, returns 0 if there is not more memory void* allocate (std::size_t nbytes); /// @cond //!Multiple element allocation, same size multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements); //!Multiple element allocation, different size multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element); //!Multiple element deallocation void deallocate_many(multiallocation_iterator it); /// @endcond //!Deallocates previously allocated bytes void deallocate (void *addr); //!Returns the size of the memory segment std::size_t get_size() const; //!Returns the number of free bytes of the memory segment std::size_t get_free_memory() const; //!Increases managed memory in extra_size bytes more void grow(std::size_t 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<class T> std::pair<T *, bool> allocation_command (allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0); std::pair<void *, bool> raw_allocation_command (allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, void *reuse_ptr = 0, std::size_t sizeof_object = 1); //!Returns the size of the buffer previously allocated pointed by ptr std::size_t 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 (std::size_t nbytes, std::size_t 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 std::pair<void *, bool> priv_allocate(allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size ,void *reuse_ptr = 0); std::pair<void *, bool> priv_allocation_command(allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size ,void *reuse_ptr ,std::size_t sizeof_object); //!Returns the number of total units that a user buffer //!of "userbytes" bytes really occupies (including header) static std::size_t priv_get_total_units(std::size_t userbytes); static std::size_t priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes); std::size_t 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<block_ctrl*, block_ctrl*>priv_prev_block_if_free(block_ctrl *ptr); //!Real expand function implementation bool priv_expand(void *ptr ,std::size_t min_size, std::size_t preferred_size ,std::size_t &received_size); //!Real expand to both sides implementation void* priv_expand_both_sides(allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size ,void *reuse_ptr ,bool only_preferred_backwards); //!Real private aligned allocation function //void* priv_allocate_aligned (std::size_t nbytes, std::size_t alignment); //!Checks if block has enough memory and splits/unlinks the block //!returning the address to the users void* priv_check_and_allocate(std::size_t units ,block_ctrl* prev ,block_ctrl* block ,std::size_t &received_size); //!Real deallocation algorithm void priv_deallocate(void *addr); //!Makes a new memory portion available for allocation void priv_add_segment(void *addr, std::size_t size); void priv_mark_new_allocated_block(block_ctrl *block); public: static const std::size_t Alignment = detail::alignment_of<detail::max_align>::value; private: static const std::size_t BlockCtrlBytes = detail::ct_rounded_size<sizeof(block_ctrl), Alignment>::value; static const std::size_t BlockCtrlUnits = BlockCtrlBytes/Alignment; static const std::size_t MinBlockUnits = BlockCtrlUnits; static const std::size_t MinBlockSize = MinBlockUnits*Alignment; static const std::size_t AllocatedCtrlBytes = BlockCtrlBytes; static const std::size_t AllocatedCtrlUnits = BlockCtrlUnits; static const std::size_t UsableByPreviousChunk = 0; public: static const std::size_t PayloadPerAllocation = BlockCtrlBytes;};template<class MutexFamily, class VoidPointer>inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer> ::priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes){ //First align "this" pointer std::size_t uint_this = (std::size_t)this_ptr; std::size_t uint_aligned_this = uint_this/Alignment*Alignment; std::size_t this_disalignment = (uint_this - uint_aligned_this); std::size_t block1_off = detail::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<class MutexFamily, class VoidPointer>inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer> ::priv_block_end_offset() const{ //First align "this" pointer std::size_t uint_this = (std::size_t)this; std::size_t uint_aligned_this = uint_this/Alignment*Alignment; std::size_t this_disalignment = (uint_this - uint_aligned_this); std::size_t old_end = detail::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<class MutexFamily, class VoidPointer>inline simple_seq_fit_impl<MutexFamily, VoidPointer>:: simple_seq_fit_impl(std::size_t size, std::size_t extra_hdr_bytes){ //Initialize sizes and counters m_header.m_allocated = 0; m_header.m_size = size; m_header.m_extra_hdr_bytes = extra_hdr_bytes; //Initialize pointers std::size_t block1_off = priv_first_block_offset(this, extra_hdr_bytes); m_header.m_root.m_next = reinterpret_cast<block_ctrl*> ((reinterpret_cast<char*>(this) + block1_off)); algo_impl_t::assert_alignment(detail::get_pointer(m_header.m_root.m_next)); m_header.m_root.m_next->m_size = (size - block1_off)/Alignment; m_header.m_root.m_next->m_next = &m_header.m_root;}template<class MutexFamily, class VoidPointer>inline simple_seq_fit_impl<MutexFamily, VoidPointer>::~simple_seq_fit_impl(){ //There is a memory leak!// assert(m_header.m_allocated == 0);// assert(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root));}template<class MutexFamily, class VoidPointer>inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::grow(std::size_t extra_size){ //Old highest address block's end offset std::size_t 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<block_ctrl*> (reinterpret_cast<char*>(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<class MutexFamily, class VoidPointer>void simple_seq_fit_impl<MutexFamily, VoidPointer>::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 = detail::get_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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?