mirror of
https://github.com/holub/mame
synced 2025-10-05 08:41:31 +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/eminline.h 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.h 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