summaryrefslogtreecommitdiff
path: root/ace/Malloc_T.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ace/Malloc_T.cpp')
-rw-r--r--ace/Malloc_T.cpp574
1 files changed, 574 insertions, 0 deletions
diff --git a/ace/Malloc_T.cpp b/ace/Malloc_T.cpp
new file mode 100644
index 00000000000..52390601baa
--- /dev/null
+++ b/ace/Malloc_T.cpp
@@ -0,0 +1,574 @@
+// Malloc_T.cpp
+// $Id$
+
+#if !defined (ACE_MALLOC_T_C)
+#define ACE_MALLOC_T_C
+
+#define ACE_BUILD_DLL
+#include "ace/Malloc_T.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Malloc_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Malloc)
+
+template <class MALLOC>
+ACE_Allocator_Adapter<MALLOC>::ACE_Allocator_Adapter (const char *pool_name,
+ const char *lock_name)
+ : allocator_ (pool_name, lock_name)
+{
+ ACE_TRACE ("ACE_Allocator_Adapter<MALLOC>::ACE_Allocator_Adapter");
+}
+
+template <class MALLOC>
+ACE_Allocator_Adapter<MALLOC>::ACE_Allocator_Adapter (const char *pool_name)
+ : allocator_ (pool_name)
+{
+ ACE_TRACE ("ACE_Allocator_Adapter<MALLOC>::ACE_Allocator_Adapter");
+}
+
+template <class MALLOC> void
+ACE_Allocator_Adapter<MALLOC>::dump (void) const
+{
+ ACE_TRACE ("ACE_Malloc<MALLOC>::dump");
+ this->allocator_.dump ();
+}
+
+template <class MEM_POOL, class LOCK> void
+ACE_Malloc<MEM_POOL, LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->memory_pool_.dump ();
+ ACE_DEBUG ((LM_DEBUG, "cb_ptr_ = %x", this->cb_ptr_));
+ ACE_DEBUG ((LM_DEBUG, "\n"));
+#if defined (ACE_MALLOC_STATS)
+ this->malloc_stats_.dump ();
+#endif /* ACE_MALLOC_STATS */
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+#if defined (ACE_MALLOC_STATS)
+
+template <class MEM_POOL, class LOCK> void
+ACE_Malloc<MEM_POOL, LOCK>::print_stats (void)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::print_stats");
+ ACE_GUARD (LOCK, ace_mon, this->lock_);
+
+ this->cb_ptr_->malloc_stats_.print ();
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) contents of freelist:\n"));
+
+ for (ACE_Malloc_Header *currp = this->cb_ptr_->freep_->s_.next_block_;
+ ;
+ currp = currp->s_.next_block_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) ptr = %u, ACE_Malloc_Header units = %d, byte units = %d\n",
+ currp, currp->s_.size_,
+ currp->s_.size_ * sizeof (ACE_Malloc_Header)));
+ if (currp == this->cb_ptr_->freep_)
+ break;
+ }
+}
+#endif /* ACE_MALLOC_STATS */
+
+// Put block AP in the free list (locked version).
+
+template<class MEM_POOL, class LOCK> void
+ACE_Malloc<MEM_POOL, LOCK>::free (void *ap)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::free");
+ ACE_GUARD (LOCK, ace_mon, this->lock_);
+
+ this->shared_free (ap);
+}
+
+// This function is called by the ACE_Malloc constructor to initialize
+// the memory pool. The first time in it allocates room for the
+// control block (as well as a chunk of memory, depending on
+// rounding...). Depending on the type of <MEM_POOL> (i.e., shared
+// vs. local) subsequent calls from other processes will only
+// initialize the control block pointer.
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc<MEM_POOL, LOCK>::open (void)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::open");
+ ACE_GUARD_RETURN (LOCK, ace_mon, this->lock_, -1);
+
+ size_t rounded_bytes = 0;
+ int first_time = 0;
+
+ this->cb_ptr_ = (ACE_Control_Block *)
+ this->memory_pool_.init_acquire (sizeof *this->cb_ptr_,
+ rounded_bytes,
+ first_time);
+ if (this->cb_ptr_ == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p\n", "init_acquire failed"), -1);
+ else if (first_time)
+ {
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) first time in, control block = %u\n", this->cb_ptr_));
+
+#if defined (ACE_MALLOC_STATS)
+ // Call the constructor on the LOCK, using the placement
+ // operator!
+ new ((void *) &this->cb_ptr_->malloc_stats_) ACE_Malloc_Stats;
+#endif /* ACE_MALLOC_STATS */
+
+ // Initialize the freelist pointer to point to the dummy
+ // ACE_Malloc_Header.
+ this->cb_ptr_->freep_ = &this->cb_ptr_->base_;
+
+ // Initialize the dummy ACE_Malloc_Header to point to itself.
+ this->cb_ptr_->freep_->s_.size_ = 0;
+ this->cb_ptr_->freep_->s_.next_block_ = this->cb_ptr_->freep_;
+
+ // initialize the name list to 0
+ this->cb_ptr_->name_head_ = 0;
+
+
+ if (rounded_bytes > (sizeof *this->cb_ptr_ + sizeof (ACE_Malloc_Header)))
+ {
+ // If we've got any extra space at the end of the control
+ // block, then skip past the dummy ACE_Malloc_Header to
+ // point at the first free block.
+ ACE_Malloc_Header *p = this->cb_ptr_->freep_ + 1;
+ p->s_.size_ = (rounded_bytes - sizeof *this->cb_ptr_)
+ / sizeof (ACE_Malloc_Header);
+
+ AMS (++this->cb_ptr_->malloc_stats_.nchunks_);
+ AMS (++this->cb_ptr_->malloc_stats_.nblocks_);
+ AMS (++this->cb_ptr_->malloc_stats_.ninuse_);
+
+ // Insert the newly allocated chunk of memory into the free
+ // list.
+ this->shared_free ((void *) (p + 1));
+ }
+ }
+ return 0;
+}
+
+template <class MEM_POOL, class LOCK>
+ACE_Malloc<MEM_POOL, LOCK>::ACE_Malloc (const char *pool_name)
+ : memory_pool_ (pool_name),
+ lock_ (pool_name == 0 ? 0 : ACE::basename (pool_name,
+ ACE_DIRECTORY_SEPARATOR_CHAR))
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::ACE_Malloc");
+
+ this->open ();
+}
+
+template <class MEM_POOL, class LOCK>
+ACE_Malloc<MEM_POOL, LOCK>::ACE_Malloc (const char *pool_name,
+ const char *lock_name)
+ : memory_pool_ (pool_name),
+ lock_ (lock_name)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::ACE_Malloc");
+
+ this->open ();
+}
+
+// Clean up the resources allocated by ACE_Malloc.
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc<MEM_POOL, LOCK>::remove (void)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::remove");
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) destroying ACE_Malloc\n"));
+ int result = 0;
+
+#if defined (ACE_MALLOC_STATS)
+ this->print_stats ();
+#endif /* ACE_MALLOC_STATS */
+
+ // Remove the LOCK.
+ this->lock_.remove ();
+
+ // Give the memory pool a chance to release its resources.
+ result = this->memory_pool_.release ();
+
+ return result;
+}
+
+// General-purpose memory allocator. Assumes caller holds the locks.
+
+template <class MEM_POOL, class LOCK> void *
+ACE_Malloc<MEM_POOL, LOCK>::shared_malloc (size_t nbytes)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::shared_malloc");
+
+ // Round up request to a multiple of the ACE_Malloc_Header size.
+ size_t nunits = (nbytes + sizeof (ACE_Malloc_Header) - 1)
+ / sizeof (ACE_Malloc_Header) + 1;
+
+ // Begin the search starting at the place in the freelist
+ // where the last block was found.
+ ACE_Malloc_Header *prevp = this->cb_ptr_->freep_;
+ ACE_Malloc_Header *currp = prevp->s_.next_block_;
+
+ // Search the freelist to locate a block of the appropriate size.
+
+ for (int i = 0; ; i++, prevp = currp, currp = currp->s_.next_block_)
+ {
+ if (currp->s_.size_ >= nunits) // Big enough
+ {
+ AMS (++this->cb_ptr_->malloc_stats_.ninuse_);
+ if (currp->s_.size_ == nunits)
+ // Exact size, just update the pointers.
+ prevp->s_.next_block_ = currp->s_.next_block_;
+ else
+ {
+ // Remaining chunk is larger than requested block, so
+ // allocate at tail end.
+ AMS (++this->cb_ptr_->malloc_stats_.nblocks_);
+ currp->s_.size_ -= nunits;
+ currp += currp->s_.size_;
+ currp->s_.size_ = nunits;
+ }
+ this->cb_ptr_->freep_ = prevp;
+ // Skip over the ACE_Malloc_Header when returning pointer.
+ return (void *) (currp + 1);
+ }
+ else if (currp == this->cb_ptr_->freep_)
+ {
+ // We've wrapped around freelist without finding a block.
+ // Therefore, we need to ask the memory pool for a new chunk
+ // of bytes.
+
+ size_t chunk_bytes = 0;
+
+ if ((currp = (ACE_Malloc_Header *)
+ this->memory_pool_.acquire (nunits * sizeof (ACE_Malloc_Header),
+ chunk_bytes)) != 0)
+ {
+ AMS (++this->cb_ptr_->malloc_stats_.nblocks_);
+ AMS (++this->cb_ptr_->malloc_stats_.nchunks_);
+ AMS (++this->cb_ptr_->malloc_stats_.ninuse_);
+
+ // Compute the chunk size in ACE_Malloc_Header units.
+ currp->s_.size_ = chunk_bytes / sizeof (ACE_Malloc_Header);
+
+ // Insert the new chunk into the freelist.
+ this->shared_free ((void *) (currp + 1));
+ currp = this->cb_ptr_->freep_;
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p\n", "malloc"), 0);
+ }
+ }
+}
+
+// General-purpose memory allocator.
+
+template <class MEM_POOL, class LOCK> void *
+ACE_Malloc<MEM_POOL, LOCK>::malloc (size_t nbytes)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::malloc");
+ ACE_GUARD_RETURN (LOCK, ace_mon, this->lock_, 0);
+
+ return this->shared_malloc (nbytes);
+}
+
+// General-purpose memory allocator.
+
+template <class MEM_POOL, class LOCK> void *
+ACE_Malloc<MEM_POOL, LOCK>::calloc (size_t nbytes,
+ char initial_value)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::calloc");
+ void *ptr = this->malloc (nbytes);
+
+ if (ptr != 0)
+ ACE_OS::memset (ptr, initial_value, nbytes);
+
+ return ptr;
+}
+
+// Put block AP in the free list (must be called with locks held!)
+
+template <class MEM_POOL, class LOCK> void
+ACE_Malloc<MEM_POOL, LOCK>::shared_free (void *ap)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::shared_free");
+
+ if (ap == 0)
+ return;
+
+ ACE_Malloc_Header *blockp; // Points to the block ACE_Malloc_Header.
+ ACE_Malloc_Header *currp;
+
+ // Adjust AP to point to the block ACE_Malloc_Header
+ blockp = (ACE_Malloc_Header *) ap - 1;
+
+ // Search until we find the location where the blocks belongs. Note
+ // that addresses are kept in sorted order.
+
+ for (currp = this->cb_ptr_->freep_;
+ blockp <= currp || blockp >= currp->s_.next_block_;
+ currp = currp->s_.next_block_)
+ {
+ if (currp >= currp->s_.next_block_
+ && (blockp > currp || blockp < currp->s_.next_block_))
+ // Freed block at the start or the end of the memory pool
+ break;
+ }
+
+ // Join to upper neighbor
+ if (blockp + blockp->s_.size_ == currp->s_.next_block_)
+ {
+ AMS (--this->cb_ptr_->malloc_stats_.nblocks_);
+ blockp->s_.size_ += currp->s_.next_block_->s_.size_;
+ blockp->s_.next_block_ = currp->s_.next_block_->s_.next_block_;
+ }
+ else
+ blockp->s_.next_block_ = currp->s_.next_block_;
+
+ if (currp + currp->s_.size_ == blockp) // Join to lower neighbor
+ {
+ AMS (--this->cb_ptr_->malloc_stats_.nblocks_);
+ currp->s_.size_ += blockp->s_.size_;
+ currp->s_.next_block_ = blockp->s_.next_block_;
+ }
+ else
+ currp->s_.next_block_ = blockp;
+
+ AMS (--this->cb_ptr_->malloc_stats_.ninuse_);
+ this->cb_ptr_->freep_ = currp;
+}
+
+// No locks held here, caller must acquire/release lock.
+
+template <class MEM_POOL, class LOCK> ACE_Name_Node *
+ACE_Malloc<MEM_POOL, LOCK>::shared_find (const char *name)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::shared_find");
+
+ for (ACE_Name_Node *node = this->cb_ptr_->name_head_;
+ node != 0;
+ node = node->next_)
+ if (ACE_OS::strcmp (node->name_, name) == 0)
+ return node;
+
+ return 0;
+}
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc<MEM_POOL, LOCK>::shared_bind (const char *name,
+ void *pointer)
+{
+ // Combine the two allocations into one to avoid overhead...
+ ACE_Name_Node *new_node = (ACE_Name_Node *)
+ this->shared_malloc (sizeof (ACE_Name_Node) + ACE_OS::strlen (name) + 1);
+
+ if (new_node == 0)
+ return -1;
+
+ // This is a sleezy trick ;-)
+ new_node->name_ = (char *) (new_node + 1);
+
+ // Insert new node at the head of the list. Note that (new_node) is
+ // *not* a cast!
+ ACE_NEW_RETURN (this->cb_ptr_->name_head_,
+ (new_node) ACE_Name_Node (name, pointer,
+ this->cb_ptr_->name_head_),
+ -1);
+ return 0;
+}
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc<MEM_POOL, LOCK>::trybind (const char *name,
+ void *&pointer)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::trybind");
+ ACE_Write_Guard<LOCK> mon (this->lock_);
+
+ ACE_Name_Node *node = this->shared_find (name);
+ if (node == 0)
+ // Didn't find it, so insert it.
+ return this->shared_bind (name, pointer);
+ else
+ {
+ // Found it, so return a copy of the current entry.
+ pointer = node->pointer_;
+ return 1;
+ }
+}
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc<MEM_POOL, LOCK>::bind (const char *name,
+ void *pointer,
+ int duplicates)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::bind");
+ ACE_Write_Guard<LOCK> mon (this->lock_);
+
+ if (duplicates == 0 && this->shared_find (name) != 0)
+ // If we're not allowing duplicates, then if the name is already
+ // present, return 1.
+ return 1;
+ else
+ // If we get this far, either we're allowing duplicates or we didn't
+ // find the name yet.
+
+ return this->shared_bind (name, pointer);
+}
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc<MEM_POOL, LOCK>::find (const char *name, void *&pointer)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::find");
+
+ ACE_Read_Guard<LOCK> mon (this->lock_);
+
+ ACE_Name_Node *node = this->shared_find (name);
+
+ if (node == 0)
+ return -1;
+ else
+ {
+ pointer = node->pointer_;
+ return 0;
+ }
+}
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc<MEM_POOL, LOCK>::find (const char *name)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::find");
+
+ ACE_Read_Guard<LOCK> mon (this->lock_);
+ return this->shared_find (name) == 0 ? -1 : 0;
+}
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc<MEM_POOL, LOCK>::unbind (const char *name, void *&pointer)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::unbind");
+
+ ACE_Write_Guard<LOCK> mon (this->lock_);
+ ACE_Name_Node *prev = 0;
+
+ for (ACE_Name_Node *curr = this->cb_ptr_->name_head_;
+ curr != 0;
+ curr = curr->next_)
+ {
+ if (ACE_OS::strcmp (curr->name_, name) == 0)
+ {
+ pointer = curr->pointer_;
+
+ if (prev == 0)
+ this->cb_ptr_->name_head_ = curr->next_;
+ else
+ prev->next_ = curr->next_;
+
+ // This will free up both the node and the name due to our
+ // sleezy trick in bind()!
+ this->shared_free (curr);
+ return 0;
+ }
+ prev = curr;
+ }
+
+ // Didn't find it, so fail.
+ return -1;
+}
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc<MEM_POOL, LOCK>::unbind (const char *name)
+{
+ ACE_TRACE ("ACE_Malloc<MEM_POOL, LOCK>::unbind");
+ void *temp = 0;
+ return this->unbind (name, temp);
+}
+
+
+template <class MEM_POOL, class LOCK> void
+ACE_Malloc_Iterator<MEM_POOL, LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_Malloc_Iterator<MEM_POOL, LOCK>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->curr_->dump ();
+ this->guard_.dump ();
+ ACE_DEBUG ((LM_DEBUG, "name_ = %s", this->name_));
+ ACE_DEBUG ((LM_DEBUG, "\n"));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class MEM_POOL, class LOCK>
+ACE_Malloc_Iterator<MEM_POOL, LOCK>::ACE_Malloc_Iterator (ACE_Malloc<MEM_POOL, LOCK> &malloc,
+ const char *name)
+ : malloc_ (malloc),
+ guard_ (malloc_.lock_),
+ curr_ (0),
+ name_ (name != 0 ? ACE_OS::strdup (name) : 0)
+{
+ ACE_TRACE ("ACE_Malloc_Iterator<MEM_POOL, LOCK>::ACE_Malloc_Iterator");
+ // Cheap trick to make code simple.
+ ACE_Name_Node temp;
+ this->curr_ = &temp;
+ this->curr_->next_ = malloc_.cb_ptr_->name_head_;
+
+ this->advance();
+}
+
+template <class MEM_POOL, class LOCK>
+ACE_Malloc_Iterator<MEM_POOL, LOCK>::~ACE_Malloc_Iterator (void)
+{
+ ACE_OS::free ((void *) this->name_);
+}
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc_Iterator<MEM_POOL, LOCK>::next (void *&next_entry,
+ char *&name)
+{
+ ACE_TRACE ("ACE_Malloc_Iterator<MEM_POOL, LOCK>::next");
+
+ if (curr_ != 0)
+ {
+ next_entry = curr_->pointer_;
+ name = curr_->name_;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc_Iterator<MEM_POOL, LOCK>::next (void *&next_entry)
+{
+ ACE_TRACE ("ACE_Malloc_Iterator<MEM_POOL, LOCK>::next");
+
+ if (curr_ != 0)
+ {
+ next_entry = curr_->pointer_;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+template <class MEM_POOL, class LOCK> int
+ACE_Malloc_Iterator<MEM_POOL, LOCK>::advance (void)
+{
+ ACE_TRACE ("ACE_Malloc_Iterator<MEM_POOL, LOCK>::advance");
+
+ this->curr_ = this->curr_->next_;
+
+ if (this->name_ == 0)
+ return 1;
+
+ for (;
+ this->curr_ != 0 &&
+ ACE_OS::strcmp (this->name_, this->curr_->name_) != 0;
+ this->curr_ = this->curr_->next_)
+ continue;
+ return 1;
+}
+
+#endif /* ACE_MALLOC_T_C */