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

Generated on 10 Aug 2018 for OpenDDS by  doxygen 1.6.1