OpenDDS  Snapshot(2023/04/28-20:55)
Cached_Allocator_With_Overflow_T.h
Go to the documentation of this file.
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 
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>
47 public:
48  /// Create a cached memory pool with @a n_chunks chunks
49  /// each with sizeof (TYPE) size.
52  , 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  size_t chunk_size = sizeof(T);
66  chunk_size = ACE_MALLOC_ROUNDUP(chunk_size, ACE_MALLOC_ALIGN);
67  begin_ = static_cast<unsigned char*> (ACE_Allocator::instance()->malloc(n_chunks * chunk_size));
68 
69  // Remember end of the pool.
70  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  for (size_t c = 0; c < n_chunks; c++) {
75  void* placement = begin_ + c * chunk_size;
76  this->free_list_.add(new(placement) ACE_Cached_Mem_Pool_Node<T>);
77  }
78  }
79 
80  /// Clear things up.
82  {
84  }
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  void* malloc(size_t nbytes = sizeof(T))
92  {
93  // Check if size requested fits within pre-determined size.
94  if (nbytes > sizeof(T))
95  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  void* rtn = this->free_list_.remove()->addr();
100  if (0 == rtn) {
101  return ACE_Allocator::instance()->malloc(sizeof(T));
102  }
103 
104  if (DCPS_debug_level >= 6 && this->available() % 512 == 0) {
105  ACE_DEBUG((LM_DEBUG, "(%P|%t) Cached_Allocator_With_Overflow::malloc %@"
106  " %Lu available from pool\n", this, this->available()));
107  }
108  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  virtual void *calloc(size_t /* nbytes */,
118  char /* initial_value */ = '\0')
119  {
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  virtual void *calloc(size_t /* n_elem */,
126  size_t /* elem_size */,
127  char /* initial_value */ = '\0')
128  {
130  }
131 
132  /// Return a chunk of memory back to free list cache.
133  void free(void* ptr)
134  {
135  unsigned char* tmp = static_cast<unsigned char*>(ptr);
136 
137  if (tmp < begin_ || tmp >= end_) {
139  } else if (ptr != 0) {
141 
142  if (DCPS_debug_level >= 6 && this->available() % 512 == 0) {
143  ACE_DEBUG((LM_DEBUG, "(%P|%t) Cached_Allocator_With_Overflow::free %@"
144  " %Lu available from pool\n", this, this->available()));
145  }
146  }
147  }
148 
149  // -- for debug
150 
151  /** How many chunks are available at this time.
152  */
153  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.
166 
167  const size_t n_chunks_;
168 };
169 
172 
173 } // namespace DCPS
174 } // namespace OpenDDS
175 
177 
178 #endif /* OPENDDS_DCPS_CACHED_ALLOCATOR_WITH_OVERFLOW_T_H */
#define ACE_MALLOC_ALIGN
#define ACE_DEBUG(X)
ACE_Locked_Free_List< ACE_Cached_Mem_Pool_Node< T >, ACE_LOCK > free_list_
Maintain a cached memory free list.
virtual ACE_Cached_Mem_Pool_Node< T > * remove(void)
#define ACE_MALLOC_ROUNDUP(X, Y)
virtual void free(void *ptr)=0
LM_DEBUG
A fixed-size allocator that caches items for quicker access but if the pool is exhausted it will use ...
void free(void *ptr)
Return a chunk of memory back to free list cache.
static ACE_Allocator * instance(void)
virtual void add(ACE_Cached_Mem_Pool_Node< T > *element)
Cached_Allocator_With_Overflow< ACE_Message_Block, ACE_Thread_Mutex > MessageBlockAllocator
OpenDDS_Dcps_Export unsigned int DCPS_debug_level
Definition: debug.cpp:30
#define OPENDDS_END_VERSIONED_NAMESPACE_DECL
The Internal API and Implementation of OpenDDS.
Definition: AddressCache.h:28
#define ACE_NOTSUP_RETURN(FAILVALUE)
#define ACE_PURE_FREE_LIST
Cached_Allocator_With_Overflow< ACE_Data_Block, ACE_Thread_Mutex > DataBlockAllocator
virtual void * malloc(size_type nbytes)=0