#ifndef ACE_MALLOC_T_CPP #define ACE_MALLOC_T_CPP #include "ace/Malloc_T.h" #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ #if !defined (__ACE_INLINE__) #include "ace/Malloc_T.inl" #endif /* __ACE_INLINE__ */ #include "ace/ACE.h" #include "ace/OS_NS_string.h" ACE_BEGIN_VERSIONED_NAMESPACE_DECL template ACE_Cached_Allocator::ACE_Cached_Allocator (size_t n_chunks) : pool_ (0), free_list_ (ACE_PURE_FREE_LIST) { // To maintain alignment requirements, make sure that each element // inserted into the free list is aligned properly for the platform. // Since the memory is allocated as a char[], the compiler won't help. // To make sure enough room is allocated, round up the size so that // each element starts aligned. // // NOTE - this would probably be easier by defining pool_ as a pointer // to T and allocating an array of them (the compiler would probably // take care of the alignment for us), but then the ACE_NEW below would // require a default constructor on T - a requirement that is not in // previous versions of ACE size_t chunk_size = sizeof (T); chunk_size = ACE_MALLOC_ROUNDUP (chunk_size, ACE_MALLOC_ALIGN); #if defined (ACE_HAS_ALLOC_HOOKS) ACE_ALLOCATOR (this->pool_, static_cast(ACE_Allocator::instance()->malloc(sizeof(char) * n_chunks * chunk_size))); #else ACE_NEW (this->pool_, char[n_chunks * chunk_size]); #endif /* ACE_HAS_ALLOC_HOOKS */ for (size_t c = 0; c < n_chunks; c++) { void* placement = this->pool_ + c * chunk_size; this->free_list_.add (new (placement) ACE_Cached_Mem_Pool_Node); } // Put into free list using placement constructor, no real memory // allocation in the above . } template ACE_Cached_Allocator::~ACE_Cached_Allocator () { #if defined (ACE_HAS_ALLOC_HOOKS) ACE_Allocator::instance()->free (this->pool_); #else delete [] this->pool_; #endif /* ACE_HAS_ALLOC_HOOKS */ } ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_Cached_Allocator) template void * ACE_Cached_Allocator::malloc (size_t nbytes) { // Check if size requested fits within pre-determined size. if (nbytes > sizeof (T)) return 0; ACE_Cached_Mem_Pool_Node *allocated = this->free_list_.remove (); return allocated == 0 ? 0 : allocated->addr(); } template void * ACE_Cached_Allocator::calloc (size_t nbytes, char initial_value) { // Check if size requested fits within pre-determined size. if (nbytes > sizeof (T)) return 0; ACE_Cached_Mem_Pool_Node *allocated = this->free_list_.remove (); void *ptr = allocated == 0 ? 0 : allocated->addr(); if (ptr != 0) ACE_OS::memset (ptr, initial_value, sizeof (T)); return ptr; } template void * ACE_Cached_Allocator::calloc (size_t, size_t, char) { ACE_NOTSUP_RETURN (0); } template void ACE_Cached_Allocator::free (void * ptr) { if (ptr != 0) this->free_list_.add ((ACE_Cached_Mem_Pool_Node *) ptr) ; } template ACE_Dynamic_Cached_Allocator::ACE_Dynamic_Cached_Allocator (size_t n_chunks, size_t chunk_size) : pool_ (0), free_list_ (ACE_PURE_FREE_LIST), chunk_size_ (chunk_size) { ACE_ASSERT (chunk_size > 0); chunk_size = ACE_MALLOC_ROUNDUP (chunk_size, ACE_MALLOC_ALIGN); ACE_NEW (this->pool_, char[n_chunks * chunk_size]); for (size_t c = 0; c < n_chunks; c++) { void *placement = this->pool_ + c * chunk_size; this->free_list_.add (new (placement) ACE_Cached_Mem_Pool_Node); } // Put into free list using placement constructor, no real memory // allocation in the above . } template ACE_Dynamic_Cached_Allocator::~ACE_Dynamic_Cached_Allocator () { delete [] this->pool_; this->pool_ = 0; chunk_size_ = 0; } template void * ACE_Dynamic_Cached_Allocator::malloc (size_t nbytes) { // Check if size requested fits within pre-determined size. if (nbytes > chunk_size_) return 0; ACE_Cached_Mem_Pool_Node *allocated = this->free_list_.remove (); return allocated == 0 ? 0 : allocated->addr(); } template void * ACE_Dynamic_Cached_Allocator::calloc (size_t nbytes, char initial_value) { // Check if size requested fits within pre-determined size. if (nbytes > chunk_size_) return 0; ACE_Cached_Mem_Pool_Node *allocated = this->free_list_.remove (); void *ptr = allocated == 0 ? 0 : allocated->addr(); if (ptr != 0) ACE_OS::memset (ptr, initial_value, chunk_size_); return ptr; } template void * ACE_Dynamic_Cached_Allocator::calloc (size_t, size_t, char) { ACE_NOTSUP_RETURN (0); } template void ACE_Dynamic_Cached_Allocator::free (void * ptr) { if (ptr != 0) this->free_list_.add ((ACE_Cached_Mem_Pool_Node *) ptr); } ACE_ALLOC_HOOK_DEFINE_Tmcc (ACE_Malloc_T) template void * ACE_Allocator_Adapter::malloc (size_t nbytes) { ACE_TRACE ("ACE_Allocator_Adapter::malloc"); return this->allocator_.malloc (nbytes); } template void * ACE_Allocator_Adapter::calloc (size_t nbytes, char initial_value) { ACE_TRACE ("ACE_Allocator_Adapter::calloc"); return this->allocator_.calloc (nbytes, initial_value); } template void * ACE_Allocator_Adapter::calloc (size_t n_elem, size_t elem_size, char initial_value) { ACE_TRACE ("ACE_Allocator_Adapter::calloc"); return this->allocator_.calloc (n_elem, elem_size, initial_value); } template MALLOC & ACE_Allocator_Adapter::alloc () { ACE_TRACE ("ACE_Allocator_Adapter::allocator"); return this->allocator_; } template void ACE_Allocator_Adapter::free (void *ptr) { ACE_TRACE ("ACE_Allocator_Adapter::free"); this->allocator_.free (ptr); } template int ACE_Allocator_Adapter::remove () { ACE_TRACE ("ACE_Allocator_Adapter::remove"); return this->allocator_.remove (); } template int ACE_Allocator_Adapter::trybind (const char *name, void *&pointer) { ACE_TRACE ("ACE_Allocator_Adapter::trybind"); return this->allocator_.trybind (name, pointer); } template int ACE_Allocator_Adapter::bind (const char *name, void *pointer, int duplicates) { ACE_TRACE ("ACE_Allocator_Adapter::bind"); return this->allocator_.bind (name, pointer, duplicates); } template int ACE_Allocator_Adapter::find (const char *name, void *&pointer) { ACE_TRACE ("ACE_Allocator_Adapter::find"); return this->allocator_.find (name, pointer); } template int ACE_Allocator_Adapter::find (const char *name) { ACE_TRACE ("ACE_Allocator_Adapter::find"); return this->allocator_.find (name); } template int ACE_Allocator_Adapter::unbind (const char *name, void *&pointer) { ACE_TRACE ("ACE_Allocator_Adapter::unbind"); return this->allocator_.unbind (name, pointer); } template int ACE_Allocator_Adapter::unbind (const char *name) { ACE_TRACE ("ACE_Allocator_Adapter::unbind"); return this->allocator_.unbind (name); } template int ACE_Allocator_Adapter::sync (ssize_t len, int flags) { ACE_TRACE ("ACE_Allocator_Adapter::sync"); return this->allocator_.sync (len, flags); } template int ACE_Allocator_Adapter::sync (void *addr, size_t len, int flags) { ACE_TRACE ("ACE_Allocator_Adapter::sync"); return this->allocator_.sync (addr, len, flags); } template int ACE_Allocator_Adapter::protect (ssize_t len, int flags) { ACE_TRACE ("ACE_Allocator_Adapter::protect"); return this->allocator_.protect (len, flags); } template int ACE_Allocator_Adapter::protect (void *addr, size_t len, int flags) { ACE_TRACE ("ACE_Allocator_Adapter::protect"); return this->allocator_.protect (addr, len, flags); } template ACE_Allocator_Adapter::ACE_Allocator_Adapter (const char *pool_name) : allocator_ (ACE_TEXT_CHAR_TO_TCHAR (pool_name)) { ACE_TRACE ("ACE_Allocator_Adapter::ACE_Allocator_Adapter"); } template ACE_Allocator_Adapter::ACE_Allocator_Adapter ( const char *pool_name, const char *lock_name, MEMORY_POOL_OPTIONS options) : allocator_ (ACE_TEXT_CHAR_TO_TCHAR (pool_name), ACE_TEXT_CHAR_TO_TCHAR (lock_name), options) { ACE_TRACE ("ACE_Allocator_Adapter::ACE_Allocator_Adapter"); } #if defined (ACE_HAS_WCHAR) template ACE_Allocator_Adapter::ACE_Allocator_Adapter (const wchar_t *pool_name) : allocator_ (ACE_TEXT_WCHAR_TO_TCHAR (pool_name)) { ACE_TRACE ("ACE_Allocator_Adapter::ACE_Allocator_Adapter"); } template ACE_Allocator_Adapter::ACE_Allocator_Adapter ( const wchar_t *pool_name, const wchar_t *lock_name, MEMORY_POOL_OPTIONS options) : allocator_ (ACE_TEXT_WCHAR_TO_TCHAR (pool_name), ACE_TEXT_WCHAR_TO_TCHAR (lock_name), options) { ACE_TRACE ("ACE_Allocator_Adapter::ACE_Allocator_Adapter"); } #endif /* ACE_HAS_WCHAR */ template ACE_Allocator_Adapter::~ACE_Allocator_Adapter () { ACE_TRACE ("ACE_Allocator_Adapter::~ACE_Allocator_Adapter"); } #if defined (ACE_HAS_MALLOC_STATS) template void ACE_Allocator_Adapter::print_stats () const { ACE_TRACE ("ACE_Allocator_Adapter::print_stats"); this->allocator_.print_stats (); } #endif /* ACE_HAS_MALLOC_STATS */ template void ACE_Allocator_Adapter::dump () const { #if defined (ACE_HAS_DUMP) ACE_TRACE ("ACE_Allocator_Adapter::dump"); this->allocator_.dump (); #endif /* ACE_HAS_DUMP */ } ACE_ALLOC_HOOK_DEFINE_Tt(ACE_Allocator_Adapter) template void ACE_Malloc_T::dump () const { #if defined (ACE_HAS_DUMP) ACE_TRACE ("ACE_Malloc_T::dump"); ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); this->memory_pool_.dump (); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("cb_ptr_ = %@\n"), this->cb_ptr_)); this->cb_ptr_->dump (); #if defined (ACE_HAS_MALLOC_STATS) if (this->cb_ptr_ != 0) this->cb_ptr_->malloc_stats_.dump (); #endif /* ACE_HAS_MALLOC_STATS */ ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* ACE_HAS_DUMP */ } #if defined (ACE_HAS_MALLOC_STATS) template void ACE_Malloc_T::print_stats () const { ACE_TRACE ("ACE_Malloc_T::print_stats"); ACE_GUARD (ACE_LOCK, ace_mon, *this->lock_); if (this->cb_ptr_ == 0) return; this->cb_ptr_->malloc_stats_.dump (); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) contents of freelist:\n"))); for (MALLOC_HEADER *currp = this->cb_ptr_->freep_->next_block_; ; currp = currp->next_block_) { ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) ptr = %@, MALLOC_HEADER units = %d, byte units = %d\n"), currp, currp->size_, currp->size_ * sizeof (MALLOC_HEADER))); if (currp == this->cb_ptr_->freep_) break; } } #endif /* ACE_HAS_MALLOC_STATS */ // Put in the free list (locked version). template void ACE_Malloc_T::free (void *ptr) { ACE_TRACE ("ACE_Malloc_T::free"); ACE_GUARD (ACE_LOCK, ace_mon, *this->lock_); this->shared_free (ptr); } // This function is called by the ACE_Malloc_T 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 (i.e., shared // vs. local) subsequent calls from other processes will only // initialize the control block pointer. template int ACE_Malloc_T::open () { ACE_TRACE ("ACE_Malloc_T::open"); ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *this->lock_, -1); size_t rounded_bytes = 0; int first_time = 0; this->cb_ptr_ = (ACE_CB *) this->memory_pool_.init_acquire (sizeof *this->cb_ptr_, rounded_bytes, first_time); if (this->cb_ptr_ == 0) ACELIB_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("init_acquire failed")), -1); else if (first_time) { // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) first time in, control block = %@\n"), this->cb_ptr_)); MALLOC_HEADER::init_ptr (&this->cb_ptr_->freep_, &this->cb_ptr_->base_, this->cb_ptr_); MALLOC_HEADER::init_ptr (&this->cb_ptr_->freep_->next_block_, this->cb_ptr_->freep_, this->cb_ptr_); NAME_NODE::init_ptr (&this->cb_ptr_->name_head_, 0, this->cb_ptr_); this->cb_ptr_->freep_->size_ = 0; this->cb_ptr_->ref_counter_ = 1; if (rounded_bytes > (sizeof *this->cb_ptr_ + sizeof (MALLOC_HEADER))) { // If we've got any extra space at the end of the control // block, then skip past the dummy to // point at the first free block. MALLOC_HEADER *p = ((MALLOC_HEADER *) (this->cb_ptr_->freep_)) + 1; MALLOC_HEADER::init_ptr (&p->next_block_, 0, this->cb_ptr_); p->size_ = (rounded_bytes - sizeof *this->cb_ptr_) / sizeof (MALLOC_HEADER); ACE_MALLOC_STATS (++this->cb_ptr_->malloc_stats_.nchunks_); ACE_MALLOC_STATS (++this->cb_ptr_->malloc_stats_.nblocks_); ACE_MALLOC_STATS (++this->cb_ptr_->malloc_stats_.ninuse_); // Insert the newly allocated chunk of memory into the free // list. Add "1" to skip over the when // freeing the pointer. this->shared_free (p + 1); } } else ++this->cb_ptr_->ref_counter_; return 0; } template ACE_Malloc_T::ACE_Malloc_T (const ACE_TCHAR *pool_name) : cb_ptr_ (0), memory_pool_ (pool_name), bad_flag_ (0) { ACE_TRACE ("ACE_Malloc_T::ACE_Malloc_T"); this->lock_ = ACE_Malloc_Lock_Adapter_T ()(pool_name); if (this->lock_ != 0) { this->delete_lock_ = true; this->bad_flag_ = this->open (); if (this->bad_flag_ == -1) ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_Malloc_T::ACE_Malloc_T"))); } } template ACE_Malloc_T::ACE_Malloc_T (const ACE_TCHAR *pool_name, const ACE_TCHAR *lock_name, const ACE_MEM_POOL_OPTIONS *options) : cb_ptr_ (0), memory_pool_ (pool_name, options), bad_flag_ (0) { ACE_TRACE ("ACE_Malloc_T::ACE_Malloc_T"); // Use pool_name for lock_name if lock_name not passed. const ACE_TCHAR *name = lock_name ? lock_name : pool_name; this->lock_ = ACE_Malloc_Lock_Adapter_T ()(name); if (this->lock_ != 0) { this->delete_lock_ = true; this->bad_flag_ = this->open (); if (this->bad_flag_ == -1) ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_Malloc_T::ACE_Malloc_T"))); } } template ACE_Malloc_T::ACE_Malloc_T (const ACE_TCHAR *pool_name, const ACE_MEM_POOL_OPTIONS *options, ACE_LOCK *lock) : cb_ptr_ (0), memory_pool_ (pool_name, options), lock_ (lock), delete_lock_ (false), bad_flag_ (0) { ACE_TRACE ("ACE_Malloc_T::ACE_Malloc_T"); if (lock == 0) { this->bad_flag_ = -1; errno = EINVAL; return; } this->bad_flag_ = this->open (); if (this->bad_flag_ == -1) ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_Malloc_T::ACE_Malloc_T"))); } template ACE_Malloc_T::~ACE_Malloc_T () { ACE_TRACE ("ACE_Malloc_T::~ACE_Malloc_T"); if (this->delete_lock_) { delete this->lock_; this->lock_ = 0; } } // Clean up the resources allocated by ACE_Malloc_T. template int ACE_Malloc_T::remove () { ACE_TRACE ("ACE_Malloc_T::remove"); // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) destroying ACE_Malloc_T\n"))); #if defined (ACE_HAS_MALLOC_STATS) this->print_stats (); #endif /* ACE_HAS_MALLOC_STATS */ // Remove the ACE_LOCK. if (this->delete_lock_) this->lock_->remove (); // Give the memory pool a chance to release its resources. int const result = this->memory_pool_.release (); // Reset this->cb_ptr_ as it is no longer valid. // There's also no need to keep the reference counter as the // underlying memory pool has been destroyed. // Also notice that we are leaving the decision of removing // the pool to users so they can map to the same mmap file // again. this->cb_ptr_ = 0; return result; } // General-purpose memory allocator. Assumes caller holds the locks. template void * ACE_Malloc_T::shared_malloc (size_t nbytes) { #if !defined (ACE_HAS_WIN32_STRUCTURED_EXCEPTIONS) ACE_TRACE ("ACE_Malloc_T::shared_malloc"); #endif /* !ACE_HAS_WIN32_STRUCTURED_EXCEPTIONS */ if (this->cb_ptr_ == 0) return 0; // Round up request to a multiple of the MALLOC_HEADER size. size_t const nunits = (nbytes + sizeof (MALLOC_HEADER) - 1) / sizeof (MALLOC_HEADER) + 1; // Add one for the itself. MALLOC_HEADER *prevp = 0; MALLOC_HEADER *currp = 0; ACE_SEH_TRY { // Begin the search starting at the place in the freelist where the // last block was found. prevp = this->cb_ptr_->freep_; currp = prevp->next_block_; } #if defined (ACE_HAS_WIN32_STRUCTURED_EXCEPTIONS) ACE_SEH_EXCEPT (this->memory_pool_.seh_selector (GetExceptionInformation ())) { currp = prevp->next_block_; } #endif /* ACE_HAS_WIN32_STRUCTURED_EXCEPTIONS */ // Search the freelist to locate a block of the appropriate size. while (1) // *Warning* Do not use "continue" within this while-loop. { ACE_SEH_TRY { if (currp->size_ >= nunits) // Big enough { ACE_MALLOC_STATS (++this->cb_ptr_->malloc_stats_.ninuse_); if (currp->size_ == nunits) // Exact size, just update the pointers. prevp->next_block_ = currp->next_block_; else { // Remaining chunk is larger than requested block, so // allocate at tail end. ACE_MALLOC_STATS (++this->cb_ptr_->malloc_stats_.nblocks_); currp->size_ -= nunits; currp += currp->size_; MALLOC_HEADER::init_ptr (&currp->next_block_, 0, this->cb_ptr_); currp->size_ = nunits; } this->cb_ptr_->freep_ = prevp; // Skip over the MALLOC_HEADER when returning pointer. return currp + 1; } else if (currp == static_cast (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; currp = (MALLOC_HEADER *) this->memory_pool_.acquire (nunits * sizeof (MALLOC_HEADER), chunk_bytes); void *remap_addr = this->memory_pool_.base_addr (); if (remap_addr != 0) this->cb_ptr_ = (ACE_CB *) remap_addr; if (currp != 0) { ACE_MALLOC_STATS (++this->cb_ptr_->malloc_stats_.nblocks_); ACE_MALLOC_STATS (++this->cb_ptr_->malloc_stats_.nchunks_); ACE_MALLOC_STATS (++this->cb_ptr_->malloc_stats_.ninuse_); MALLOC_HEADER::init_ptr (&currp->next_block_, 0, this->cb_ptr_); // Compute the chunk size in MALLOC_HEADER units. currp->size_ = chunk_bytes / sizeof (MALLOC_HEADER); // Insert the newly allocated chunk of memory into the // free list. Add "1" to skip over the // when freeing the pointer since // the first thing does is decrement by this // amount. this->shared_free (currp + 1); currp = this->cb_ptr_->freep_; } else return 0; // Shouldn't do this here because of errors with the wchar ver // This is because ACELIB_ERROR_RETURN converts the __FILE__ to // wchar before printing out. The compiler will complain // about this since a destructor would present in a SEH block //ACELIB_ERROR_RETURN ((LM_ERROR, // ACE_TEXT ("(%P|%t) %p\n"), // ACE_TEXT ("malloc")), // 0); } prevp = currp; currp = currp->next_block_; } ACE_SEH_EXCEPT (this->memory_pool_.seh_selector (GetExceptionInformation ())) { } } ACE_NOTREACHED (return 0;) } // General-purpose memory allocator. template void * ACE_Malloc_T::malloc (size_t nbytes) { ACE_TRACE ("ACE_Malloc_T::malloc"); ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *this->lock_, 0); return this->shared_malloc (nbytes); } // General-purpose memory allocator. template void * ACE_Malloc_T::calloc (size_t nbytes, char initial_value) { ACE_TRACE ("ACE_Malloc_T::calloc"); void *ptr = this->malloc (nbytes); if (ptr != 0) ACE_OS::memset (ptr, initial_value, nbytes); return ptr; } template void * ACE_Malloc_T::calloc (size_t n_elem, size_t elem_size, char initial_value) { ACE_TRACE ("ACE_Malloc_T::calloc"); return this->calloc (n_elem * elem_size, initial_value); } // Put block AP in the free list (must be called with locks held!) template void ACE_Malloc_T::shared_free (void *ap) { #if !defined (ACE_HAS_WIN32_STRUCTURED_EXCEPTIONS) ACE_TRACE ("ACE_Malloc_T::shared_free"); #endif /* ACE_HAS_WIN32_STRUCTURED_EXCEPTIONS */ if (ap == 0 || this->cb_ptr_ == 0) return; // Adjust AP to point to the block MALLOC_HEADER MALLOC_HEADER *blockp = ((MALLOC_HEADER *) ap) - 1; MALLOC_HEADER *currp = this->cb_ptr_->freep_; // Search until we find the location where the blocks belongs. Note // that addresses are kept in sorted order. ACE_SEH_TRY { for (; blockp <= currp || blockp >= (MALLOC_HEADER *) currp->next_block_; currp = currp->next_block_) { if (currp >= (MALLOC_HEADER *) currp->next_block_ && (blockp > currp || blockp < (MALLOC_HEADER *) currp->next_block_)) // Freed block at the start or the end of the memory pool. break; } // Join to upper neighbor. if (blockp + blockp->size_ == static_cast (currp->next_block_)) { ACE_MALLOC_STATS (--this->cb_ptr_->malloc_stats_.nblocks_); blockp->size_ += currp->next_block_->size_; blockp->next_block_ = currp->next_block_->next_block_; } else blockp->next_block_ = currp->next_block_; // Join to lower neighbor. if ((currp + currp->size_) == blockp) { ACE_MALLOC_STATS (--this->cb_ptr_->malloc_stats_.nblocks_); currp->size_ += blockp->size_; currp->next_block_ = blockp->next_block_; } else currp->next_block_ = blockp; ACE_MALLOC_STATS (--this->cb_ptr_->malloc_stats_.ninuse_); this->cb_ptr_->freep_ = currp; } ACE_SEH_EXCEPT (this->memory_pool_.seh_selector (GetExceptionInformation ())) { } } // No locks held here, caller must acquire/release lock. template void* ACE_Malloc_T::shared_find (const char *name) { #if !defined (ACE_HAS_WIN32_STRUCTURED_EXCEPTIONS) ACE_TRACE ("ACE_Malloc_T::shared_find"); #endif /* !ACE_HAS_WIN32_STRUCTURED_EXCEPTIONS */ if (this->cb_ptr_ == 0) return 0; ACE_SEH_TRY { for (NAME_NODE *node = this->cb_ptr_->name_head_; node != 0; node = node->next_) if (ACE_OS::strcmp (node->name (), name) == 0) return node; } ACE_SEH_EXCEPT (this->memory_pool_.seh_selector (GetExceptionInformation ())) { } return 0; } template int ACE_Malloc_T::shared_bind (const char *name, void *pointer) { if (this->cb_ptr_ == 0) return -1; // Combine the two allocations into one to avoid overhead... NAME_NODE *new_node = 0; ACE_ALLOCATOR_RETURN (new_node, (NAME_NODE *) this->shared_malloc (sizeof (NAME_NODE) + ACE_OS::strlen (name) + 1), -1); char *name_ptr = (char *) (new_node + 1); // Use operator placement new to insert at the head of // the linked list of s. NAME_NODE *result = new (new_node) NAME_NODE (name, name_ptr, reinterpret_cast (pointer), this->cb_ptr_->name_head_); this->cb_ptr_->name_head_ = result; return 0; } template int ACE_Malloc_T::trybind (const char *name, void *&pointer) { ACE_TRACE ("ACE_Malloc_T::trybind"); ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, *this->lock_, -1); NAME_NODE *node = (NAME_NODE *) this->shared_find (name); if (node == 0) // Didn't find it, so insert it. return this->shared_bind (name, pointer); // Found it, so return a copy of the current entry. pointer = (char *) node->pointer_; return 1; } template int ACE_Malloc_T::bind (const char *name, void *pointer, int duplicates) { ACE_TRACE ("ACE_Malloc_T::bind"); ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, *this->lock_, -1); 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; // 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 int ACE_Malloc_T::find (const char *name, void *&pointer) { ACE_TRACE ("ACE_Malloc_T::find"); ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, *this->lock_, -1); NAME_NODE *node = (NAME_NODE *) this->shared_find (name); if (node == 0) return -1; pointer = (char *) node->pointer_; return 0; } // Returns a count of the number of available chunks that can hold // byte allocations. Function can be used to determine if you // have reached a water mark. This implies a fixed amount of allocated // memory. // // @param size - the chunk size of that you would like a count of // @return function returns the number of chunks of the given size // that would fit in the currently allocated memory template ssize_t ACE_Malloc_T::avail_chunks (size_t size) const { ACE_TRACE ("ACE_Malloc_T::avail_chunks"); ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, *this->lock_, -1); if (this->cb_ptr_ == 0) return -1; size_t count = 0; // Avoid dividing by 0... size = size == 0 ? 1 : size; MALLOC_HEADER *currp = this->cb_ptr_->freep_; // Calculate how many will fit in this block. do { size_t avail_size = currp->size_ == 0 ? 0 : currp->size_ - 1; if (avail_size * sizeof (MALLOC_HEADER) >= size) count += avail_size * sizeof (MALLOC_HEADER) / size; currp = currp->next_block_; } while (currp != this->cb_ptr_->freep_); return count; } template int ACE_Malloc_T::find (const char *name) { ACE_TRACE ("ACE_Malloc_T::find"); ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, *this->lock_, -1); return this->shared_find (name) == 0 ? -1 : 0; } template int ACE_Malloc_T::unbind (const char *name, void *&pointer) { ACE_TRACE ("ACE_Malloc_T::unbind"); ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, *this->lock_, -1); if (this->cb_ptr_ == 0) return -1; NAME_NODE *prev = 0; for (NAME_NODE *curr = this->cb_ptr_->name_head_; curr != 0; curr = curr->next_) { if (ACE_OS::strcmp (curr->name (), name) == 0) { pointer = (char *) curr->pointer_; if (prev == 0) this->cb_ptr_->name_head_ = curr->next_; else prev->next_ = curr->next_; if (curr->next_) curr->next_->prev_ = prev; // This will free up both the node and the name due to our // clever trick in ! this->shared_free (curr); return 0; } prev = curr; } // Didn't find it, so fail. return -1; } template int ACE_Malloc_T::unbind (const char *name) { ACE_TRACE ("ACE_Malloc_T::unbind"); void *temp = 0; return this->unbind (name, temp); } /*****************************************************************************/ template ACE_LOCK * ACE_Malloc_Lock_Adapter_T::operator () (const ACE_TCHAR *name) { ACE_LOCK *p = 0; if (name == 0) ACE_NEW_RETURN (p, ACE_LOCK (name), 0); else ACE_NEW_RETURN (p, ACE_LOCK (ACE::basename (name, ACE_DIRECTORY_SEPARATOR_CHAR)), 0); return p; } /*****************************************************************************/ template void ACE_Malloc_LIFO_Iterator_T::dump () const { #if defined (ACE_HAS_DUMP) ACE_TRACE ("ACE_Malloc_LIFO_Iterator_T::dump"); ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); this->curr_->dump (); this->guard_.dump (); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("name_ = %C\n"), this->name_)); ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* ACE_HAS_DUMP */ } template ACE_Malloc_LIFO_Iterator_T::ACE_Malloc_LIFO_Iterator_T (ACE_Malloc_T &malloc, const char *name) : malloc_ (malloc), curr_ (0), guard_ (*malloc_.lock_), name_ (name != 0 ? ACE_OS::strdup (name) : 0) { ACE_TRACE ("ACE_Malloc_LIFO_Iterator_T::ACE_Malloc_LIFO_Iterator_T"); // Cheap trick to make code simple. // @@ Doug, this looks like trouble... NAME_NODE temp; this->curr_ = &temp; this->curr_->next_ = malloc_.cb_ptr_->name_head_; this->advance (); } template ACE_Malloc_LIFO_Iterator_T::~ACE_Malloc_LIFO_Iterator_T () { ACE_OS::free ((void *) this->name_); } template int ACE_Malloc_LIFO_Iterator_T::next (void *&next_entry, const char *&name) { ACE_TRACE ("ACE_Malloc_LIFO_Iterator_T::next"); if (this->curr_ != 0) { next_entry = (char *) this->curr_->pointer_; name = this->curr_->name (); return 1; } else return 0; } template int ACE_Malloc_LIFO_Iterator_T::next (void *&next_entry) { ACE_TRACE ("ACE_Malloc_LIFO_Iterator_T::next"); if (this->curr_ != 0) { next_entry = this->curr_->pointer_; return 1; } else return 0; } template int ACE_Malloc_LIFO_Iterator_T::done () const { ACE_TRACE ("ACE_Malloc_LIFO_Iterator_T::done"); return this->curr_ == 0; } template int ACE_Malloc_LIFO_Iterator_T::advance () { ACE_TRACE ("ACE_Malloc_LIFO_Iterator_T::advance"); this->curr_ = this->curr_->next_; if (this->name_ == 0) return this->curr_ != 0; while (this->curr_ != 0 && ACE_OS::strcmp (this->name_, this->curr_->name ()) != 0) this->curr_ = this->curr_->next_; return this->curr_ != 0; } template void ACE_Malloc_FIFO_Iterator_T::dump () const { #if defined (ACE_HAS_DUMP) ACE_TRACE ("ACE_Malloc_FIFO_Iterator_T::dump"); ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); this->curr_->dump (); this->guard_.dump (); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("name_ = %s\n"), this->name_)); ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* ACE_HAS_DUMP */ } template ACE_Malloc_FIFO_Iterator_T::ACE_Malloc_FIFO_Iterator_T (ACE_Malloc_T &malloc, const char *name) : malloc_ (malloc), curr_ (0), guard_ (*malloc_.lock_), name_ (name != 0 ? ACE_OS::strdup (name) : 0) { ACE_TRACE ("ACE_Malloc_FIFO_Iterator_T::ACE_Malloc_FIFO_Iterator"); // Cheap trick to make code simple. // @@ Doug, this looks like trouble... NAME_NODE temp; this->curr_ = &temp; this->curr_->next_ = malloc_.cb_ptr_->name_head_; this->curr_->prev_ = 0; // Go to the first element that was inserted. this->start (); } template ACE_Malloc_FIFO_Iterator_T::~ACE_Malloc_FIFO_Iterator_T () { ACE_OS::free ((void *) this->name_); } template int ACE_Malloc_FIFO_Iterator_T::next (void *&next_entry, const char *&name) { ACE_TRACE ("ACE_Malloc_FIFO_Iterator_T::next"); if (this->curr_ != 0) { next_entry = (char *) this->curr_->pointer_; name = this->curr_->name (); return 1; } else return 0; } template int ACE_Malloc_FIFO_Iterator_T::next (void *&next_entry) { ACE_TRACE ("ACE_Malloc_FIFO_Iterator_T::next"); if (this->curr_ != 0) { next_entry = this->curr_->pointer_; return 1; } else return 0; } template int ACE_Malloc_FIFO_Iterator_T::done () const { ACE_TRACE ("ACE_Malloc_FIFO_Iterator_T::done"); return this->curr_ == 0; } template int ACE_Malloc_FIFO_Iterator_T::advance () { ACE_TRACE ("ACE_Malloc_FIFO_Iterator_T::advance"); this->curr_ = this->curr_->prev_; if (this->name_ == 0) return this->curr_ != 0; while (this->curr_ != 0 && ACE_OS::strcmp (this->name_, this->curr_->name ()) != 0) this->curr_ = this->curr_->prev_; return this->curr_ != 0; } template int ACE_Malloc_FIFO_Iterator_T::start () { this->curr_ = this->curr_->next_; NAME_NODE *prev = 0; // Locate the element that was inserted first. // @@ We could optimize this by making the list a circular list or // storing an extra pointer. while (this->curr_ != 0) { prev = this->curr_; this->curr_ = this->curr_->next_; } this->curr_ = prev; return this->curr_ != 0; } ACE_END_VERSIONED_NAMESPACE_DECL #endif /* ACE_MALLOC_T_CPP */