Line data Source code
1 : /* 2 : * 3 : * 4 : * Distributed under the OpenDDS License. 5 : * See: http://www.opendds.org/license.html 6 : */ 7 : 8 : #ifndef OPENDDS_DCPS_CACHED_ALLOCATOR_WITH_OVERFLOW_T_H 9 : #define OPENDDS_DCPS_CACHED_ALLOCATOR_WITH_OVERFLOW_T_H 10 : 11 : #include "debug.h" 12 : #include "SafetyProfilePool.h" 13 : #include "PoolAllocationBase.h" 14 : 15 : #include <ace/Atomic_Op.h> 16 : #include <ace/Free_List.h> 17 : #include <ace/Guard_T.h> 18 : #include <ace/Malloc_Allocator.h> 19 : #include <ace/Malloc_T.h> 20 : #include <ace/Message_Block.h> 21 : 22 : #if !defined (ACE_LACKS_PRAGMA_ONCE) 23 : # pragma once 24 : #endif /* ACE_LACKS_PRAGMA_ONCE */ 25 : 26 : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL 27 : 28 : namespace OpenDDS { 29 : namespace DCPS { 30 : 31 : /** 32 : * @class Cached_Allocator_With_Overflow 33 : * 34 : * @brief A fixed-size allocator that caches items for quicker access 35 : * but if the pool is exhausted it will use the heap. 36 : * 37 : * This class enables caching of dynamically allocated, 38 : * fixed-sized classes. Notice that the <code>sizeof (TYPE)</code> 39 : * must be greater than or equal to <code> sizeof (void*) </code> for 40 : * this to work properly. 41 : * If the free list is empty then memory is allocated from the heap. 42 : * This way the allocations will not fail but may be slower. 43 : * 44 : */ 45 : template <class T, class ACE_LOCK> 46 : class Cached_Allocator_With_Overflow : public ACE_New_Allocator, public PoolAllocationBase { 47 : public: 48 : /// Create a cached memory pool with @a n_chunks chunks 49 : /// each with sizeof (TYPE) size. 50 4 : explicit Cached_Allocator_With_Overflow(size_t n_chunks) 51 4 : : free_list_(ACE_PURE_FREE_LIST) 52 4 : , n_chunks_(n_chunks) 53 : { 54 : // To maintain alignment requirements, make sure that each element 55 : // inserted into the free list is aligned properly for the platform. 56 : // Since the memory is allocated as a char[], the compiler won't help. 57 : // To make sure enough room is allocated, round up the size so that 58 : // each element starts aligned. 59 : // 60 : // NOTE - this would probably be easier by defining begin_ as a pointer 61 : // to T and allocating an array of them (the compiler would probably 62 : // take care of the alignment for us), but then the ACE_NEW below would 63 : // require a default constructor on T - a requirement that is not in 64 : // previous versions of ACE 65 4 : size_t chunk_size = sizeof(T); 66 4 : chunk_size = ACE_MALLOC_ROUNDUP(chunk_size, ACE_MALLOC_ALIGN); 67 4 : begin_ = static_cast<unsigned char*> (ACE_Allocator::instance()->malloc(n_chunks * chunk_size)); 68 : 69 : // Remember end of the pool. 70 4 : end_ = begin_ + n_chunks * chunk_size; 71 : 72 : // Put into free list using placement contructor, no real memory 73 : // allocation in the <new> below. 74 4100 : for (size_t c = 0; c < n_chunks; c++) { 75 4096 : void* placement = begin_ + c * chunk_size; 76 4096 : this->free_list_.add(new(placement) ACE_Cached_Mem_Pool_Node<T>); 77 : } 78 4 : } 79 : 80 : /// Clear things up. 81 4 : ~Cached_Allocator_With_Overflow() 82 : { 83 4 : ACE_Allocator::instance()->free(begin_); 84 8 : } 85 : /** 86 : * Get a chunk of memory from free list cache. Note that @a nbytes is 87 : * only checked to make sure that it's less or equal to sizeof T, and is 88 : * otherwise ignored since @c malloc() always returns a pointer to an 89 : * item of sizeof (T). 90 : */ 91 6 : void* malloc(size_t nbytes = sizeof(T)) 92 : { 93 : // Check if size requested fits within pre-determined size. 94 6 : if (nbytes > sizeof(T)) 95 0 : return 0; 96 : 97 : // addr() call is really not absolutely necessary because of the way 98 : // ACE_Cached_Mem_Pool_Node's internal structure arranged. 99 6 : void* rtn = this->free_list_.remove()->addr(); 100 6 : if (0 == rtn) { 101 0 : return ACE_Allocator::instance()->malloc(sizeof(T)); 102 : } 103 : 104 6 : if (DCPS_debug_level >= 6 && this->available() % 512 == 0) { 105 0 : ACE_DEBUG((LM_DEBUG, "(%P|%t) Cached_Allocator_With_Overflow::malloc %@" 106 : " %Lu available from pool\n", this, this->available())); 107 : } 108 6 : return rtn; 109 : } 110 : 111 : /** 112 : * Get a chunk of memory from free list cache, giving them 113 : * @a initial_value. Note that @a nbytes is only checked to make sure 114 : * that it's less or equal to sizeof T, and is otherwise ignored since 115 : * calloc() always returns a pointer to an item of sizeof (T). 116 : */ 117 0 : virtual void *calloc(size_t /* nbytes */, 118 : char /* initial_value */ = '\0') 119 : { 120 0 : ACE_NOTSUP_RETURN(0); 121 : } 122 : 123 : /// This method is a no-op and just returns 0 since the free list 124 : /// only works with fixed sized entities. 125 0 : virtual void *calloc(size_t /* n_elem */, 126 : size_t /* elem_size */, 127 : char /* initial_value */ = '\0') 128 : { 129 0 : ACE_NOTSUP_RETURN(0); 130 : } 131 : 132 : /// Return a chunk of memory back to free list cache. 133 6 : void free(void* ptr) 134 : { 135 6 : unsigned char* tmp = static_cast<unsigned char*>(ptr); 136 : 137 6 : if (tmp < begin_ || tmp >= end_) { 138 0 : ACE_Allocator::instance()->free(tmp); 139 6 : } else if (ptr != 0) { 140 6 : this->free_list_.add((ACE_Cached_Mem_Pool_Node<T> *) ptr) ; 141 : 142 6 : if (DCPS_debug_level >= 6 && this->available() % 512 == 0) { 143 0 : ACE_DEBUG((LM_DEBUG, "(%P|%t) Cached_Allocator_With_Overflow::free %@" 144 : " %Lu available from pool\n", this, this->available())); 145 : } 146 : } 147 6 : } 148 : 149 : // -- for debug 150 : 151 : /** How many chunks are available at this time. 152 : */ 153 0 : size_t available() { return free_list_.size(); } 154 : 155 : size_t n_chunks() const { return n_chunks_; } 156 : 157 : private: 158 : /// Remember how we allocate the memory in the first place so 159 : /// we can clear things up later. 160 : unsigned char* begin_; 161 : /// The end of the pool. 162 : unsigned char* end_; 163 : 164 : /// Maintain a cached memory free list. 165 : ACE_Locked_Free_List<ACE_Cached_Mem_Pool_Node<T>, ACE_LOCK> free_list_; 166 : 167 : const size_t n_chunks_; 168 : }; 169 : 170 : typedef Cached_Allocator_With_Overflow<ACE_Message_Block, ACE_Thread_Mutex> MessageBlockAllocator; 171 : typedef Cached_Allocator_With_Overflow<ACE_Data_Block, ACE_Thread_Mutex> DataBlockAllocator; 172 : 173 : } // namespace DCPS 174 : } // namespace OpenDDS 175 : 176 : OPENDDS_END_VERSIONED_NAMESPACE_DECL 177 : 178 : #endif /* OPENDDS_DCPS_CACHED_ALLOCATOR_WITH_OVERFLOW_T_H */