sl@0: /* Copyright (c) 2009 The Khronos Group Inc. sl@0: * Portions copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies) sl@0: * sl@0: * Permission is hereby granted, free of charge, to any person obtaining a sl@0: * copy of this software and/or associated documentation files (the sl@0: * "Materials"), to deal in the Materials without restriction, including sl@0: * without limitation the rights to use, copy, modify, merge, publish, sl@0: * distribute, sublicense, and/or sell copies of the Materials, and to sl@0: * permit persons to whom the Materials are furnished to do so, subject to sl@0: * the following conditions: sl@0: * sl@0: * The above copyright notice and this permission notice shall be included sl@0: * in all copies or substantial portions of the Materials. sl@0: * sl@0: * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, sl@0: * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF sl@0: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. sl@0: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY sl@0: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, sl@0: * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE sl@0: * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. sl@0: */ sl@0: sl@0: sl@0: #ifdef __cplusplus sl@0: extern "C" sl@0: { sl@0: #endif sl@0: sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include "owfmemory.h" sl@0: #include "owfdebug.h" sl@0: sl@0: #ifdef DEBUG sl@0: sl@0: #define MAGIK 0x05EAF00D sl@0: #define FENCE1 0xFACED00D sl@0: #define FENCE2 0xFACE50FF sl@0: sl@0: #define OFFSET(x,y) ((OWFuint32)&(((x*) 0x1000)->y) - 0x1000) sl@0: sl@0: typedef struct BLOCK_ { sl@0: OWFint magik; sl@0: struct BLOCK_* next; sl@0: const char* file; sl@0: OWFint line; sl@0: OWFuint32 size; sl@0: OWFuint32 nInts; sl@0: OWFint memory[2]; sl@0: } BLOCK; sl@0: sl@0: sl@0: sl@0: sl@0: static void sl@0: OWF_Memory_Shutdown(void); sl@0: sl@0: sl@0: sl@0: static void sl@0: OWF_Memory_LockUnlockManagedBlocks(OWFboolean lock) sl@0: { sl@0: #ifndef DEBUG sl@0: (void) lock; sl@0: #endif sl@0: sl@0: #ifdef DEBUG sl@0: /* cannot use OWF_MUTEX because it uses managed memory */ sl@0: static pthread_mutex_t mem_mutex = PTHREAD_MUTEX_INITIALIZER; sl@0: sl@0: if (lock) sl@0: { sl@0: pthread_mutex_lock(&mem_mutex); sl@0: } sl@0: else sl@0: { sl@0: pthread_mutex_unlock(&mem_mutex); sl@0: } sl@0: #endif sl@0: } sl@0: sl@0: static void sl@0: OWF_Memory_LockManagedBlocks() sl@0: { sl@0: OWF_Memory_LockUnlockManagedBlocks(OWF_TRUE); sl@0: } sl@0: sl@0: static void sl@0: OWF_Memory_UnlockManagedBlocks() sl@0: { sl@0: OWF_Memory_LockUnlockManagedBlocks(OWF_FALSE); sl@0: } sl@0: sl@0: sl@0: OWF_API_CALL BLOCK* sl@0: OWF_Memory_GetSetManagedBlocks(BLOCK* b, OWFboolean set) sl@0: { sl@0: #ifdef DEBUG sl@0: static BLOCK* managed_blocks = NULL; sl@0: static OWFboolean initialized = OWF_FALSE; sl@0: sl@0: if (!initialized) { sl@0: /* add exit handler (leak report) */ sl@0: atexit(OWF_Memory_Shutdown); sl@0: initialized = OWF_TRUE; sl@0: } sl@0: sl@0: if (set) sl@0: { sl@0: managed_blocks = b; sl@0: return b; sl@0: } sl@0: else sl@0: { sl@0: return managed_blocks; sl@0: } sl@0: #else sl@0: if (set) sl@0: { sl@0: b = b; /* dummy code */ sl@0: } sl@0: return NULL; sl@0: #endif sl@0: } sl@0: sl@0: static BLOCK* sl@0: OWF_Memory_GetManagedBlocks() sl@0: { sl@0: return OWF_Memory_GetSetManagedBlocks(NULL, OWF_FALSE); sl@0: } sl@0: sl@0: static void sl@0: OWF_Memory_SetManagedBlocks(BLOCK* b) sl@0: { sl@0: OWF_Memory_GetSetManagedBlocks(b, OWF_TRUE); sl@0: } sl@0: sl@0: OWF_API_CALL void* sl@0: OWF_Memory_Alloc(const char* file, OWFint line, OWFuint32 size) sl@0: { sl@0: #define INT_SIZE sizeof(OWFint) sl@0: sl@0: BLOCK* block = NULL; sl@0: sl@0: /* size rounded to nearest sizeof(int)*n + 2*sizeof(int) for fences */ sl@0: OWFuint32 nInts = 2 + (((size + INT_SIZE-1) &~ (INT_SIZE-1)) >> 2); sl@0: OWFuint32 realSize = nInts * INT_SIZE + sizeof(BLOCK); sl@0: sl@0: if (realSize > size) /* not int overflow */ sl@0: { sl@0: block = (BLOCK*) malloc(realSize); sl@0: } sl@0: sl@0: if (!block) sl@0: { sl@0: DPRINT(("Couldn't alloc %u bytes\n", size)); sl@0: return NULL; sl@0: } sl@0: sl@0: /* populate block header */ sl@0: memset(block, 0, realSize); sl@0: block->magik = MAGIK; sl@0: block->file = file; sl@0: block->line = line; sl@0: block->size = size; sl@0: block->nInts = nInts; sl@0: block->memory[0] = FENCE1; sl@0: block->memory[nInts-1] = FENCE2; sl@0: sl@0: OWF_Memory_LockManagedBlocks(); sl@0: { sl@0: /* insert to list at position 0 */ sl@0: block->next = (BLOCK*) OWF_Memory_GetManagedBlocks(); sl@0: OWF_Memory_SetManagedBlocks(block); sl@0: } sl@0: OWF_Memory_UnlockManagedBlocks(); sl@0: sl@0: return &block->memory[1]; sl@0: } sl@0: sl@0: OWF_API_CALL void sl@0: OWF_Memory_Free(void* ptr) sl@0: { sl@0: BLOCK* block = NULL; sl@0: sl@0: if (!ptr) { sl@0: return; sl@0: } sl@0: sl@0: /* POINTER ARITHMETIC HAZARD */ sl@0: block = (BLOCK*) ((OWFuint32) ptr - (OWFuint32) OFFSET(BLOCK,memory[1])); sl@0: sl@0: if (!block) sl@0: { sl@0: DPRINT(("Sanity check failed. Ptr was zero....\n")); sl@0: return; sl@0: } sl@0: sl@0: OWF_Memory_LockManagedBlocks(); sl@0: { sl@0: BLOCK* temp = NULL; sl@0: BLOCK* prev = NULL; sl@0: OWFboolean stillExists = OWF_FALSE; sl@0: sl@0: temp = OWF_Memory_GetManagedBlocks(); sl@0: sl@0: while (temp) sl@0: { sl@0: /* the block is on the list? */ sl@0: if (temp == block && ptr == &temp->memory[1]) sl@0: { sl@0: stillExists = OWF_TRUE; sl@0: break; sl@0: } sl@0: prev = temp; sl@0: temp = temp->next; sl@0: } sl@0: sl@0: if (stillExists == OWF_TRUE) sl@0: { sl@0: if (MAGIK != temp->magik) sl@0: { sl@0: DPRINT(("Possibly corrupt or invalid block, addr = %p\n", ptr)); sl@0: } sl@0: if (block->memory[0] != (OWFint)FENCE1) sl@0: { sl@0: DPRINT(("Block's start fence corrupted, addr = %p\n", ptr)); sl@0: } sl@0: if (block->memory[block->nInts-1] != (OWFint)FENCE2) sl@0: { sl@0: DPRINT(("Block's end fence corrupted, addr = %p\n", ptr)); sl@0: } sl@0: sl@0: /* valid block, unlink & free it */ sl@0: if (prev) sl@0: { sl@0: prev->next = temp->next; sl@0: } sl@0: else sl@0: { sl@0: OWF_Memory_SetManagedBlocks(temp->next); sl@0: } sl@0: free(block); sl@0: } sl@0: else sl@0: { sl@0: /* possibly already freed, strangled pointer. complain. */ sl@0: DPRINT(("Block possibly freed already! (block = %p, addr = %p)\n", sl@0: (void*) block, ptr)); sl@0: } sl@0: } sl@0: OWF_Memory_UnlockManagedBlocks(); sl@0: sl@0: } sl@0: sl@0: OWF_API_CALL void sl@0: OWF_Memory_BlockDump() sl@0: { sl@0: BLOCK* block = OWF_Memory_GetManagedBlocks(); sl@0: sl@0: /* managed blocks locked when this is executed */ sl@0: sl@0: while (block) sl@0: { sl@0: BLOCK* next = (BLOCK*) block->next; sl@0: if (MAGIK == block->magik) sl@0: { sl@0: DPRINT(("Block: %p\nFile: %s(%d)\nSize: %u bytes\n", sl@0: (void*) &block->memory[1], sl@0: block->file, sl@0: block->line, sl@0: block->size)); sl@0: } sl@0: else sl@0: { sl@0: DPRINT(("Possibly corrupt or invalid block (addr = %p)\n", sl@0: (void*) block)); sl@0: } sl@0: block = next; sl@0: } sl@0: } sl@0: sl@0: #ifdef DEBUG sl@0: static void sl@0: OWF_Memory_Shutdown() sl@0: { sl@0: BLOCK* block = NULL; sl@0: sl@0: OWF_Memory_LockManagedBlocks(); sl@0: { sl@0: sl@0: if (OWF_Memory_GetManagedBlocks()) sl@0: { sl@0: DPRINT(("======================================================================\n"));DPRINT(("MEMORY LEAK REPORT\n"));DPRINT(("======================================================================\n")); sl@0: OWF_Memory_BlockDump(); sl@0: block = OWF_Memory_GetManagedBlocks(); sl@0: while (block) sl@0: { sl@0: BLOCK* next = (BLOCK*) block->next; sl@0: if (MAGIK == block->magik) sl@0: { sl@0: free(block); sl@0: } sl@0: block = next; sl@0: } sl@0: OWF_Memory_SetManagedBlocks(NULL); sl@0: } sl@0: sl@0: } sl@0: OWF_Memory_UnlockManagedBlocks(); sl@0: } sl@0: #endif sl@0: #endif sl@0: sl@0: #ifdef __cplusplus sl@0: } sl@0: #endif