diff options
Diffstat (limited to 'ace/Malloc_T.cpp')
-rw-r--r-- | ace/Malloc_T.cpp | 574 |
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 */ |