MemoryPool.h

Go to the documentation of this file.
00001 /*
00002  *
00003  *
00004  * Distributed under the OpenDDS License.
00005  * See: http://www.opendds.org/license.html
00006  */
00007 
00008 #ifndef OPENDDS_MEMORY_POOL_H
00009 #define OPENDDS_MEMORY_POOL_H
00010 
00011 #include "dcps_export.h"
00012 
00013 class MemoryPoolTest;
00014 class FreeIndexTest;
00015 
00016 namespace OpenDDS {
00017 namespace DCPS {
00018 
00019 /// Header of all allocations - found at beginning of allocation inside pool.
00020 /// Extra room must be added to each allocation for this header.
00021 class OpenDDS_Dcps_Export AllocHeader {
00022 public:
00023   /** Construct */
00024   AllocHeader();
00025 
00026   /** Get alloc size */
00027   unsigned int size() const { return is_free() ? -alloc_size_ : alloc_size_; }
00028   /** Get prev alloc size */
00029   unsigned int prev_size() const { return prev_size_; }
00030   /** Is this alloc free */
00031   bool is_free() const { return alloc_size_ < 0; }
00032 
00033   /** Get pointer to start of my buffer */
00034   unsigned char* ptr() const;
00035 
00036   /** Go to next header */
00037   AllocHeader* next_adjacent();
00038 
00039   /** Go to prev header */
00040   AllocHeader* prev_adjacent();
00041 
00042   /** Allocate from this block: change size, and mark as allocated */
00043   void allocate(size_t size);
00044 
00045   /** Set the size value stored in this header */
00046   void set_size(size_t size);
00047   /** Set the prev size value stored in this header */
00048   void set_prev_size(int size) { prev_size_ = size; }
00049   /** Mark this block as allocated */
00050   void set_allocated() { if (alloc_size_ < 0) alloc_size_ = - alloc_size_; }
00051 
00052   /** Join with the next adjacent block */
00053   void join_next();
00054 
00055 protected:
00056   /** Sizes are those of buffers, does not include size of headers */
00057   int alloc_size_; ///< Size of my buffer, negative if free, positive if alloc
00058   int prev_size_;  ///< Size of previous buffer, or 0 if first, never negative
00059 };
00060 
00061 /// Header of free allocations - found at beginning of allocation inside pool.
00062 /// This forces a minimum allocation size, so that, when freed, header can
00063 /// be cast to this type.
00064 class OpenDDS_Dcps_Export FreeHeader : public AllocHeader {
00065 public:
00066   /** Initialize the first AllocHeader with its size */
00067   void init_free_block(unsigned int pool_size);
00068 
00069   /** Mark as free */
00070   void set_free();
00071 
00072   /** Get next equal or smaller free block in size order */
00073   FreeHeader* smaller_free(unsigned char* pool_base) const;
00074   /** Get next equal or larger free block in size order */
00075   FreeHeader* larger_free(unsigned char* pool_base) const;
00076 
00077   /** Set the next equal or smaller free block in size order */
00078   void set_smaller_free(FreeHeader* next, unsigned char* pool_base);
00079   /** Set the next equal or larger free block in size order */
00080   void set_larger_free(FreeHeader* prev, unsigned char* pool_base);
00081 
00082 private:
00083   size_t offset_smaller_free_; ///< Offset to smaller free block in size order
00084   size_t offset_larger_free_;  ///< Offset to larger free block in size order
00085 };
00086 
00087 /// Node of free index.  Should point to smallest free block of the range
00088 /// from size (inclusive) to limit (non inclusive).  If multiple free
00089 /// allocations of the smallest size in range exist, should point to the one
00090 /// which is the "smallest" (in free list order).
00091 class FreeIndexNode {
00092 public:
00093   FreeIndexNode();
00094   /** Set the free alloc this node points to */
00095   void set_ptr(FreeHeader* ptr) { ptr_ = ptr; }
00096   /** Set the sizes for this node */
00097   void set_sizes(size_t size, size_t limit);
00098 
00099   /** Does this node contain a given size */
00100   bool contains(size_t size) { return ((size >= size_) && (size < limit_)); }
00101 
00102   /** Get this node's free block */
00103   FreeHeader* ptr() { return ptr_; }
00104   /** Get this node's minimum size */
00105   unsigned int size() const { return static_cast<unsigned int>(size_); }
00106 
00107 private:
00108   size_t size_;       ///< size of buffer
00109   size_t limit_;      ///< upper_limit of buffer size (one too large)
00110   FreeHeader* ptr_;   ///< points to smallest free alloc of size_ or larger
00111 };
00112 
00113 /// Index of free nodes in memory pool.
00114 /// Allows for a faster search of free nodes
00115 class OpenDDS_Dcps_Export FreeIndex {
00116   friend class ::MemoryPoolTest;
00117   friend class ::FreeIndexTest;
00118 public:
00119   explicit FreeIndex(FreeHeader*& largest_free);
00120   /** Initialize index with initial free block */
00121   void init(FreeHeader* init_free_block);
00122 
00123   /** Add free block to index */
00124   void add(FreeHeader* free_block);
00125   /** Remove free block from index */
00126   void remove(FreeHeader* free_block, FreeHeader* next_largest);
00127 
00128   /** Find smallest free block of size or larger */
00129   FreeHeader* find(size_t size, unsigned char* base);
00130 
00131   /** Calculate index of node corresponding to a size */
00132   static unsigned int node_index(size_t size);
00133 
00134 #ifdef VALIDATE_MEMORY_POOL
00135   static void validate_index(FreeIndex& index,
00136                              unsigned char* base,
00137                              bool log = false);
00138 #endif
00139 private:
00140   enum {
00141     min_index_pow = 3,
00142     max_index_pow = 12
00143   };
00144   enum {
00145     min_index = 8,    // 2^^3
00146     max_index = 4096  // 2^^12
00147   };
00148 
00149   size_t size_;               ///< Number of index nodes
00150   FreeHeader*& largest_free_; ///< Memory pool's pointer to largest free block
00151   FreeIndexNode nodes_[max_index_pow - min_index_pow + 1];   ///< Index nodes
00152 };
00153 
00154 // MemoryPool tracks free list, in size order (next meaning largest to smallest)
00155 // and an index into the list at various sizes, which point to the smallest
00156 // free allocation of that size or larger (but not larger than the next size).
00157 // Allocations can be done by checking the index for the needed size, and going
00158 // to the first free block.
00159 class OpenDDS_Dcps_Export MemoryPool {
00160   friend class ::MemoryPoolTest;
00161 public:
00162   explicit MemoryPool(unsigned int pool_size, size_t granularity = 8);
00163   ~MemoryPool();
00164 
00165   /** Does the pool include a given pointer */
00166   bool includes(void* ptr) const {
00167      return (pool_ptr_ <= ptr) && (ptr < pool_ptr_ + pool_size_); }
00168 
00169   /** Allocate size bytes from the pool **/
00170   void* pool_alloc(size_t size);
00171 
00172   /** Attempt to free an allocation.  Return true if allocation is managed by
00173       this pool (and thus was freed).
00174    */
00175   bool pool_free(void* ptr);
00176 
00177   /** Low water mark of maximum available bytes for an allocation */
00178   size_t lwm_free_bytes() const;
00179 
00180   /** Calculate aligned size of allocation */
00181   static size_t align(size_t size, size_t granularity) {
00182      return (size + granularity - 1) / granularity * granularity; }
00183 
00184   size_t size () const { return pool_size_; }
00185 
00186 private:
00187   const size_t granularity_;     ///< Configured granularity
00188   const size_t min_alloc_size_;  ///< Aligned minimum allocation size
00189   const size_t pool_size_;       ///< Configured pool size
00190   size_t lwm_free_bytes_;        ///< Low water mark of available bytes
00191   unsigned char* pool_ptr_;      ///< Pointer to pool
00192 
00193   FreeHeader* largest_free_;     ///< Pointer to largest free index
00194   FreeIndex free_index_;         ///< Index of free nodex
00195 
00196   enum {
00197     min_free_size = sizeof(FreeHeader)
00198   };
00199 
00200   // Helpers
00201   void remove_free_alloc(FreeHeader* block_to_alloc);
00202   void insert_free_alloc(FreeHeader* block_freed);
00203   void join_free_allocs(FreeHeader* block_freed);
00204   unsigned char* allocate(FreeHeader* free_block, size_t alloc_size);
00205 
00206   bool joinable_next(FreeHeader* freed);
00207   bool joinable_prev(FreeHeader* freed);
00208 
00209 #ifdef VALIDATE_MEMORY_POOL
00210   static void validate_pool(MemoryPool& pool, bool log = false);
00211 #endif
00212 };
00213 
00214 }} // end namespaces
00215 
00216 #endif // OPENDDS_MEMORY_POOL_H

Generated on Fri Feb 12 20:05:24 2016 for OpenDDS by  doxygen 1.4.7