multi_simple_seq_fit_impl.hpp
来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 972 行 · 第 1/3 页
HPP
972 行
////////////////////////////////////////////////////////////////////////////////// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost// Software License, Version 1.0. (See accompanying file// LICENSE_1_0.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/multi_segment_services.hpp>#include <boost/type_traits/alignment_of.hpp>#include <boost/type_traits/type_with_alignment.hpp>#include <boost/interprocess/sync/scoped_lock.hpp>#include <algorithm>#include <utility>#include <cstring>#include <assert.h>#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; private: struct block_ctrl; typedef typename detail:: pointer_to_other<void_pointer, block_ctrl>::type block_ctrl_ptr; /*!Block control structure*/ struct block_ctrl { /*!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; } static block_ctrl *get_block_from_addr(void *addr) { return reinterpret_cast<block_ctrl*> (reinterpret_cast<char*>(addr) - BlockCtrlBytes); } void *get_addr() const { return reinterpret_cast<block_ctrl*> (reinterpret_cast<const char*>(this) + BlockCtrlBytes); } }; /*!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; } m_header; 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); /*!Deallocates previously allocated bytes*/ void deallocate (void *addr); /*!Returns the size of the memory segment*/ std::size_t get_size() const; /*!Increases managed memory in extra_size bytes more*/ void grow(std::size_t extra_size); /*!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 clear_free_memory(); std::pair<void *, bool> 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 backwards_multiple = 1); /*!Returns the size of the buffer previously allocated pointed by ptr*/ std::size_t size(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); /*!Allocates bytes, if there is no more memory, it executes functor f(std::size_t) to allocate a new segment to manage. The functor returns std::pair<void*, std::size_t> indicating the base address and size of the new segment. If the new segment can't be allocated, allocate it will return 0.*/ void* multi_allocate(std::size_t nbytes); private: /*!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); /*!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); /*!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 shrink function implementation*/ bool priv_shrink(void *ptr ,std::size_t max_size, std::size_t preferred_size ,std::size_t &received_size); //!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); enum { Alignment = boost::alignment_of<boost::detail::max_align>::value }; enum { BlockCtrlBytes = detail::ct_rounded_size<sizeof(block_ctrl), Alignment>::value }; enum { BlockCtrlSize = BlockCtrlBytes/Alignment }; enum { MinBlockSize = BlockCtrlSize + Alignment }; public: enum { PayloadPerAllocation = BlockCtrlBytes };};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; //Initialize pointers std::size_t block1_off = detail::get_rounded_size(sizeof(*this)+extra_hdr_bytes, Alignment); m_header.m_root.m_next = reinterpret_cast<block_ctrl*> (reinterpret_cast<char*>(this) + block1_off); 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 = m_header.m_size/Alignment*Alignment; //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); 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(reinterpret_cast<char*>(new_block) + BlockCtrlBytes);}template<class MutexFamily, class VoidPointer>inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_add_segment(void *addr, std::size_t size){ //Check size assert(!(size < MinBlockSize)); if(size < MinBlockSize) return; //Construct big block using the new segment block_ctrl *new_block = static_cast<block_ctrl *>(addr); new_block->m_size = 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(reinterpret_cast<char*>(new_block) + BlockCtrlBytes);}template<class MutexFamily, class VoidPointer>inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::get_size() const { return m_header.m_size; }template<class MutexFamily, class VoidPointer>inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>:: get_min_size (std::size_t extra_hdr_bytes){ return detail::get_rounded_size(sizeof(simple_seq_fit_impl)+extra_hdr_bytes ,Alignment) + MinBlockSize;}template<class MutexFamily, class VoidPointer>inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>:: all_memory_deallocated(){ //----------------------- boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header); //----------------------- return m_header.m_allocated == 0 && detail::get_pointer(m_header.m_root.m_next->m_next) == &m_header.m_root;}template<class MutexFamily, class VoidPointer>inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::clear_free_memory(){ //----------------------- boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header); //----------------------- block_ctrl *block = detail::get_pointer(m_header.m_root.m_next); //Iterate through all free portions
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?