mirror of
https://github.com/holub/mame
synced 2025-05-21 21:29:15 +03:00

This update changes the way we handle memory allocation. Rather than allocating in terms of bytes, allocations are now done in terms of objects. This is done via new set of macros that replace the malloc_or_die() macro: alloc_or_die(t) - allocate memory for an object of type 't' alloc_array_or_die(t,c) - allocate memory for an array of 'c' objects of type 't' alloc_clear_or_die(t) - same as alloc_or_die but memset's the memory to 0 alloc_array_clear_or_die(t,c) - same as alloc_array_or_die but memset's the memory to 0 All original callers of malloc_or_die have been updated to call these new macros. If you just need an array of bytes, you can use alloc_array_or_die(UINT8, numbytes). Made a similar change to the auto_* allocation macros. In addition, added 'machine' as a required parameter to the auto-allocation macros, as the resource pools will eventually be owned by the machine object. The new macros are: auto_alloc(m,t) - allocate memory for an object of type 't' auto_alloc_array(m,t,c) - allocate memory for an array of 'c' objects of type 't' auto_alloc_clear(m,t) - allocate and memset auto_alloc_array_clear(m,t,c) - allocate and memset All original calls or auto_malloc have been updated to use the new macros. In addition, auto_realloc(), auto_strdup(), auto_astring_alloc(), and auto_bitmap_alloc() have been updated to take a machine parameter. Changed validity check allocations to not rely on auto_alloc* anymore because they are not done in the context of a machine. One final change that is included is the removal of SMH_BANKn macros. Just use SMH_BANK(n) instead, which is what the previous macros mapped to anyhow.
374 lines
10 KiB
C
374 lines
10 KiB
C
/***************************************************************************
|
|
|
|
restrack.c
|
|
|
|
Core MAME resource tracking.
|
|
|
|
Copyright Nicola Salmoria and the MAME Team.
|
|
Visit http://mamedev.org for licensing and usage restrictions.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "restrack.h"
|
|
#include "pool.h"
|
|
#include "timer.h"
|
|
#include "state.h"
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
TYPE DEFINITIONS
|
|
***************************************************************************/
|
|
|
|
enum _memory_block_overlap
|
|
{
|
|
OVERLAP_NONE,
|
|
OVERLAP_PARTIAL,
|
|
OVERLAP_FULL
|
|
};
|
|
typedef enum _memory_block_overlap memory_block_overlap;
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
GLOBAL VARIABLES
|
|
***************************************************************************/
|
|
|
|
/* pool list */
|
|
static object_pool *pools[64];
|
|
|
|
/* resource tracking */
|
|
int resource_tracking_tag = 0;
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
PROTOTYPES
|
|
***************************************************************************/
|
|
|
|
static void astring_destructor(void *object, size_t size);
|
|
static void bitmap_destructor(void *object, size_t size);
|
|
static memory_block_overlap pool_contains_block(object_pool *pool, void *ptr, size_t size, void **found_block, size_t *found_block_size);
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
CORE IMPLEMENTATION
|
|
***************************************************************************/
|
|
|
|
/*-------------------------------------------------
|
|
malloc_or_die_file_line - allocate memory or die
|
|
trying
|
|
-------------------------------------------------*/
|
|
|
|
void *malloc_or_die_file_line(size_t size, const char *file, int line)
|
|
{
|
|
void *result;
|
|
|
|
/* fail on attempted allocations of 0 */
|
|
if (size == 0)
|
|
fatalerror("Attempted to malloc zero bytes (%s:%d)", file, line);
|
|
|
|
/* allocate and return if we succeeded */
|
|
#ifdef MALLOC_DEBUG
|
|
result = malloc_file_line(size, file, line);
|
|
#else
|
|
result = malloc(size);
|
|
#endif
|
|
if (result != NULL)
|
|
{
|
|
#ifdef MAME_DEBUG
|
|
rand_memory(result, size);
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
/* otherwise, die horribly */
|
|
fatalerror("Failed to allocate %d bytes (%s:%d)", (int)size, file, line);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
init_resource_tracking - initialize the
|
|
resource tracking system
|
|
-------------------------------------------------*/
|
|
|
|
void init_resource_tracking(void)
|
|
{
|
|
resource_tracking_tag = 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
exit_resource_tracking - tear down the
|
|
resource tracking system
|
|
-------------------------------------------------*/
|
|
|
|
void exit_resource_tracking(void)
|
|
{
|
|
while (resource_tracking_tag != 0)
|
|
end_resource_tracking();
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
memory_error - report a memory error
|
|
-------------------------------------------------*/
|
|
|
|
static void memory_error(const char *message)
|
|
{
|
|
fatalerror("%s", message);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
begin_resource_tracking - start tracking
|
|
resources
|
|
-------------------------------------------------*/
|
|
|
|
void begin_resource_tracking(void)
|
|
{
|
|
object_pool *new_pool;
|
|
|
|
/* sanity check */
|
|
assert_always(resource_tracking_tag < ARRAY_LENGTH(pools), "Too many memory pools");
|
|
|
|
/* create a new pool */
|
|
new_pool = pool_alloc(memory_error);
|
|
if (!new_pool)
|
|
fatalerror("Failed to allocate new memory pool");
|
|
pools[resource_tracking_tag] = new_pool;
|
|
|
|
/* add resource types */
|
|
pool_type_register(new_pool, OBJTYPE_ASTRING, "String", astring_destructor);
|
|
pool_type_register(new_pool, OBJTYPE_BITMAP, "Bitmap", bitmap_destructor);
|
|
pool_type_register(new_pool, OBJTYPE_TIMER, "Timer", timer_destructor);
|
|
pool_type_register(new_pool, OBJTYPE_STATEREG, "Save State Registration", state_destructor);
|
|
|
|
/* increment the tag counter */
|
|
resource_tracking_tag++;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
end_resource_tracking - stop tracking
|
|
resources
|
|
-------------------------------------------------*/
|
|
|
|
void end_resource_tracking(void)
|
|
{
|
|
/* decrement the tag counter */
|
|
resource_tracking_tag--;
|
|
|
|
/* free the memory pool */
|
|
pool_free(pools[resource_tracking_tag]);
|
|
pools[resource_tracking_tag] = NULL;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
current_pool - identifies the current memory
|
|
pool
|
|
-------------------------------------------------*/
|
|
|
|
static object_pool *current_pool(void)
|
|
{
|
|
object_pool *pool;
|
|
assert_always((resource_tracking_tag > 0) && (resource_tracking_tag <= ARRAY_LENGTH(pools)), "Invalid resource_tracking_tag");
|
|
pool = pools[resource_tracking_tag - 1];
|
|
assert_always(pool != NULL, "current_pool() is NULL");
|
|
return pool;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
restrack_register_object - registers an
|
|
object with the current pool
|
|
-------------------------------------------------*/
|
|
|
|
void *restrack_register_object(object_type type, void *ptr, size_t size, const char *file, int line)
|
|
{
|
|
return pool_object_add_file_line(current_pool(), type, ptr, size, file, line);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
auto_malloc_file_line - allocate auto-
|
|
freeing memory
|
|
-------------------------------------------------*/
|
|
|
|
void *auto_malloc_file_line(running_machine *machine, size_t size, const char *file, int line)
|
|
{
|
|
void *result = pool_malloc_file_line(current_pool(), size, file, line);
|
|
#ifdef MAME_DEBUG
|
|
rand_memory(result, size);
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
auto_realloc_file_line - reallocate auto-
|
|
freeing memory
|
|
-------------------------------------------------*/
|
|
|
|
void *auto_realloc_file_line(running_machine *machine, void *ptr, size_t size, const char *file, int line)
|
|
{
|
|
object_pool *pool = current_pool();
|
|
if (ptr != NULL)
|
|
{
|
|
int tag = resource_tracking_tag;
|
|
for (; tag > 0; tag--)
|
|
{
|
|
pool = pools[tag - 1];
|
|
if (pool_object_exists(pool, OBJTYPE_MEMORY, ptr))
|
|
break;
|
|
}
|
|
assert_always(tag > 0, "Failed to find alloc in pool");
|
|
}
|
|
|
|
return pool_realloc_file_line(pool, ptr, size, file, line);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
auto_strdup_file_line - allocate auto-freeing
|
|
string
|
|
-------------------------------------------------*/
|
|
|
|
char *auto_strdup_file_line(running_machine *machine, const char *str, const char *file, int line)
|
|
{
|
|
return pool_strdup_file_line(current_pool(), str, file, line);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
auto_strdup_allow_null_file_line - allocate
|
|
auto-freeing string if str is null
|
|
-------------------------------------------------*/
|
|
|
|
char *auto_strdup_allow_null_file_line(running_machine *machine, const char *str, const char *file, int line)
|
|
{
|
|
return (str != NULL) ? auto_strdup_file_line(machine, str, file, line) : NULL;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
auto_astring_alloc_file_line - allocate
|
|
auto-freeing astring
|
|
-------------------------------------------------*/
|
|
|
|
astring *auto_astring_alloc_file_line(running_machine *machine, const char *file, int line)
|
|
{
|
|
return (astring *)restrack_register_object(OBJTYPE_ASTRING, astring_alloc(), 0, file, line);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
auto_bitmap_alloc_file_line - allocate
|
|
auto-freeing bitmap
|
|
-------------------------------------------------*/
|
|
|
|
bitmap_t *auto_bitmap_alloc_file_line(running_machine *machine, int width, int height, bitmap_format format, const char *file, int line)
|
|
{
|
|
return (bitmap_t *)restrack_register_object(OBJTYPE_BITMAP, bitmap_alloc(width, height, format), width * height, file, line);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
validate_auto_malloc_memory - validate that a
|
|
block of memory has been allocated by
|
|
auto_malloc()
|
|
-------------------------------------------------*/
|
|
|
|
void validate_auto_malloc_memory(void *memory, size_t memory_size)
|
|
{
|
|
memory_block_overlap overlap = OVERLAP_NONE;
|
|
void *block_base = NULL;
|
|
size_t block_size = 0;
|
|
int i;
|
|
|
|
/* scan all pools for an overlapping block */
|
|
for (i = 0; overlap == OVERLAP_NONE && i < resource_tracking_tag; i++)
|
|
overlap = pool_contains_block(pools[i], memory, memory_size, &block_base, &block_size);
|
|
|
|
/* fatal error if not a full overlap */
|
|
switch (overlap)
|
|
{
|
|
case OVERLAP_NONE:
|
|
fatalerror("Memory block [0x%p-0x%p] not found", memory, (UINT8 *)memory + memory_size - 1);
|
|
break;
|
|
|
|
case OVERLAP_PARTIAL:
|
|
fatalerror("Memory block [0x%p-0x%p] partially overlaps with allocated block [0x%p-0x%p]", memory, (UINT8 *)memory + memory_size - 1, block_base, (UINT8 *)block_base + block_size - 1);
|
|
break;
|
|
|
|
case OVERLAP_FULL:
|
|
/* expected outcome */
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
astring_destructor - destructor for astring
|
|
objects
|
|
-------------------------------------------------*/
|
|
|
|
static void astring_destructor(void *object, size_t size)
|
|
{
|
|
astring_free((astring *)object);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
bitmap_destructor - destructor for bitmap
|
|
objects
|
|
-------------------------------------------------*/
|
|
|
|
static void bitmap_destructor(void *object, size_t size)
|
|
{
|
|
bitmap_free((bitmap_t *)object);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
pool_contains_block - determines if a pool
|
|
contains a memory block
|
|
-------------------------------------------------*/
|
|
|
|
static memory_block_overlap pool_contains_block(object_pool *pool, void *ptr, size_t size, void **found_block, size_t *found_block_size)
|
|
{
|
|
memory_block_overlap overlap = OVERLAP_NONE;
|
|
object_pool_iterator *iter;
|
|
UINT8 *ptrstart = (UINT8 *)ptr;
|
|
UINT8 *ptrend = ptrstart + size - 1;
|
|
void *blockptr = NULL;
|
|
size_t blocksize = 0;
|
|
|
|
/* iterate over memory objects in the pool */
|
|
for (iter = pool_iterate_begin(pool, OBJTYPE_MEMORY); iter != NULL && pool_iterate_next(iter, &blockptr, &blocksize, NULL); )
|
|
{
|
|
int startwithin = (ptrstart >= (UINT8 *)blockptr && ptrstart < (UINT8 *)blockptr + blocksize);
|
|
int endwithin = (ptrend >= (UINT8 *)blockptr && ptrend < (UINT8 *)blockptr + blocksize);
|
|
|
|
/* if the start of the incoming pointer lies within the block... */
|
|
if (startwithin || endwithin)
|
|
{
|
|
overlap = (startwithin && endwithin) ? OVERLAP_FULL : OVERLAP_PARTIAL;
|
|
break;
|
|
}
|
|
}
|
|
pool_iterate_end(iter);
|
|
|
|
/* store the results */
|
|
if (overlap != OVERLAP_NONE)
|
|
{
|
|
if (found_block != NULL)
|
|
*found_block = blockptr;
|
|
if (found_block_size != NULL)
|
|
*found_block_size = blocksize;
|
|
}
|
|
return overlap;
|
|
}
|