X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FRtsUtils.c;h=a2a291970241c70355f786a5ffccd8d0a0c5754f;hb=221e74f6814f76430ff74b970a77393b0ae83eb5;hp=bf02c328fb45e0c4308f12bbaa03127c738fce8b;hpb=e3c55aebd4f9ce7a5b4390d4726612865fd207f2;p=ghc-hetmet.git diff --git a/rts/RtsUtils.c b/rts/RtsUtils.c index bf02c32..a2a2919 100644 --- a/rts/RtsUtils.c +++ b/rts/RtsUtils.c @@ -45,6 +45,137 @@ #endif /* ----------------------------------------------------------------------------- + Debugging allocator + -------------------------------------------------------------------------- */ + +#if defined(DEBUG) + +typedef struct Allocated_ { + void *addr; + size_t len; + struct Allocated_ *next; +} Allocated; + +static Allocated *allocs = NULL; + +#ifdef THREADED_RTS +static Mutex allocator_mutex; +#endif + +void +initAllocator(void) +{ + Allocated *a; + size_t alloc_size; + +#ifdef THREADED_RTS + initMutex(&allocator_mutex); +#endif + alloc_size = sizeof(Allocated); + if ((a = (Allocated *) malloc(alloc_size)) == NULL) { + /* don't fflush(stdout); WORKAROUND bug in Linux glibc */ + MallocFailHook((W_) alloc_size, "initialising debugging allocator"); + stg_exit(EXIT_INTERNAL_ERROR); + } + a->addr = NULL; + a->len = 0; + a->next = NULL; + allocs = a; +} + +void +shutdownAllocator(void) +{ + Allocated *prev, *a; + + if (allocs == NULL) { + barf("Allocator shutdown requested, but not initialised!"); + } + +#ifdef THREADED_RTS + closeMutex(&allocator_mutex); +#endif + + prev = allocs; + while (1) { + a = prev->next; + free(prev); + if (a == NULL) return; + IF_DEBUG(sanity, + debugBelch("Warning: %p still allocated at shutdown\n", + a->addr);) + prev = a; + } +} + +static void addAllocation(void *addr, size_t len) { + Allocated *a; + size_t alloc_size; + + if (allocs != NULL) { + alloc_size = sizeof(Allocated); + if ((a = (Allocated *) malloc(alloc_size)) == NULL) { + /* don't fflush(stdout); WORKAROUND bug in Linux glibc */ + MallocFailHook((W_) alloc_size, + "creating info for debugging allocator"); + stg_exit(EXIT_INTERNAL_ERROR); + } + a->addr = addr; + a->len = len; + ACQUIRE_LOCK(&allocator_mutex); + a->next = allocs->next; + allocs->next = a; + RELEASE_LOCK(&allocator_mutex); + } + else { + /* This doesn't actually help as we haven't looked at the flags + * at the time that it matters (while running constructors) */ + IF_DEBUG(sanity, + debugBelch("Ignoring allocation %p %zd as allocs is NULL\n", + addr, len);) + } +} + +static void removeAllocation(void *addr) { + Allocated *prev, *a; + + if (addr == NULL) { + barf("Freeing NULL!"); + } + + if (allocs != NULL) { + ACQUIRE_LOCK(&allocator_mutex); + prev = allocs; + a = prev->next; + while (a != NULL) { + if (a->addr == addr) { + prev->next = a->next; + memset(addr, 0xaa, a->len); + free(a); + RELEASE_LOCK(&allocator_mutex); + return; + } + prev = a; + a = a->next; + } + /* We would like to barf here, but we can't as conc021 + * allocates some stuff in a constructor which then gets freed + * during hs_exit */ + /* barf("Freeing non-allocated memory at %p", addr); */ + IF_DEBUG(sanity, + debugBelch("Warning: Freeing non-allocated memory at %p\n", + addr);) + RELEASE_LOCK(&allocator_mutex); + } + else { + IF_DEBUG(sanity, + debugBelch("Ignoring free of %p as allocs is NULL\n", + addr);) + } +} +#endif + +/* ----------------------------------------------------------------------------- Result-checking malloc wrappers. -------------------------------------------------------------------------- */ @@ -52,12 +183,17 @@ void * stgMallocBytes (int n, char *msg) { char *space; + size_t n2; - if ((space = (char *) malloc((size_t) n)) == NULL) { + n2 = (size_t) n; + if ((space = (char *) malloc(n2)) == NULL) { /* don't fflush(stdout); WORKAROUND bug in Linux glibc */ MallocFailHook((W_) n, msg); /*msg*/ stg_exit(EXIT_INTERNAL_ERROR); } +#if defined(DEBUG) + addAllocation(space, n2); +#endif return space; } @@ -65,12 +201,18 @@ void * stgReallocBytes (void *p, int n, char *msg) { char *space; + size_t n2; - if ((space = (char *) realloc(p, (size_t) n)) == NULL) { + n2 = (size_t) n; + if ((space = (char *) realloc(p, (size_t) n2)) == NULL) { /* don't fflush(stdout); WORKAROUND bug in Linux glibc */ MallocFailHook((W_) n, msg); /*msg*/ stg_exit(EXIT_INTERNAL_ERROR); } +#if defined(DEBUG) + removeAllocation(p); + addAllocation(space, n2); +#endif return space; } @@ -84,6 +226,9 @@ stgCallocBytes (int n, int m, char *msg) MallocFailHook((W_) n*m, msg); /*msg*/ stg_exit(EXIT_INTERNAL_ERROR); } +#if defined(DEBUG) + addAllocation(space, (size_t) n * (size_t) m); +#endif return space; } @@ -93,6 +238,9 @@ stgCallocBytes (int n, int m, char *msg) void stgFree(void* p) { +#if defined(DEBUG) + removeAllocation(p); +#endif free(p); }