LCOV - code coverage report
Current view: top level - DCPS - Cached_Allocator_With_Overflow_T.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 27 37 73.0 %
Date: 2023-04-30 01:32:43 Functions: 8 472 1.7 %

          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 */

Generated by: LCOV version 1.16