diff options
Diffstat (limited to 'src/emu/emualloc.c')
-rw-r--r-- | src/emu/emualloc.c | 370 |
1 files changed, 6 insertions, 364 deletions
diff --git a/src/emu/emualloc.c b/src/emu/emualloc.c index 22c0e044fed..adf6cd21419 100644 --- a/src/emu/emualloc.c +++ b/src/emu/emualloc.c @@ -21,195 +21,10 @@ //************************************************************************** -// CONSTANTS -//************************************************************************** - -// align all allocated memory to this size -//const int memory_align = 16; - -// number of memory_entries to allocate in a block -const int memory_block_alloc_chunk = 256; - - - -//************************************************************************** -// MACROS -//************************************************************************** - -// enable deletion -#undef delete - - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// this struct is allocated in pools to track memory allocations -// it must be a POD type!! -class memory_entry -{ -public: - memory_entry * m_next; // link to the next entry - memory_entry * m_prev; // link to the previous entry - size_t m_size; // size of the allocation (not including this header) - void * m_base; // base of the allocation - const char * m_file; // file the allocation was made from - int m_line; // line number within that file - UINT64 m_id; // unique id - - static const int k_hash_prime = 6151; - - static UINT64 s_curid; // current ID - static osd_lock * s_lock; // lock for managing the list - static bool s_lock_alloc; // set to true temporarily during lock allocation - static bool s_tracking; // set to true when tracking is live - static memory_entry *s_hash[k_hash_prime];// hash table based on pointer - static memory_entry *s_freehead; // pointer to the head of the free list - - static memory_entry *allocate(size_t size, void *base, const char *file, int line); - static memory_entry *find(void *ptr); - static void release(memory_entry *entry); - static void report_unfreed(); - -private: - static void acquire_lock(); - static void release_lock(); -}; - - - -//************************************************************************** // GLOBALS //************************************************************************** -// dummy zeromem object -const zeromem_t zeromem = { }; - -// globals for memory_entry -UINT64 memory_entry::s_curid = 1; -osd_lock *memory_entry::s_lock = NULL; -bool memory_entry::s_lock_alloc = false; -bool memory_entry::s_tracking = false; -memory_entry *memory_entry::s_hash[memory_entry::k_hash_prime] = { NULL }; -memory_entry *memory_entry::s_freehead = NULL; - -// wrapper for the global resource pool to help ensure construction order -resource_pool &global_resource_pool() -{ - static resource_pool s_pool(6151); - return s_pool; -}; - - -//************************************************************************** -// GLOBAL HELPERS -//************************************************************************** - -//------------------------------------------------- -// malloc_file_line - allocate memory with file -// and line number information -//------------------------------------------------- - -void *malloc_file_line(size_t size, const char *file, int line) -{ - // allocate the memory and fail if we can't - void *result = osd_malloc(size); - if (result == NULL) - return NULL; - - // add a new entry - memory_entry::allocate(size, result, file, line); - -#if !__has_feature(memory_sanitizer) && defined(MAME_DEBUG) - memset(result, 0xdd, size); -#endif - - return result; -} - - -//------------------------------------------------- -// malloc_array_file_line - allocate memory with -// file and line number information, and a hint -// that this object is an array -//------------------------------------------------- - -void *malloc_array_file_line(size_t size, const char *file, int line) -{ - // allocate the memory and fail if we can't - void *result = osd_malloc_array(size); - if (result == NULL) - return NULL; - - // add a new entry - memory_entry::allocate(size, result, file, line); - -#if !__has_feature(memory_sanitizer) && defined(MAME_DEBUG) - memset(result, 0xdd, size); -#endif - - return result; -} - - -//------------------------------------------------- -// free_file_line - free memory with file -// and line number information -//------------------------------------------------- - -void free_file_line(void *memory, const char *file, int line) -{ - // ignore NULL frees/deletes - if (memory == NULL) - return; - - // find the memory entry - memory_entry *entry = memory_entry::find(memory); - - // warn about untracked frees - if (entry == NULL) - { - fprintf(stderr, "Error: attempt to free untracked memory in %s(%d)!\n", file, line); - osd_break_into_debugger("Error: attempt to free untracked memory"); - return; - } - -#ifdef MAME_DEBUG - // clear memory to a bogus value - memset(memory, 0xfc, entry->m_size); -#endif - - // free the entry and the memory - memory_entry::release(entry); - osd_free(memory); -} - - -//------------------------------------------------- -// dump_unfreed_mem - called from the exit path -// of any code that wants to check for unfreed -// memory -//------------------------------------------------- - -void track_memory(bool track) -{ - memory_entry::s_tracking = track; -} - - -//------------------------------------------------- -// dump_unfreed_mem - called from the exit path -// of any code that wants to check for unfreed -// memory -//------------------------------------------------- - -void dump_unfreed_mem() -{ -#ifdef MAME_DEBUG - memory_entry::report_unfreed(); -#endif -} +UINT64 resource_pool::s_id = 0; @@ -225,11 +40,10 @@ void dump_unfreed_mem() resource_pool::resource_pool(int hash_size) : m_hash_size(hash_size), m_listlock(osd_lock_alloc()), - m_hash(new resource_pool_item *[hash_size]), + m_hash(hash_size, 0), m_ordered_head(NULL), m_ordered_tail(NULL) { - memset(m_hash, 0, hash_size * sizeof(m_hash[0])); } @@ -244,7 +58,6 @@ resource_pool::~resource_pool() clear(); if (m_listlock != NULL) osd_lock_free(m_listlock); - delete[] m_hash; } @@ -252,7 +65,7 @@ resource_pool::~resource_pool() // add - add a new item to the resource pool //------------------------------------------------- -void resource_pool::add(resource_pool_item &item) +void resource_pool::add(resource_pool_item &item, size_t size, const char *type) { osd_lock_acquire(m_listlock); @@ -263,13 +76,9 @@ void resource_pool::add(resource_pool_item &item) // fetch the ID of this item's pointer; some implementations put hidden data // before, so if we don't find it, check 4 bytes ahead - memory_entry *entry = memory_entry::find(item.m_ptr); - if (entry == NULL) - entry = memory_entry::find(reinterpret_cast<UINT8 *>(item.m_ptr) - sizeof(size_t)); - assert(entry != NULL); - item.m_id = entry->m_id; + item.m_id = ++s_id; if (LOG_ALLOCS) - fprintf(stderr, "#%06d, add %d bytes (%s:%d)\n", (UINT32)entry->m_id, static_cast<UINT32>(entry->m_size), entry->m_file, (int)entry->m_line); + fprintf(stderr, "#%06d, add %s, %d bytes\n", (UINT32)item.m_id, type, size); // find the entry to insert after resource_pool_item *insert_after; @@ -340,7 +149,7 @@ void resource_pool::remove(void *ptr) // delete the object and break if (LOG_ALLOCS) fprintf(stderr, "#%06d, delete %d bytes\n", (UINT32)deleteme->m_id, static_cast<UINT32>(deleteme->m_size)); - delete deleteme; + global_free(deleteme); break; } @@ -414,170 +223,3 @@ void resource_pool::clear() osd_lock_release(m_listlock); } - - - -//************************************************************************** -// MEMORY ENTRY -//************************************************************************** - -//------------------------------------------------- -// acquire_lock - acquire the memory entry lock, -// creating a new one if needed -//------------------------------------------------- - -void memory_entry::acquire_lock() -{ - // allocate a lock on first usage - // note that osd_lock_alloc() may re-enter this path, so protect against recursion! - if (s_lock == NULL) - { - if (s_lock_alloc) - return; - s_lock_alloc = true; - s_lock = osd_lock_alloc(); - s_lock_alloc = false; - } - osd_lock_acquire(s_lock); -} - - -//------------------------------------------------- -// release_lock - release the memory entry lock -//------------------------------------------------- - -void memory_entry::release_lock() -{ - osd_lock_release(s_lock); -} - - -//------------------------------------------------- -// allocate - allocate a new memory entry -//------------------------------------------------- - -memory_entry *memory_entry::allocate(size_t size, void *base, const char *file, int line) -{ - acquire_lock(); - - // if we're out of free entries, allocate a new chunk - if (s_freehead == NULL) - { - // create a new chunk, and fail if we can't - memory_entry *entry = reinterpret_cast<memory_entry *>(osd_malloc_array(memory_block_alloc_chunk * sizeof(memory_entry))); - if (entry == NULL) - { - release_lock(); - return NULL; - } - - // add all the entries to the list - for (int entrynum = 0; entrynum < memory_block_alloc_chunk; entrynum++) - { - entry->m_next = s_freehead; - s_freehead = entry++; - } - } - - // grab a free entry - memory_entry *entry = s_freehead; - s_freehead = entry->m_next; - - // populate it - entry->m_size = size; - entry->m_base = base; - entry->m_file = s_tracking ? file : NULL; - entry->m_line = s_tracking ? line : 0; - entry->m_id = s_curid++; - if (LOG_ALLOCS) - fprintf(stderr, "#%06d, alloc %d bytes (%s:%d)\n", (UINT32)entry->m_id, static_cast<UINT32>(entry->m_size), entry->m_file, (int)entry->m_line); - - // add it to the alloc list - int hashval = reinterpret_cast<FPTR>(base) % k_hash_prime; - entry->m_next = s_hash[hashval]; - if (entry->m_next != NULL) - entry->m_next->m_prev = entry; - entry->m_prev = NULL; - s_hash[hashval] = entry; - - release_lock(); - return entry; -} - - -//------------------------------------------------- -// find - find a memory entry -//------------------------------------------------- - -memory_entry *memory_entry::find(void *ptr) -{ - // NULL maps to nothing - if (ptr == NULL) - return NULL; - - // scan the list under the lock - acquire_lock(); - - int hashval = reinterpret_cast<FPTR>(ptr) % k_hash_prime; - memory_entry *entry; - for (entry = s_hash[hashval]; entry != NULL; entry = entry->m_next) - if (entry->m_base == ptr) - break; - - release_lock(); - return entry; -} - - -//------------------------------------------------- -// release - release a memory entry -//------------------------------------------------- - -void memory_entry::release(memory_entry *entry) -{ - acquire_lock(); - - // remove ourselves from the alloc list - int hashval = reinterpret_cast<FPTR>(entry->m_base) % k_hash_prime; - if (entry->m_prev != NULL) - entry->m_prev->m_next = entry->m_next; - else - s_hash[hashval] = entry->m_next; - if (entry->m_next != NULL) - entry->m_next->m_prev = entry->m_prev; - - // add ourself to the free list - entry->m_next = s_freehead; - s_freehead = entry; - - release_lock(); -} - - -//------------------------------------------------- -// report_unfreed - print a list of unfreed -// memory to the target file -//------------------------------------------------- - -void memory_entry::report_unfreed() -{ - acquire_lock(); - - // check for leaked memory - UINT32 total = 0; - - for (int hashnum = 0; hashnum < k_hash_prime; hashnum++) - for (memory_entry *entry = s_hash[hashnum]; entry != NULL; entry = entry->m_next) - if (entry->m_file != NULL) - { - if (total == 0) - fprintf(stderr, "--- memory leak warning ---\n"); - total += entry->m_size; - fprintf(stderr, "#%06d, nofree %d bytes (%s:%d)\n", (UINT32)entry->m_id, static_cast<UINT32>(entry->m_size), entry->m_file, (int)entry->m_line); - } - - release_lock(); - - if (total > 0) - fprintf(stderr, "a total of %u bytes were not freed\n", total); -} |