From a3b57f5fd5dd4a5555c165155ff52587e6242f05 Mon Sep 17 00:00:00 2001 From: Aaron Giles Date: Tue, 8 Jan 2008 06:19:50 +0000 Subject: [PATCH] (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....) --- src/osd/windows/winalloc.c | 352 +++++++++++++++++++++++++------------ 1 file changed, 241 insertions(+), 111 deletions(-) diff --git a/src/osd/windows/winalloc.c b/src/osd/windows/winalloc.c index ddace2874e2..1c6b867ab13 100644 --- a/src/osd/windows/winalloc.c +++ b/src/osd/windows/winalloc.c @@ -12,6 +12,7 @@ // standard windows headers #define WIN32_LEAN_AND_MEAN #include +#include // MAME headers #include "osdcore.h" @@ -75,7 +76,21 @@ static memory_entry *free_list; static int current_id; 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 //============================================================ +INLINE void global_init_if_not_done(void) +{ + if (!global_init_done) + { + global_init_done = TRUE; + global_init(); + } +} + + INLINE void memory_lock_acquire(void) { - if (!memory_lock_initialized) - { - memory_lock_initialized = TRUE; - InitializeCriticalSection(&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 //============================================================ +//============================================================ +// 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) { UINT8 *block_base; 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; 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) { 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) { // 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) { 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) { 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 *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 != 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) { return realloc_file_line(memory, size, NULL, 0); } +//============================================================ +// free - override for the free() function +//============================================================ + void CLIB_DECL free(void *memory) { memory_entry *entry; @@ -352,7 +316,8 @@ void CLIB_DECL free(void *memory) if (memory == NULL) return; - if (use_malloc_tracking()) + // only proceed if enabled + if (use_malloc_tracking) { // error if no entry found 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 result; - if (use_malloc_tracking()) + // only proceed if enabled + if (use_malloc_tracking) { memory_entry *entry = find_entry(memory); 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) { memory_entry *entry; int total = 0; - if (use_malloc_tracking()) + // only valid if we are tracking + if (use_malloc_tracking) { 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); } } + + +//============================================================ +// 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 +}