Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/ps/Profile.cpp
Show First 20 Lines • Show All 457 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
#elif defined(USE_GLIBC_MALLOC_HOOK) | #elif defined(USE_GLIBC_MALLOC_HOOK) | ||||
// Set up malloc hooks to count allocations - see | // Set up malloc hooks to count allocations - see | ||||
// http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html | // http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html | ||||
static intptr_t malloc_count = 0; | static intptr_t malloc_count = 0; | ||||
static void *(*old_malloc_hook) (size_t, const void*); | static void *(*old_malloc_hook) (size_t, const void*); | ||||
static pthread_mutex_t alloc_hook_mutex = PTHREAD_MUTEX_INITIALIZER; | static std::mutex alloc_hook_mutex; | ||||
static void *malloc_hook(size_t size, const void* UNUSED(caller)) | static void *malloc_hook(size_t size, const void* UNUSED(caller)) | ||||
{ | { | ||||
// This doesn't really work across threads. The hooks are global variables, and | // This doesn't really work across threads. The hooks are global variables, and | ||||
// we have to temporarily unhook in order to call the real malloc, and during that | // we have to temporarily unhook in order to call the real malloc, and during that | ||||
// time period another thread may perform an unhooked (hence uncounted) allocation | // time period another thread may perform an unhooked (hence uncounted) allocation | ||||
// which we will miss. | // which we will miss. | ||||
// Two threads may execute the hook simultaneously, so we need to do the | // Two threads may execute the hook simultaneously, so we need to do the | ||||
// temporary unhooking in a thread-safe way, so for simplicity we just use a mutex. | // temporary unhooking in a thread-safe way, so for simplicity we just use a mutex. | ||||
pthread_mutex_lock(&alloc_hook_mutex); | std::lock_guard<std::mutex> lock(alloc_hook_mutex); | ||||
++malloc_count; | ++malloc_count; | ||||
__malloc_hook = old_malloc_hook; | __malloc_hook = old_malloc_hook; | ||||
void* result = malloc(size); | void* result = malloc(size); | ||||
old_malloc_hook = __malloc_hook; | old_malloc_hook = __malloc_hook; | ||||
__malloc_hook = malloc_hook; | __malloc_hook = malloc_hook; | ||||
pthread_mutex_unlock(&alloc_hook_mutex); | |||||
return result; | return result; | ||||
} | } | ||||
static void alloc_hook_initialize() | static void alloc_hook_initialize() | ||||
{ | { | ||||
pthread_mutex_lock(&alloc_hook_mutex); | std::lock_guard<std::mutex> lock(alloc_hook_mutex); | ||||
old_malloc_hook = __malloc_hook; | old_malloc_hook = __malloc_hook; | ||||
__malloc_hook = malloc_hook; | __malloc_hook = malloc_hook; | ||||
// (we don't want to bother hooking realloc and memalign, because if they allocate | // (we don't want to bother hooking realloc and memalign, because if they allocate | ||||
// new memory then they'll be caught by the malloc hook anyway) | // new memory then they'll be caught by the malloc hook anyway) | ||||
pthread_mutex_unlock(&alloc_hook_mutex); | |||||
} | } | ||||
/* | /* | ||||
It would be nice to do: | It would be nice to do: | ||||
__attribute__ ((visibility ("default"))) void (*__malloc_initialize_hook)() = malloc_initialize_hook; | __attribute__ ((visibility ("default"))) void (*__malloc_initialize_hook)() = malloc_initialize_hook; | ||||
except that doesn't seem to work in practice, since something (?) resets the | except that doesn't seem to work in practice, since something (?) resets the | ||||
hook to NULL some time while loading the game, after we've set it here - so | hook to NULL some time while loading the game, after we've set it here - so | ||||
we just call malloc_initialize_hook once inside CProfileManager::Frame instead | we just call malloc_initialize_hook once inside CProfileManager::Frame instead | ||||
and hope nobody deletes our hook after that. | and hope nobody deletes our hook after that. | ||||
▲ Show 20 Lines • Show All 274 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator