//%2005//////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; // IBM Corp.; EMC Corporation, The Open Group. // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; // EMC Corporation; VERITAS Software Corporation; The Open Group. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //============================================================================== // // Author: Mike Day (mdday@us.ibm.com) // // Modified By: // Rammnath Ravindran (Ramnath.Ravindran@hp.com) // //%///////////////////////////////////////////////////////////////////////////// #include "suballoc.h" #include #include PEGASUS_NAMESPACE_BEGIN //#define PEGASUS_DEBUG_MEMORY peg_suballocator *peg_suballocator::_suballoc_instance = 0; PEGASUS_SUBALLOC_LINKAGE peg_suballocator *peg_suballocator::get_instance(void) { if(peg_suballocator::_suballoc_instance == 0) { #if defined(PEGASUS_DEBUG_MEMORY) PEGASUS_STD(cout) << "Initializing Debug Heap" << PEGASUS_STD(endl); #endif void *buffer = calloc(sizeof(peg_suballocator), sizeof(char)); peg_suballocator::_suballoc_instance = new(buffer) peg_suballocator(true); } return peg_suballocator::_suballoc_instance; } #if defined(PEGASUS_DEBUG_MEMORY) PEGASUS_SUBALLOC_LINKAGE void * pegasus_alloc(size_t size, void * handle, int type, const Sint8 *classname, Sint8 *file, Uint32 line) { return peg_suballocator::get_instance()->vs_malloc(size, ((handle == NULL) ? &(peg_suballocator::get_instance()->get_handle()) : handle), type, classname, file, line) ; } PEGASUS_SUBALLOC_LINKAGE void pegasus_free(void * dead, void * handle, int type, Sint8 *classname, Sint8 * file, Uint32 line) { if ( dead == 0 ) return; peg_suballocator::get_instance()->vs_free(dead, ((handle == NULL) ? &(peg_suballocator::get_instance()->get_handle()) : handle), type, classname, file, line); } #else PEGASUS_SUBALLOC_LINKAGE void * pegasus_alloc(size_t size) { return peg_suballocator::get_instance()->vs_malloc(size); } PEGASUS_SUBALLOC_LINKAGE void pegasus_free(void *dead) { peg_suballocator::get_instance()->vs_free(dead); } #endif PEGASUS_NAMESPACE_END PEGASUS_USING_STD; #if !defined(PEGASUS_PLATFORM_HPUX_ACC) && !defined(PEGASUS_PLATFORM_LINUX_IA64_GNU) && !defined(PEGASUS_PLATFORM_TRU64_ALPHA_DECCXX) PEGASUS_USING_PEGASUS; void * operator new(size_t size) throw (PEGASUS_STD(bad_alloc)) { if( size == 0 ) size = 1; void *p; while(1) { #if defined(PEGASUS_DEBUG_MEMORY) p = peg_suballocator::get_instance()->vs_malloc(size, &(peg_suballocator::get_instance()->get_handle()), NORMAL, "BUILTIN NEW", __FILE__, __LINE__) ; #else p = peg_suballocator::get_instance()->vs_malloc(size); #endif if( p ) return p; new_handler global = set_new_handler(0); set_new_handler(global); if( global) (*global)(); else throw PEGASUS_STD(bad_alloc()); } } #ifdef PEGASUS_PLATFORM_HPUX_ACC void operator delete(void *dead) throw() #else void operator delete(void *dead) #endif { if( dead == 0 ) return; #if defined(PEGASUS_DEBUG_MEMORY) peg_suballocator::get_instance()->vs_free(dead, &(peg_suballocator::get_instance()->get_handle()), NORMAL, "internal", __FILE__, __LINE__); #else peg_suballocator::get_instance()->vs_free(dead); #endif return; } void * operator new[] (size_t size) throw (PEGASUS_STD(bad_alloc)) { if( size == 0 ) size = 1; void *p; while(1) { #if defined(PEGASUS_DEBUG_MEMORY) p = peg_suballocator::get_instance()->vs_malloc(size, &(peg_suballocator::get_instance()->get_handle()), ARRAY, "BUILTIN ARRAY NEW", __FILE__, __LINE__) ; #else p = peg_suballocator::get_instance()->vs_malloc(size); #endif if( p ) return p; new_handler global = set_new_handler(0); set_new_handler(global); if( global) (*global)(); else throw PEGASUS_STD(bad_alloc()); } } #ifdef PEGASUS_PLATFORM_HPUX_ACC void operator delete[] (void *dead) throw() #else void operator delete[] (void *dead) #endif { if( dead == 0 ) return; #if defined(PEGASUS_DEBUG_MEMORY) peg_suballocator::get_instance()->vs_free(dead, &(peg_suballocator::get_instance()->get_handle()), ARRAY, "internal", __FILE__, __LINE__); #else peg_suballocator::get_instance()->vs_free(dead); #endif return; } #endif // PEGASUS_PLATFORM_HPUX_ACC PEGASUS_NAMESPACE_BEGIN #if defined(PEGASUS_DEBUG_MEMORY) const Uint8 peg_suballocator::guard[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03}; const Uint8 peg_suballocator::alloc_pattern = 0xaa; const Uint8 peg_suballocator::delete_pattern = 0xee; #endif const Sint32 peg_suballocator::nodeSizes[3][16] = { { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff }, { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800, 0x900, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00, 0xfff }, { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000, 2 * sizeof(void *) } }; // prototypes that begin with an underscore do not attempt to // gain ownership of semaphores and can be safely called // by a process that owns a semaphore const Uint32 peg_suballocator::preAlloc[3][16] = { {20, 20, 20, 20, 20, 20, 20, 10, 10, 10, 10, 10, 10, 10, 10, 10 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; const Uint32 peg_suballocator::step[3][16] = { {20, 20, 20, 20, 20, 20, 20, 10, 10, 10, 10, 10, 10, 10, 10, 10 }, {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; peg_suballocator::peg_suballocator(void) : initialized(0), debug_mode(true), abort_on_error(true), check_for_leaks(true), internal_handle("internal_suballoc_log") { memcpy(internal_handle.classname, "internal\0", 9); InitializeSubAllocator(); return; } peg_suballocator::peg_suballocator(Boolean mode) : initialized(0), debug_mode(mode), abort_on_error(true), check_for_leaks(true), internal_handle("internal_suballoc_log") { memcpy(internal_handle.classname, "internal\0", 9); InitializeSubAllocator(); return; } peg_suballocator::~peg_suballocator(void) { DeInitSubAllocator(&internal_handle); } peg_suballocator::SUBALLOC_HANDLE *peg_suballocator::InitializeProcessHeap(Sint8 *f) { return new SUBALLOC_HANDLE(f); } /**************************************************************** * InitializeSubAllocator * * * PARAMETERS: none * * DESCRIPTION: If suballocator is already initialized, returns * true immediately. Otherwise, allocates node list * heads and performs pre-allocations. * * RETURNS: true if successful, false otherwise * ***************************************************************/ Boolean peg_suballocator::InitializeSubAllocator(void) { SUBALLOC_NODE *temp; Sint32 i, o; Boolean ccode = true; Sint32 waitCode; if(initialized) return true; if(CREATE_MUTEX(&globalSemHandle)) return(false); WAIT_MUTEX(&globalSemHandle, 1000, &waitCode); // check to see if we are already initialized // gain ownership of global semaphore here for (o = 0; o < 3; o++) { for (i = 0; i < 16; i++) { // allocate our list heads if (0 == ((Sint32)(CREATE_MUTEX(&(semHandles[o][i]))))) { nodeListHeads[o][i] = (SUBALLOC_NODE *)calloc(1, sizeof (SUBALLOC_NODE)); if ( nodeListHeads[o][i] == NULL ) { while (o >= 0) { while (i >= 0) { if (nodeListHeads[o][i] != NULL) { free(nodeListHeads[o][i]); nodeListHeads[o][i] = NULL; } CLOSE_MUTEX(&(semHandles[o][i])); i--; } o--; } RELEASE_MUTEX(&globalSemHandle); RELEASE_MUTEX(&init_mutex); return(false); } temp = nodeListHeads[o][i]; temp->next = temp->prev = temp; temp->flags |= (IS_HEAD_NODE ); #if defined(PEGASUS_DEBUG_MEMORY) memcpy(temp->guardPre, guard, GUARD_SIZE); #endif if (preAlloc[o][i]) ccode = _Allocate(o, i, PRE_ALLOCATE); if (ccode == false) { while (o >= 0) { while (i >= 0) { if (nodeListHeads[o][i] != NULL) { free(nodeListHeads[o][i]); nodeListHeads[o][i] = NULL; } CLOSE_MUTEX(&(semHandles[o][i])); i--; } o--; } RELEASE_MUTEX(&globalSemHandle); RELEASE_MUTEX(&init_mutex); return(false); } } } } initialized = 1; // release global concurrency semaphore here RELEASE_MUTEX(&globalSemHandle); return(true); } /**************************************************************** * _Allocate * * * PARAMETERS: IN index is a selector for the correct * node head. * IN code is a control code that determines if we * are doing a pre-allocation or a step-allocation. * * DESCRIPTION: Creates new memory nodes, initializes them, * and links them to the appropriate list head. * A pre-allocation creates nodes at init time, while * a step-allocation creates nodes at run time when all * existing nodes are unavailable. * * INTERNAL CALL ONLY - caller must own the semaphore * for the list indicated by index; or, alternatively, * caller must own the global semaphore. * * RETURNS: true if successful, false otherwise * ***************************************************************/ Boolean peg_suballocator::_Allocate(Sint32 vector, Sint32 index, Sint32 code) { // no semaphores - this internal routine must only be // called by threads owning the list head indicated by index SUBALLOC_NODE *temp, *temp2; Sint32 i; Sint8 *g; temp = nodeListHeads[vector][index]; if (code == PRE_ALLOCATE) // this is a preallocation i = preAlloc[vector][index]; else i = step[vector][index]; // this is a step allocation #if defined(PEGASUS_DEBUG_MEMORY) size_t chunk_size = (i * (sizeof(SUBALLOC_NODE) + GUARD_SIZE + nodeSizes[vector][index])); #else size_t chunk_size = (i * (sizeof(SUBALLOC_NODE) + nodeSizes[vector][index])); #endif temp2 = (SUBALLOC_NODE *)calloc(chunk_size, sizeof(char)); if(temp2 == NULL) return false; for ( ; i > 0; i--) { temp2->flags |= AVAIL; temp2->concurrencyHandle = &internal_handle; #if defined(PEGASUS_DEBUG_MEMORY) memcpy(temp2->guardPre, guard, GUARD_SIZE); #endif g = (Sint8 *)temp2; g+= sizeof(SUBALLOC_NODE); g+= nodeSizes[vector][index]; #if defined(PEGASUS_DEBUG_MEMORY) memcpy(g, guard, GUARD_SIZE); g += GUARD_SIZE; #endif INSERT(temp2, temp); temp2 = (SUBALLOC_NODE *)g; } return(true); } /**************************************************************** * DeInitSubAllocator * * * PARAMETERS: * * DESCRIPTION: Locks suballocator and destroys all of its data * structures. Checks for unfreed nodes, which * represent memory leaks. * * RETURNS: * ***************************************************************/ void peg_suballocator::DeInitSubAllocator(void *handle) { Sint32 i, o, waitCode; assert(handle != 0); // _UnfreedNodes(handle); if( handle != (void *) &internal_handle) free((void *)handle); init_count--; if (! init_count) { initialized = 0; WAIT_MUTEX(&globalSemHandle, 1000, &waitCode); for (o = 0; o < 3; o++) { for (i = 0; i < 16; i++) { WAIT_MUTEX(&(semHandles[o][i]), 1000, &waitCode); CLOSE_MUTEX(&(semHandles[o][i])); _DeAllocate(o, i); free(nodeListHeads[o][i]); nodeListHeads[o][i] = NULL; } } CLOSE_MUTEX(&(globalSemHandle)); initialized = 0; } return; } /**************************************************************** * _DeAllocate * * * PARAMETERS: IN index is a selector for the correct * list to destroy * * DESCRIPTION: INTERNAL CALL ONLY - caller must own the semaphore * for the list head, or, alternatively, the * global semaphore. * After calling this function, be certain to close * the semaphore handle corresponding to index. * * RETURNS: * ***************************************************************/ void peg_suballocator::_DeAllocate(Sint32 vector, Sint32 index) { // caller owns semHandles[vector][index] SUBALLOC_NODE *temp, *temp2; temp = nodeListHeads[vector][index]; while ( ! IS_EMPTY(temp) ) { temp2 = temp->next; _DELETE(temp2); free(temp2); } return; } /**************************************************************** * GetNode * * * PARAMETERS: IN index is a selector for the listHead from which * we want to get a node. * * DESCRIPTION: Allocates a node from the selected list. If the * list is fully utilized, allocates some new nodes * and returns one of those. * * RETURNS: pointer to an allocated node. the node remains linked * its list but is marked as not being available. * ***************************************************************/ peg_suballocator::SUBALLOC_NODE *peg_suballocator::GetNode(Sint32 vector, Sint32 index) { SUBALLOC_NODE *temp; Sint32 waitCode; if(initialized == 0 ) { InitializeSubAllocator(); } WAIT_MUTEX(&(semHandles[vector][index]), 1000, &waitCode); temp = (nodeListHeads[vector][index])->next; // if list is empty we will fall through while (! IS_HEAD(temp) ) { if ((temp->flags & AVAIL) && (false == IS_HEAD(temp))) { temp->flags &= ~(AVAIL) ; // release semHandles[index] RELEASE_MUTEX(&(semHandles[vector][index])); return(temp); } temp = temp->next; } // the list is either empty or fully allocated if (! _Allocate(vector, index, STEP_ALLOCATE)) { // release semHandles[index]; RELEASE_MUTEX(&(semHandles[vector][index])); return(NULL); } // Allocate always links new nodes at the front of the list // we can just grab the first node and go temp = (nodeListHeads[vector][index])->next; temp->flags &= ~(AVAIL); if( check_for_leaks == true ) temp->flags |= CHECK_LEAK; // release semHandles[vector][index]; RELEASE_MUTEX(&(semHandles[vector][index])); return(temp); } /**************************************************************** * GetHugeNode * * * PARAMETERS: IN size is the amount of memory requested by the * caller. * * DESCRIPTION: Allocates a node from the "huge" list. This list is * maintained specifically for memory allocations that * are greater than 32K bytes. If the list is fully * utilized, will allocate some new nodes and return * one of those. * * RETURNS: pointer to an allocated node. the node remains linked * its list but is marked as not being available. * ***************************************************************/ peg_suballocator::SUBALLOC_NODE * peg_suballocator::GetHugeNode(Sint32 size) { SUBALLOC_NODE *temp; Sint32 waitCode; if(initialized == 0 ) { InitializeSubAllocator(); } WAIT_MUTEX(&(semHandles[2][15]), 1000, &waitCode); temp = (nodeListHeads[2][15])->next; while (! IS_HEAD(temp) ) { if ((temp->flags & AVAIL) && (false == IS_HEAD(temp))) { if(temp->nodeSize >= (Uint32)size) { temp->flags &= ~(AVAIL) ; temp->allocSize = size; break; } } temp = temp->next; } if( IS_HEAD(temp)) { #if defined(PEGASUS_DEBUG_MEMORY) size_t chunk_size = (sizeof(SUBALLOC_NODE) + GUARD_SIZE + size); #else size_t chunk_size = (sizeof(SUBALLOC_NODE) + size); #endif temp = (SUBALLOC_NODE *)calloc(chunk_size, sizeof(char)); if(temp == NULL) { RELEASE_MUTEX(&(semHandles[2][15])); return temp; } temp->allocSize = temp->nodeSize = size; INSERT(temp, nodeListHeads[2][15]); } temp->concurrencyHandle = &internal_handle; #if defined(PEGASUS_DEBUG_MEMORY) memcpy(temp->guardPre, guard, GUARD_SIZE); #endif RELEASE_MUTEX(&(semHandles[2][15])); return(temp); } /**************************************************************** * PutNode * * * PARAMETERS: IN index is a selector for the correct listhead. * IN node is the node that we need to "put" back * on to the list. * * DESCRIPTION: "put" is a misnomer because the node never * leaves its list. However, we do unlink the node * and insert it at the front of the list before marking * it as being available. We do this to speed up allocation * of the node next time someone needs it. We want * to keep all available nodes at the front of the list. * * RETURNS: * ***************************************************************/ void peg_suballocator::PutNode(Sint32 vector, Sint32 index, SUBALLOC_NODE *node) { Sint32 waitCode; WAIT_MUTEX(&(semHandles[vector][index]), 1000, &waitCode); // mark the node as available, unlink it, and relink it // to the front of the list assert(node != NULL); // gain ownership of semHandles[index]; // delete insert the node at the front of the list - // this will make it faster to get the node _DELETE(node); node->concurrencyHandle = &internal_handle; node->flags |= AVAIL; INSERT(node, nodeListHeads[vector][index]); RELEASE_MUTEX(&(semHandles[vector][index])); return; } /**************************************************************** * PutHugeNode * * * PARAMETERS: IN node is the node that we need to "put" back * on to the "huge" list. * * DESCRIPTION: "put" is a misnomer because the node never * leaves its list. However, we do unlink the node * and insert it at the front of the list before marking * it as being available. We do this to speed up allocation * of the node next time someone needs it. We want * to keep all available nodes at the front of the list. * * RETURNS: * ***************************************************************/ void peg_suballocator::PutHugeNode(SUBALLOC_NODE *node) { // mark the node as available, unlink it, and relink it // to the front of the list PutNode(2, 15, node); } /**************************************************************** * vs_malloc * * * PARAMETERS: IN size is the amount of memory requested * * DESCRIPTION: initializes the suballocator if neccesary. * gets an appropriately sized memory node and * returns a pointer to the caller. * * RETURNS: pointer to memory available for use by the caller, * or NULL. * ***************************************************************/ #if defined(PEGASUS_DEBUG_MEMORY) void *peg_suballocator::vs_malloc(size_t size, void *handle, int type, const Sint8 *classname, const Sint8 *f, Uint32 l) { // we don't need to grab any semaphores, // called routines will do that for us SUBALLOC_NODE *temp; Sint8 *g; assert(size != 0); if (! (size >> 8)) { temp = GetNode(0, (size >> 4)); } else if (! (size >> 12)) { temp = GetNode(1, (size >> 8)); } else if (! (size >> 16)) { temp = GetNode(2, (size >> 12)); } else { temp = GetHugeNode(size); } temp->allocSize = size; temp->concurrencyHandle = (void *)handle; if(type == ARRAY) temp->flags |= ARRAY_NODE; if(classname) strncpy(temp->classname, classname, MAX_CLASS_LEN); else temp->classname[0] = 0x00; if(f) strncpy(temp->file, f, MAX_PATH_LEN); else temp->file[0] = 0x00; temp->line = l; g = (Sint8 *)temp; g += sizeof(SUBALLOC_NODE); memcpy(g + size, guard, GUARD_SIZE); return((void *)g); } #else void *peg_suballocator::vs_malloc(size_t size) { SUBALLOC_NODE *temp; Sint8 *g; assert(size != 0); if (! (size >> 8)) { temp = GetNode(0, (size >> 4)); } else if (! (size >> 12)) { temp = GetNode(1, (size >> 8)); } else if (! (size >> 16)) { temp = GetNode(2, (size >> 12)); } else temp = GetHugeNode(size); temp->allocSize = size; temp->concurrencyHandle = (void *)&internal_handle; g = (Sint8 *)temp; g += sizeof(SUBALLOC_NODE); return((void *)g); } #endif /**************************************************************** * vs_calloc * * * PARAMETERS: IN num is the number of memory units requested. * IN size is the size of each memory unit. result * is a contigious area of memory that is * num * size bytes. * * DESCRIPTION: initializes the suballocator if neccesary. * gets an appropriately sized memory node, zeros * caller's memory block and returns a * pointer to the caller. * * RETURNS: pointer to zero'ed memory available for use by the * caller, or NULL. ***************************************************************/ #if defined(PEGASUS_DEBUG_MEMORY) void *peg_suballocator::vs_calloc(size_t num, size_t s, void *handle, int type, Sint8 *f, Uint32 l) { void *g = vs_malloc((unsigned)num * s, handle, type, "internal", f, l); memset(g, 0x00, num * s); return(g); } #else void *peg_suballocator::vs_calloc(size_t num, size_t s) { void *g = vs_malloc((unsigned)num * s); memset(g, 0x00, num * s); return(g); } #endif /**************************************************************** * vs_free * * * PARAMETERS: IN pointer to memory that the caller wants freed. * * DESCRIPTION: marks the node as available. in debug mode, * checks for memory under and over -writes. * * RETURNS: * ***************************************************************/ #if defined(PEGASUS_DEBUG_MEMORY) void peg_suballocator::vs_free(void *m, void *handle, int type , Sint8 *classname, Sint8* file, Uint32 line) { // we don't need to grab any semaphores - // called routines will do that for us assert( m != NULL); SUBALLOC_NODE *temp = _CheckNode(m, type, file, line); memset(temp->d_classname, 0x00, MAX_CLASS_LEN + 1); strncpy(temp->d_classname, classname, MAX_CLASS_LEN); memset(temp->d_file, 0x00, MAX_PATH_LEN + 1); strncpy(temp->d_file, file, MAX_PATH_LEN); temp->d_line = line; if (! (temp->allocSize >> 8)) { PutNode(0, (temp->allocSize >> 4), temp); } else if (! (temp->allocSize >> 12)) { PutNode(1, (temp->allocSize >> 8), temp); } else if (! (temp->allocSize >> 16)) { PutNode(2, (temp->allocSize >> 12), temp); } else PutHugeNode(temp); return; } #else void peg_suballocator::vs_free(void *m) { // we don't need to grab any semaphores - // called routines will do that for us assert( m != 0 ); SUBALLOC_NODE *temp = (SUBALLOC_NODE *)m; temp--; if (! (temp->allocSize >> 8)) { PutNode(0, (temp->allocSize >> 4), temp); } else if (! (temp->allocSize >> 12)) { PutNode(1, (temp->allocSize >> 8), temp); } else if (! (temp->allocSize >> 16)) { PutNode(2, (temp->allocSize >> 12), temp); } else PutHugeNode(temp); return; } #endif #if defined(PEGASUS_DEBUG_MEMORY) void *peg_suballocator::vs_realloc(void *pblock, size_t newsize, void *handle, int type, Sint8 *f, Uint32 l) { if (pblock == NULL) { return(vs_malloc(newsize, handle, type, 0, f, l)); } if (newsize == 0) { vs_free(pblock, handle, type, "INTERNAL", f, l); return(NULL); } { void *newblock; newblock = vs_calloc(newsize, sizeof(char), handle, type, f, l); if (newblock != NULL) { SUBALLOC_NODE *temp; int copysize; temp = (SUBALLOC_NODE *)pblock; temp--; if(newsize > temp->allocSize) copysize = temp->allocSize; else copysize = newsize; /* get the actual data size of the old block - only copy that much */ /* if newsize is smaller than oldsize, only copy newsize */ memcpy(newblock, pblock, copysize); vs_free(pblock, handle, type, "INTERNAL", f, l); return(newblock); } else return(pblock); } } #else void *peg_suballocator::vs_realloc(void *pblock, size_t newsize) { if (pblock == NULL) { return(vs_malloc(newsize)); } if (newsize == 0) { vs_free(pblock); return(NULL); } { void *newblock; newblock = vs_calloc(newsize, sizeof(char)); if (newblock != NULL) { SUBALLOC_NODE *temp; int copysize; temp = (SUBALLOC_NODE *)pblock; temp--; if(newsize > temp->allocSize) copysize = temp->allocSize; else copysize = newsize; /* get the actual data size of the old block - only copy that much */ /* if newsize is smaller than oldsize, only copy newsize */ memcpy(newblock, pblock, copysize); vs_free(pblock); return(newblock); } else return(pblock); } } #endif #if defined(PEGASUS_DEBUG_MEMORY) Sint8 * peg_suballocator::vs_strdup(const Sint8 *string, void *handle, int type, Sint8 *f, Uint32 l) { Sint8 *memory; if (!string) return(NULL); if ((memory = (Sint8 *)vs_malloc(strlen(string) + 1, handle, type, 0, f, l))) return(strcpy(memory,string)); return(NULL); } #else Sint8 * peg_suballocator::vs_strdup(const Sint8 *string) { Sint8 *memory; if (!string) return(NULL); if ((memory = (Sint8 *)vs_malloc(strlen(string) + 1))) return(strcpy(memory,string)); return(NULL); } #endif /**************************************************************** * _UnfreedNodes * * * PARAMETERS: IN index is a selector for the correct listhead. * * DESCRIPTION: Checks the list for unfreed nodes. These are nodes * that are marked as available. Call this routine * to check for memory leaks. * INTERNAL call only - caller must own the semaphore * for the list indicated by index. * * RETURNS: true if there are unfreed nodes on the list, * false otherwise * ***************************************************************/ #if defined(PEGASUS_DEBUG_MEMORY) Boolean peg_suballocator::_UnfreedNodes(void * handle) { Sint8 i, y; Sint32 waitCode; SUBALLOC_NODE *temp; Boolean ccode = false; SUBALLOC_HANDLE *h = (SUBALLOC_HANDLE *)handle; for (y = 0; y < 3; y++ ) { for (i = 0; i < 16; i++) { WAIT_MUTEX(&(semHandles[y][i]), 1000, &waitCode); temp = (nodeListHeads[y][i])->next; // if list is empty we will fall through while (! IS_HEAD(temp) ) { if (!(temp->flags & AVAIL) && temp->concurrencyHandle == handle) { if( temp->flags & CHECK_LEAK) { h = (SUBALLOC_HANDLE *)temp->concurrencyHandle; RELEASE_MUTEX(&(semHandles[y][i])); Tracer::trace(__FILE__, __LINE__, TRC_MEMORY, Tracer::LEVEL2, "Memory Leak: %d bytes class %s allocated memory in source file %s at " \ "line %d", temp->allocSize, temp->classname, temp->file, temp->line); WAIT_MUTEX(&(semHandles[y][i]), 1000, &waitCode); ccode = true; } } temp = temp->next; } RELEASE_MUTEX(&(semHandles[y][i])); } } return(ccode); } /**************************************************************** * _CheckGuard * * * PARAMETERS: IN node is a node that we want to check for * under and over -writes. * * DESCRIPTION: checks node for under and over -writes * * NOTE: only available in debug mode. * * RETURNS: true if node is intact, false if node has been * stomped upon. * ***************************************************************/ Boolean peg_suballocator::_CheckGuard(SUBALLOC_NODE *node) { Sint32 ccode; ccode = memcmp(node->guardPre, guard, GUARD_SIZE); if (ccode == 0) { Sint8 *g = (Sint8 *)node; g += sizeof(SUBALLOC_NODE); g += node->allocSize; ccode = memcmp(g, guard, GUARD_SIZE); if (ccode == 0) { return(true); } } return(false); } Uint32 peg_suballocator::CheckMemory(void *m) { return _CheckNode(m); } Uint32 peg_suballocator::_CheckNode(void *m) { assert(m != NULL); SUBALLOC_NODE *temp = (SUBALLOC_NODE *)m; temp--; if(temp->flags & AVAIL) return ALREADY_DELETED; if(false == _CheckGuard(temp)) return OVERWRITE; return 0; } peg_suballocator::SUBALLOC_NODE *peg_suballocator::_CheckNode(void *m, int type, Sint8 *file, Uint32 line) { assert(m != NULL); SUBALLOC_NODE *temp = (SUBALLOC_NODE *)m; temp--; if( (temp->flags & AVAIL ) ) { Tracer::trace(file, line, TRC_MEMORY, Tracer::LEVEL2, "Doubly freed memory, already deleted by class %s at " \ "source file %s line number %d; this deletion is from " \ "source file %s line number %d", temp->d_classname, temp->d_file, temp->d_line, file, line); temp->flags |= CHECK_FAILED; if( abort_on_error) abort(); } /****** if( type == ARRAY ) { if( false == IS_ARRAY(temp)) { Tracer::trace(file, line, TRC_MEMORY, Tracer::LEVEL2, "Array delete called with non-array object at " \ "source file %s line number %d. Object was originally allocated " \ " by class %s in source file %s at line number %d", file, line, temp->classname, temp->file, temp->line); temp->flags |= CHECK_FAILED; if( abort_on_error) abort(); } } else if( true == IS_ARRAY(temp)) { Tracer::trace(file, line, TRC_MEMORY, Tracer::LEVEL2, "Normal delete called with array object at " \ "source file %s line number %d. Object was originally allocated " \ " by class %s in source file %s at line number %d", file, line, temp->classname, temp->file, temp->line); temp->flags |= CHECK_FAILED; if( abort_on_error) abort(); } *****/ if(false == _CheckGuard(temp)) { Tracer::trace(file, line, TRC_MEMORY, Tracer::LEVEL2, "Memory overwritten. Allocated by %s in source file %s at line number %d", temp->classname, temp->file, temp->line); temp->flags |= CHECK_FAILED; if( abort_on_error) abort(); } return temp; } void peg_suballocator::PrintNodeInfo(void *m, Sint8 *output_file, Sint8 *file, Uint32 line) { assert(m != NULL); SUBALLOC_NODE *temp = (SUBALLOC_NODE *)m; temp--; FILE *output = fopen(output_file, "a+"); if(output != NULL) { fprintf(output, "********* MEMORY NODE RECORD *********\n"); fprintf(output, "node address: %p\n", temp); fprintf(output, "allocated at %s line %d\n", temp->file, temp->line); fprintf(output, "classname (may not be available): %s\n", temp->classname); fprintf(output, "alloc size: %d; node size: %d\n", temp->allocSize, temp->nodeSize); if(temp->flags & AVAIL) { fprintf(output, "Doubly freed memory, already deleted by class %s at " \ "source file %s line number %d; this deletion is from " \ "source file %s line number %d\n", temp->d_classname, temp->d_file, temp->d_line, file, line); } if( true == IS_ARRAY(temp)) { fprintf(output, "Array node\n"); } if( false == _CheckGuard(temp)) { fprintf(output, "Memory overwritten!\n"); } fclose(output); } } #endif // defined PEGASUS_DEBUG_MEMORY PEGASUS_NAMESPACE_END