mirror of
https://github.com/holub/mame
synced 2025-10-06 17:08:28 +03:00
Oops, forgot these files.
This commit is contained in:
parent
91a1b8d634
commit
ab68710ce5
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -564,6 +564,8 @@ src/emu/eigccppc.h svneol=native#text/plain
|
|||||||
src/emu/eigccx86.h svneol=native#text/plain
|
src/emu/eigccx86.h svneol=native#text/plain
|
||||||
src/emu/eminline.h svneol=native#text/plain
|
src/emu/eminline.h svneol=native#text/plain
|
||||||
src/emu/emu.mak svneol=native#text/plain
|
src/emu/emu.mak svneol=native#text/plain
|
||||||
|
src/emu/emualloc.c svneol=native#text/plain
|
||||||
|
src/emu/emualloc.h svneol=native#text/plain
|
||||||
src/emu/emucore.c svneol=native#text/plain
|
src/emu/emucore.c svneol=native#text/plain
|
||||||
src/emu/emucore.h svneol=native#text/plain
|
src/emu/emucore.h svneol=native#text/plain
|
||||||
src/emu/emuopts.c svneol=native#text/plain
|
src/emu/emuopts.c svneol=native#text/plain
|
||||||
|
601
src/emu/emualloc.c
Normal file
601
src/emu/emualloc.c
Normal file
@ -0,0 +1,601 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
emualloc.c
|
||||||
|
|
||||||
|
Memory allocation helpers for the core emulator.
|
||||||
|
|
||||||
|
****************************************************************************
|
||||||
|
|
||||||
|
Copyright Aaron Giles
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name 'MAME' nor the names of its contributors may be
|
||||||
|
used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "emucore.h"
|
||||||
|
#include "coreutil.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
TYPE DEFINITIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
// this struct is allocated in pools to track memory allocations
|
||||||
|
// it must be a POD type!!
|
||||||
|
class memory_entry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
memory_entry * next; // link to the next entry
|
||||||
|
memory_entry * prev; // link to the previous entry
|
||||||
|
size_t size; // size of the allocation (not including this header)
|
||||||
|
void * base; // base of the allocation
|
||||||
|
const char * file; // file the allocation was made from
|
||||||
|
int line; // line number within that file
|
||||||
|
int id; // unique id
|
||||||
|
|
||||||
|
static const int hash_prime = 193;
|
||||||
|
|
||||||
|
static int curid; // current ID
|
||||||
|
static osd_lock * lock; // lock for managing the list
|
||||||
|
static bool lock_alloc; // set to true temporarily during lock allocation
|
||||||
|
static memory_entry *hash[hash_prime];// hash table based on pointer
|
||||||
|
static memory_entry *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
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
// global resource pool to handle allocations outside of the emulator context
|
||||||
|
resource_pool global_resource_pool;
|
||||||
|
|
||||||
|
// dummy zeromem object
|
||||||
|
const zeromem_t zeromem = { };
|
||||||
|
|
||||||
|
// globals for memory_entry
|
||||||
|
int memory_entry::curid = 0;
|
||||||
|
osd_lock *memory_entry::lock = NULL;
|
||||||
|
bool memory_entry::lock_alloc = false;
|
||||||
|
memory_entry *memory_entry::hash[memory_entry::hash_prime] = { NULL };
|
||||||
|
memory_entry *memory_entry::freehead = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
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;
|
||||||
|
|
||||||
|
#ifdef MAME_DEBUG
|
||||||
|
// add a new entry
|
||||||
|
memory_entry::allocate(size, result, file, line);
|
||||||
|
|
||||||
|
// randomize the memory
|
||||||
|
rand_memory(result, 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)
|
||||||
|
{
|
||||||
|
#ifdef MAME_DEBUG
|
||||||
|
// 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!\n");
|
||||||
|
osd_break_into_debugger("Error: attempt to free untracked memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// free the entry and the memory
|
||||||
|
if (entry != NULL)
|
||||||
|
memory_entry::release(entry);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
osd_free(memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
dump_unfreed_mem - called from the exit path
|
||||||
|
of any code that wants to check for unfreed
|
||||||
|
memory
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void dump_unfreed_mem(void)
|
||||||
|
{
|
||||||
|
#ifdef MAME_DEBUG
|
||||||
|
memory_entry::report_unfreed();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
RESOURCE POOL
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
resource_pool - constructor for a new resource
|
||||||
|
pool
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
resource_pool::resource_pool()
|
||||||
|
: listlock(osd_lock_alloc())
|
||||||
|
{
|
||||||
|
memset(hash, 0, sizeof(hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
~resource_pool - destructor for a resource
|
||||||
|
pool; make sure all tracked objects are
|
||||||
|
deleted
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
resource_pool::~resource_pool()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
if (listlock != NULL)
|
||||||
|
osd_lock_free(listlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
add - add a new item to the resource pool
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void resource_pool::add(resource_pool_item &item)
|
||||||
|
{
|
||||||
|
osd_lock_acquire(listlock);
|
||||||
|
int hashval = reinterpret_cast<FPTR>(item.ptr) % hash_prime;
|
||||||
|
item.next = hash[hashval];
|
||||||
|
hash[hashval] = &item;
|
||||||
|
osd_lock_release(listlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
remove - remove a specific item from the
|
||||||
|
resource pool
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void resource_pool::remove(void *ptr)
|
||||||
|
{
|
||||||
|
// ignore NULLs
|
||||||
|
if (ptr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// search for the item
|
||||||
|
osd_lock_acquire(listlock);
|
||||||
|
|
||||||
|
int hashval = reinterpret_cast<FPTR>(ptr) % hash_prime;
|
||||||
|
for (resource_pool_item **scanptr = &hash[hashval]; *scanptr != NULL; scanptr = &(*scanptr)->next)
|
||||||
|
|
||||||
|
// must match the pointer
|
||||||
|
if ((*scanptr)->ptr == ptr)
|
||||||
|
{
|
||||||
|
resource_pool_item *deleteme = *scanptr;
|
||||||
|
*scanptr = deleteme->next;
|
||||||
|
delete deleteme;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osd_lock_release(listlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
find - find a specific item in the resource
|
||||||
|
pool
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
resource_pool_item *resource_pool::find(void *ptr)
|
||||||
|
{
|
||||||
|
// search for the item
|
||||||
|
osd_lock_acquire(listlock);
|
||||||
|
|
||||||
|
int hashval = reinterpret_cast<FPTR>(ptr) % hash_prime;
|
||||||
|
resource_pool_item *item;
|
||||||
|
for (item = hash[hashval]; item != NULL; item = item->next)
|
||||||
|
if (item->ptr == ptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
osd_lock_release(listlock);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
contains - return true if given ptr is
|
||||||
|
contained by one of the objects in the pool
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
bool resource_pool::contains(void *_ptrstart, void *_ptrend)
|
||||||
|
{
|
||||||
|
UINT8 *ptrstart = reinterpret_cast<UINT8 *>(_ptrstart);
|
||||||
|
UINT8 *ptrend = reinterpret_cast<UINT8 *>(_ptrend);
|
||||||
|
|
||||||
|
// search for the item
|
||||||
|
osd_lock_acquire(listlock);
|
||||||
|
|
||||||
|
resource_pool_item *item = NULL;
|
||||||
|
for (int hashval = 0; hashval < hash_prime; hashval++)
|
||||||
|
for (item = hash[hashval]; item != NULL; item = item->next)
|
||||||
|
{
|
||||||
|
UINT8 *objstart = reinterpret_cast<UINT8 *>(item->ptr);
|
||||||
|
UINT8 *objend = objstart + item->size;
|
||||||
|
if (ptrstart >= objstart && ptrend <= objend)
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
|
osd_lock_release(listlock);
|
||||||
|
|
||||||
|
return (item != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
clear - remove all items from a resource pool
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void resource_pool::clear()
|
||||||
|
{
|
||||||
|
osd_lock_acquire(listlock);
|
||||||
|
for (int hashval = 0; hashval < hash_prime; hashval++)
|
||||||
|
while (hash[hashval] != NULL)
|
||||||
|
{
|
||||||
|
resource_pool_item *deleteme = hash[hashval];
|
||||||
|
hash[hashval] = deleteme->next;
|
||||||
|
delete deleteme;
|
||||||
|
}
|
||||||
|
osd_lock_release(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 (lock == NULL)
|
||||||
|
{
|
||||||
|
if (lock_alloc)
|
||||||
|
return;
|
||||||
|
lock_alloc = true;
|
||||||
|
lock = osd_lock_alloc();
|
||||||
|
lock_alloc = false;
|
||||||
|
}
|
||||||
|
osd_lock_acquire(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
release_lock - release the memory entry lock
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void memory_entry::release_lock()
|
||||||
|
{
|
||||||
|
osd_lock_release(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 (freehead == NULL)
|
||||||
|
{
|
||||||
|
// create a new chunk, and fail if we can't
|
||||||
|
memory_entry *entry = reinterpret_cast<memory_entry *>(osd_malloc(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->next = freehead;
|
||||||
|
freehead = entry++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// grab a free entry
|
||||||
|
memory_entry *entry = freehead;
|
||||||
|
freehead = entry->next;
|
||||||
|
|
||||||
|
// populate it
|
||||||
|
entry->size = size;
|
||||||
|
entry->base = base;
|
||||||
|
entry->file = file;
|
||||||
|
entry->line = line;
|
||||||
|
entry->id = curid++;
|
||||||
|
|
||||||
|
// add it to the alloc list
|
||||||
|
int hashval = reinterpret_cast<FPTR>(base) % hash_prime;
|
||||||
|
entry->next = hash[hashval];
|
||||||
|
if (entry->next != NULL)
|
||||||
|
entry->next->prev = entry;
|
||||||
|
entry->prev = NULL;
|
||||||
|
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) % hash_prime;
|
||||||
|
memory_entry *entry;
|
||||||
|
for (entry = hash[hashval]; entry != NULL; entry = entry->next)
|
||||||
|
if (entry->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->base) % hash_prime;
|
||||||
|
if (entry->prev != NULL)
|
||||||
|
entry->prev->next = entry->next;
|
||||||
|
else
|
||||||
|
hash[hashval] = entry->next;
|
||||||
|
if (entry->next != NULL)
|
||||||
|
entry->next->prev = entry->prev;
|
||||||
|
|
||||||
|
// add ourself to the free list
|
||||||
|
entry->next = freehead;
|
||||||
|
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 hashval = 0; hashval < hash_prime; hashval++)
|
||||||
|
for (memory_entry *entry = hash[hashval]; entry; entry = entry->next)
|
||||||
|
if (entry->file != NULL)
|
||||||
|
{
|
||||||
|
if (total == 0)
|
||||||
|
fprintf(stderr, "--- memory leak warning ---\n");
|
||||||
|
total += entry->size;
|
||||||
|
fprintf(stderr, "allocation #%06d, %d bytes (%s:%d)\n", entry->id, static_cast<UINT32>(entry->size), entry->file, (int)entry->line);
|
||||||
|
}
|
||||||
|
|
||||||
|
release_lock();
|
||||||
|
|
||||||
|
if (total > 0)
|
||||||
|
fprintf(stderr, "a total of %d bytes were not free()'d\n", total);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
STANDARD NEW/DELETE OPERATORS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
void *operator new(std::size_t size) throw (std::bad_alloc)
|
||||||
|
{
|
||||||
|
void *result = malloc_file_line(size, NULL, 0);
|
||||||
|
if (result == NULL)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *operator new[](std::size_t size) throw (std::bad_alloc)
|
||||||
|
{
|
||||||
|
void *result = malloc_file_line(size, NULL, 0);
|
||||||
|
if (result == NULL)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void operator delete(void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr != NULL)
|
||||||
|
free_file_line(ptr, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void operator delete[](void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr != NULL)
|
||||||
|
free_file_line(ptr, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
POOL NEW/DELETE OPERATORS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
void *operator new(std::size_t size, const char *file, int line) throw (std::bad_alloc)
|
||||||
|
{
|
||||||
|
void *result = malloc_file_line(size, file, line);
|
||||||
|
if (result == NULL)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *operator new[](std::size_t size, const char *file, int line) throw (std::bad_alloc)
|
||||||
|
{
|
||||||
|
void *result = malloc_file_line(size, file, line);
|
||||||
|
if (result == NULL)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void operator delete(void *ptr, const char *file, int line)
|
||||||
|
{
|
||||||
|
if (ptr != NULL)
|
||||||
|
free_file_line(ptr, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void operator delete[](void *ptr, const char *file, int line)
|
||||||
|
{
|
||||||
|
if (ptr != NULL)
|
||||||
|
free_file_line(ptr, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
POOL NEW/DELETE OPERATORS WITH ZEROING
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
void *operator new(std::size_t size, const char *file, int line, const zeromem_t &) throw (std::bad_alloc)
|
||||||
|
{
|
||||||
|
void *result = malloc_file_line(size, file, line);
|
||||||
|
if (result == NULL)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
memset(result, 0, size);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *operator new[](std::size_t size, const char *file, int line, const zeromem_t &) throw (std::bad_alloc)
|
||||||
|
{
|
||||||
|
void *result = malloc_file_line(size, file, line);
|
||||||
|
if (result == NULL)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
memset(result, 0, size);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void operator delete(void *ptr, const char *file, int line, const zeromem_t &)
|
||||||
|
{
|
||||||
|
if (ptr != NULL)
|
||||||
|
free_file_line(ptr, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void operator delete[](void *ptr, const char *file, int line, const zeromem_t &)
|
||||||
|
{
|
||||||
|
if (ptr != NULL)
|
||||||
|
free_file_line(ptr, file, line);
|
||||||
|
}
|
222
src/emu/emualloc.h
Normal file
222
src/emu/emualloc.h
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
emualloc.h
|
||||||
|
|
||||||
|
Memory allocation helpers for the core emulator.
|
||||||
|
|
||||||
|
****************************************************************************
|
||||||
|
|
||||||
|
Copyright Aaron Giles
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name 'MAME' nor the names of its contributors may be
|
||||||
|
used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __EMUALLOC_H__
|
||||||
|
#define __EMUALLOC_H__
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include "osdcore.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
TYPE DEFINITIONS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
// zeromem_t is a dummy class used to tell new to zero memory after allocation
|
||||||
|
class zeromem_t { };
|
||||||
|
|
||||||
|
|
||||||
|
// resource_pool_item is a base class for items that are tracked by a resource pool
|
||||||
|
class resource_pool_item
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
resource_pool_item(const resource_pool_item &);
|
||||||
|
resource_pool_item &operator=(const resource_pool_item &);
|
||||||
|
|
||||||
|
public:
|
||||||
|
resource_pool_item(void *_ptr, size_t _size)
|
||||||
|
: next(NULL),
|
||||||
|
ptr(_ptr),
|
||||||
|
size(_size) { }
|
||||||
|
virtual ~resource_pool_item() { }
|
||||||
|
|
||||||
|
resource_pool_item * next;
|
||||||
|
void * ptr;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// a resource_pool_object is a simple object wrapper for the templatized type
|
||||||
|
template<class T> class resource_pool_object : public resource_pool_item
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
resource_pool_object<T>(const resource_pool_object<T> &);
|
||||||
|
resource_pool_object<T> &operator=(const resource_pool_object<T> &);
|
||||||
|
|
||||||
|
public:
|
||||||
|
resource_pool_object(T *_object)
|
||||||
|
: resource_pool_item(reinterpret_cast<void *>(_object), sizeof(T)),
|
||||||
|
object(_object) { }
|
||||||
|
virtual ~resource_pool_object() { delete object; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T *object;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// a resource_pool_array is a simple object wrapper for an allocated array of
|
||||||
|
// the templatized type
|
||||||
|
template<class T> class resource_pool_array : public resource_pool_item
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
resource_pool_array<T>(const resource_pool_array<T> &);
|
||||||
|
resource_pool_array<T> &operator=(const resource_pool_array<T> &);
|
||||||
|
|
||||||
|
public:
|
||||||
|
resource_pool_array(T *_array, int _count)
|
||||||
|
: resource_pool_item(reinterpret_cast<void *>(_array), sizeof(T) * _count),
|
||||||
|
array(_array),
|
||||||
|
count(_count) { }
|
||||||
|
virtual ~resource_pool_array() { delete[] array; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T *array;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// a resource pool tracks items and frees them upon reset or destruction
|
||||||
|
class resource_pool
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
resource_pool(const resource_pool &);
|
||||||
|
resource_pool &operator=(const resource_pool &);
|
||||||
|
|
||||||
|
public:
|
||||||
|
resource_pool();
|
||||||
|
~resource_pool();
|
||||||
|
|
||||||
|
void add(resource_pool_item &item);
|
||||||
|
void remove(resource_pool_item &item) { remove(item.ptr); }
|
||||||
|
void remove(void *ptr);
|
||||||
|
void remove(const void *ptr) { remove(const_cast<void *>(ptr)); }
|
||||||
|
resource_pool_item *find(void *ptr);
|
||||||
|
bool contains(void *ptrstart, void *ptrend);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
template<class T> T *add_object(T* object) { add(*new(__FILE__, __LINE__) resource_pool_object<T>(object)); return object; }
|
||||||
|
template<class T> T *add_array(T* array, int count) { add(*new(__FILE__, __LINE__) resource_pool_array<T>(array, count)); return array; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const int hash_prime = 193;
|
||||||
|
|
||||||
|
resource_pool_item * hash[hash_prime];
|
||||||
|
osd_lock * listlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
MACROS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
// re-route classic malloc-style allocations
|
||||||
|
#undef malloc
|
||||||
|
#undef calloc
|
||||||
|
#undef realloc
|
||||||
|
#undef free
|
||||||
|
|
||||||
|
#define malloc(x) __error_use_auto_alloc_or_global_alloc_instead__
|
||||||
|
#define calloc(x,y) __error_use_auto_alloc_clear_or_global_alloc_clear_instead__
|
||||||
|
#define realloc(x,y) __error_realloc_is_dangerous__
|
||||||
|
#define free(x) __error_use_auto_free_or_global_free_instead__
|
||||||
|
|
||||||
|
// pool allocation helpers
|
||||||
|
#define pool_alloc(_pool, _type) (_pool).add_object(new(__FILE__, __LINE__) _type)
|
||||||
|
#define pool_alloc_clear(_pool, _type) (_pool).add_object(new(__FILE__, __LINE__, zeromem) _type)
|
||||||
|
#define pool_alloc_array(_pool, _type, _num) (_pool).add_array(new(__FILE__, __LINE__) _type[_num], (_num))
|
||||||
|
#define pool_alloc_array_clear(_pool, _type, _num) (_pool).add_array(new(__FILE__, __LINE__, zeromem) _type[_num], (_num))
|
||||||
|
#define pool_free(_pool, v) (_pool).remove(v)
|
||||||
|
|
||||||
|
// global allocation helpers
|
||||||
|
#define global_alloc(_type) pool_alloc(global_resource_pool, _type)
|
||||||
|
#define global_alloc_clear(_type) pool_alloc_clear(global_resource_pool, _type)
|
||||||
|
#define global_alloc_array(_type, _num) pool_alloc_array(global_resource_pool, _type, _num)
|
||||||
|
#define global_alloc_array_clear(_type, _num) pool_alloc_array_clear(global_resource_pool, _type, _num)
|
||||||
|
#define global_free(v) pool_free(global_resource_pool, v)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
GLOBAL VARIABLES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
// global resource pool
|
||||||
|
extern resource_pool global_resource_pool;
|
||||||
|
|
||||||
|
// dummy objects to pass to the specialized new variants
|
||||||
|
extern const zeromem_t zeromem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
FUNCTION PROTOTYPES
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
// allocate memory with file and line number information
|
||||||
|
void *malloc_file_line(size_t size, const char *file, int line);
|
||||||
|
|
||||||
|
// free memory with file and line number information
|
||||||
|
void free_file_line(void *memory, const char *file, int line);
|
||||||
|
|
||||||
|
// called from the exit path of any code that wants to check for unfreed memory
|
||||||
|
void dump_unfreed_mem();
|
||||||
|
|
||||||
|
// standard new/delete operators (try to avoid using)
|
||||||
|
void *operator new(std::size_t size) throw (std::bad_alloc);
|
||||||
|
void *operator new[](std::size_t size) throw (std::bad_alloc);
|
||||||
|
void operator delete(void *ptr);
|
||||||
|
void operator delete[](void *ptr);
|
||||||
|
|
||||||
|
// file/line new/delete operators
|
||||||
|
void *operator new(std::size_t size, const char *file, int line) throw (std::bad_alloc);
|
||||||
|
void *operator new[](std::size_t size, const char *file, int line) throw (std::bad_alloc);
|
||||||
|
void operator delete(void *ptr, const char *file, int line);
|
||||||
|
void operator delete[](void *ptr, const char *file, int line);
|
||||||
|
|
||||||
|
// file/line new/delete operators with zeroing
|
||||||
|
void *operator new(std::size_t size, const char *file, int line, const zeromem_t &) throw (std::bad_alloc);
|
||||||
|
void *operator new[](std::size_t size, const char *file, int line, const zeromem_t &) throw (std::bad_alloc);
|
||||||
|
void operator delete(void *ptr, const char *file, int line, const zeromem_t &);
|
||||||
|
void operator delete[](void *ptr, const char *file, int line, const zeromem_t &);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __EMUALLOC_H__ */
|
Loading…
Reference in New Issue
Block a user