(Windows only)

Added code to debug 64-bit builds to allocate all address space below 4GB to help find 64-bit errors.
Added environment variable OSDDEBUGMALLOC which, if set, explicitly overrides the debug malloc debug settings.
Added environment variable OSDDEBUG4GB which, if set, explicitly overrides the new 64-bit address space allocations.
(Sadly this is necessary due to my nvidia D3D drivers being 64-bit unclean....)
This commit is contained in:
Aaron Giles 2008-01-08 06:19:50 +00:00
parent 1ee549675e
commit a3b57f5fd5

View file

@ -12,6 +12,7 @@
// standard windows headers // standard windows headers
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <tchar.h>
// MAME headers // MAME headers
#include "osdcore.h" #include "osdcore.h"
@ -75,7 +76,21 @@ static memory_entry *free_list;
static int current_id; static int current_id;
static CRITICAL_SECTION memory_lock; static CRITICAL_SECTION memory_lock;
static UINT8 memory_lock_initialized = FALSE;
static UINT8 global_init_done = FALSE;
static UINT8 use_malloc_tracking = FALSE;
//============================================================
// PROTOTYPES
//============================================================
static memory_entry *allocate_entry(void);
static memory_entry *find_entry(void *pointer);
static void free_entry(memory_entry *entry);
static void global_init(void);
@ -83,13 +98,18 @@ static UINT8 memory_lock_initialized = FALSE;
// INLINES // INLINES
//============================================================ //============================================================
INLINE void global_init_if_not_done(void)
{
if (!global_init_done)
{
global_init_done = TRUE;
global_init();
}
}
INLINE void memory_lock_acquire(void) INLINE void memory_lock_acquire(void)
{ {
if (!memory_lock_initialized)
{
memory_lock_initialized = TRUE;
InitializeCriticalSection(&memory_lock);
}
EnterCriticalSection(&memory_lock); EnterCriticalSection(&memory_lock);
} }
@ -100,116 +120,26 @@ INLINE void memory_lock_release(void)
} }
INLINE memory_entry *allocate_entry(void)
{
memory_entry *entry;
memory_lock_acquire();
// if we're out of entries, allocate some more
if (free_list == NULL)
{
int entries_per_page = PAGE_SIZE / sizeof(memory_entry);
// allocate a new pages' worth of entry
entry = (memory_entry *)VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
if (entry == NULL)
{
fprintf(stderr, "Out of memory for malloc tracking!\n");
exit(1);
}
// add all the entries to the list
while (entries_per_page--)
{
entry->next = free_list;
free_list = entry;
entry++;
}
}
// grab a free list entry
entry = free_list;
free_list = free_list->next;
// add ourselves to the alloc list
entry->next = alloc_list;
if (entry->next)
entry->next->prev = entry;
entry->prev = NULL;
alloc_list = entry;
memory_lock_release();
return entry;
}
INLINE memory_entry *find_entry(void *pointer)
{
memory_entry *entry;
// scan the list looking for a matching base
if (pointer)
{
memory_lock_acquire();
for (entry = alloc_list; entry; entry = entry->next)
if (entry->base == pointer)
break;
memory_lock_release();
return entry;
}
return NULL;
}
INLINE void free_entry(memory_entry *entry)
{
memory_lock_acquire();
// remove ourselves from the alloc list
if (entry->prev)
entry->prev->next = entry->next;
else
alloc_list = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
// add ourself to the free list
entry->next = free_list;
free_list = entry;
memory_lock_release();
}
INLINE int use_malloc_tracking(void)
{
#ifdef MESS
extern BOOL win_is_gui_application(void);
return !win_is_gui_application();
#elif defined(WINUI)
return FALSE;
#else
return TRUE;
#endif
}
//============================================================ //============================================================
// IMPLEMENTATION // IMPLEMENTATION
//============================================================ //============================================================
//============================================================
// malloc_file_line - debugging version of malloc which
// accepts filename and line number
//============================================================
void *malloc_file_line(size_t size, const char *file, int line) void *malloc_file_line(size_t size, const char *file, int line)
{ {
UINT8 *block_base; UINT8 *block_base;
int id = current_id++; int id = current_id++;
// perform global intialization if not already done
global_init_if_not_done();
if (use_malloc_tracking()) // only proceed if enabled
if (use_malloc_tracking)
{ {
UINT8 *page_base; UINT8 *page_base;
size_t rounded_size; size_t rounded_size;
@ -259,12 +189,21 @@ void *malloc_file_line(size_t size, const char *file, int line)
} }
//============================================================
// malloc - override for the malloc() function
//============================================================
void *CLIB_DECL malloc(size_t size) void *CLIB_DECL malloc(size_t size)
{ {
return malloc_file_line(size, NULL, 0); return malloc_file_line(size, NULL, 0);
} }
//============================================================
// calloc_file_line - debugging version of calloc which
// accepts filename and line number
//============================================================
void *calloc_file_line(size_t size, size_t count, const char *file, int line) void *calloc_file_line(size_t size, size_t count, const char *file, int line)
{ {
// first allocate the memory // first allocate the memory
@ -278,24 +217,41 @@ void *calloc_file_line(size_t size, size_t count, const char *file, int line)
} }
//============================================================
// calloc - override for the calloc() function
//============================================================
void *CLIB_DECL calloc(size_t size, size_t count) void *CLIB_DECL calloc(size_t size, size_t count)
{ {
return calloc_file_line(size, count, NULL, 0); return calloc_file_line(size, count, NULL, 0);
} }
// this function is called by beginthreadex //============================================================
// _calloc_crt - override for the _calloc_crt() function,
// which is called by beginthreadex
//============================================================
void *CLIB_DECL _calloc_crt(size_t size, size_t count) void *CLIB_DECL _calloc_crt(size_t size, size_t count)
{ {
return calloc_file_line(size, count, NULL, 0); return calloc_file_line(size, count, NULL, 0);
} }
//============================================================
// realloc_file_line - debugging version of realloc which
// accepts filename and line number
//============================================================
void *realloc_file_line(void *memory, size_t size, const char *file, int line) void *realloc_file_line(void *memory, size_t size, const char *file, int line)
{ {
void *newmemory = NULL; void *newmemory = NULL;
if (use_malloc_tracking()) // perform global intialization if not already done
global_init_if_not_done();
// only proceed if enabled
if (use_malloc_tracking)
{ {
// if size is non-zero, we need to reallocate memory // if size is non-zero, we need to reallocate memory
if (size != 0) if (size != 0)
@ -338,12 +294,20 @@ void *realloc_file_line(void *memory, size_t size, const char *file, int line)
} }
//============================================================
// realloc - override for the realloc() function
//============================================================
void *CLIB_DECL realloc(void *memory, size_t size) void *CLIB_DECL realloc(void *memory, size_t size)
{ {
return realloc_file_line(memory, size, NULL, 0); return realloc_file_line(memory, size, NULL, 0);
} }
//============================================================
// free - override for the free() function
//============================================================
void CLIB_DECL free(void *memory) void CLIB_DECL free(void *memory)
{ {
memory_entry *entry; memory_entry *entry;
@ -352,7 +316,8 @@ void CLIB_DECL free(void *memory)
if (memory == NULL) if (memory == NULL)
return; return;
if (use_malloc_tracking()) // only proceed if enabled
if (use_malloc_tracking)
{ {
// error if no entry found // error if no entry found
entry = find_entry(memory); entry = find_entry(memory);
@ -381,11 +346,17 @@ void CLIB_DECL free(void *memory)
} }
//============================================================
// _msize - internal MSVC routine that returns the size of
// a memory block
//============================================================
size_t CLIB_DECL _msize(void *memory) size_t CLIB_DECL _msize(void *memory)
{ {
size_t result; size_t result;
if (use_malloc_tracking()) // only proceed if enabled
if (use_malloc_tracking)
{ {
memory_entry *entry = find_entry(memory); memory_entry *entry = find_entry(memory);
if (entry == NULL) if (entry == NULL)
@ -407,12 +378,18 @@ size_t CLIB_DECL _msize(void *memory)
} }
//============================================================
// check_unfreed_mem - called from the exit path of any
// code that wants to check for unfreed memory
//============================================================
void check_unfreed_mem(void) void check_unfreed_mem(void)
{ {
memory_entry *entry; memory_entry *entry;
int total = 0; int total = 0;
if (use_malloc_tracking()) // only valid if we are tracking
if (use_malloc_tracking)
{ {
memory_lock_acquire(); memory_lock_acquire();
@ -432,3 +409,156 @@ void check_unfreed_mem(void)
fprintf(stderr, "a total of %d bytes were not free()'d\n", total); fprintf(stderr, "a total of %d bytes were not free()'d\n", total);
} }
} }
//============================================================
// allocate_entry - allocate a new entry and link it into
// the list of allocated memory
//============================================================
static memory_entry *allocate_entry(void)
{
memory_entry *entry;
// always take the lock when allocating
memory_lock_acquire();
// if we're out of entries, allocate some more
if (free_list == NULL)
{
int entries_per_page = PAGE_SIZE / sizeof(memory_entry);
// allocate a new pages' worth of entry
entry = (memory_entry *)VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
if (entry == NULL)
{
memory_lock_release();
fprintf(stderr, "Out of memory for malloc tracking!\n");
exit(1);
}
// add all the entries to the list
while (entries_per_page--)
{
entry->next = free_list;
free_list = entry;
entry++;
}
}
// grab a free list entry
entry = free_list;
free_list = free_list->next;
// add ourselves to the alloc list
entry->next = alloc_list;
if (entry->next)
entry->next->prev = entry;
entry->prev = NULL;
alloc_list = entry;
// release the lock when finished
memory_lock_release();
return entry;
}
//============================================================
// find_entry - find a memory_object entry in the list that
// contains the given pointer
//============================================================
static memory_entry *find_entry(void *pointer)
{
memory_entry *entry;
// scan the list looking for a matching base
if (pointer)
{
memory_lock_acquire();
for (entry = alloc_list; entry; entry = entry->next)
if (entry->base == pointer)
break;
memory_lock_release();
return entry;
}
return NULL;
}
//============================================================
// free_entry - free a memory_entry object
//============================================================
static void free_entry(memory_entry *entry)
{
memory_lock_acquire();
// remove ourselves from the alloc list
if (entry->prev)
entry->prev->next = entry->next;
else
alloc_list = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
// add ourself to the free list
entry->next = free_list;
free_list = entry;
memory_lock_release();
}
//============================================================
// global_init - global initialization of memory variables
//============================================================
static void global_init(void)
{
TCHAR *envstring;
// create the memory lock
InitializeCriticalSection(&memory_lock);
// determine if we enabled by default
#ifdef MESS
extern BOOL win_is_gui_application(void);
use_malloc_tracking = !win_is_gui_application();
#elif defined(WINUI)
use_malloc_tracking = FALSE;
#else
use_malloc_tracking = TRUE;
#endif
// now allow overrides by the environment
envstring = _tgetenv(_T("OSDDEBUGMALLOC"));
if (envstring != NULL)
use_malloc_tracking = (_ttoi(envstring) != 0);
#ifdef PTR64
// 64-bit builds also can allocate everything under 4GB, unless disabled
envstring = _tgetenv(_T("OSDDEBUG4GB"));
if (envstring == NULL || _ttoi(envstring) != 0)
{
INT8 allocshift;
// loop from 256MB down to 4k (page size)
for (allocshift = 8 + 20; allocshift >= 12; allocshift--)
{
// keep allocating address space at that size until we get something >4gb
while ((UINT64)VirtualAlloc(NULL, (UINT64)1 << allocshift, MEM_RESERVE, PAGE_NOACCESS) < ((UINT64)1 << 32)) ;
}
// loop from 64k down
for (allocshift = 6 + 10; allocshift >= 1; allocshift--)
{
// keep allocating memory until we get something >4gb
while ((UINT64)GlobalAlloc(GMEM_FIXED, (UINT64)1 << allocshift) < ((UINT64)1 << 32)) ;
}
}
#endif
}