log only flushes to disk if option MMGR_FLUSH_ALL is set.

log is shut down in log_shutdown, instead of in every static dtor
(speeds up shutdown)
minor cleanup.

This was SVN commit r1881.
This commit is contained in:
janwas 2005-01-30 17:31:20 +00:00
parent f1d322d5af
commit be3be6cede
2 changed files with 72 additions and 70 deletions

View File

@ -83,38 +83,6 @@ static void unlock() throw()
}
//////////////////////////////////////////////////////////////////////////////
// init/shutdown hook - notifies us when ctor/dtor are called
//////////////////////////////////////////////////////////////////////////////
static bool static_dtor_called = false;
static struct NonLocalStaticObject
{
NonLocalStaticObject()
{
// by calling now instead of on first lock() call,
// we ensure no threads have been spawned yet.
lock_init();
// note: don't init log here - current directory hasn't yet been set.
// the log file may otherwise be split between 2 files.
}
~NonLocalStaticObject()
{
// if the app requested a leak report before now, the deallocator
// will update its leak report on every call (since dtors are now
// being called, each may be the last). note that there is no
// portable way to make sure a mmgr_shutdown() would be called
// as the very last thing before exit.
static_dtor_called = true;
// don't shutdown the lock - some threads may still be active.
// do so in shutdown() - see call site.
}
} nlso;
//////////////////////////////////////////////////////////////////////////////
// options (enable/disable additional checks)
//////////////////////////////////////////////////////////////////////////////
@ -161,13 +129,6 @@ uint mmgr_set_options(uint new_options)
// string formatting routines for log and reports
//////////////////////////////////////////////////////////////////////////////
const size_t NUM_SIZE = 32;
// enough to cover even 64 bit numbers
const size_t OWNER_SIZE = 92+400;
// specific size chosen such that sizeof(Alloc) == 128
// (power-of-two for more efficient allocation)
// strip off uninteresting parts of func in-place.
// e.g. "std::basic_string<char, char_traits<char>, std::allocator<char> >" =>
@ -271,8 +232,9 @@ static void simplify_stl_func(char* func)
}
const size_t OWNER_SIZE = 92+400;
// specific size chosen such that sizeof(Alloc) == 128
// (power-of-two for more efficient allocation)
static void store_owner(char* owner, const char* path, int line, const char* func)
{
@ -311,6 +273,9 @@ static void store_owner(char* owner, const char* path, int line, const char* fun
}
const size_t NUM_SIZE = 32;
// enough to cover even 64 bit numbers
static const char* insert_commas(char* out, size_t value)
{
char num[NUM_SIZE];
@ -715,31 +680,19 @@ static void stats_remove(const Alloc* a)
static void log_init();
static const char* const log_filename = "mem_log.txt";
static FILE* log_fp;
// open/append/close every call to make sure nothing gets lost when crashing.
// split out of log() to allow locked_log without code duplication.
static void vlog(const char* fmt, va_list args)
{
log_init();
static FILE* fp;
// first call, or FLUSH option set
if(!fp)
{
fp = fopen(log_filename, "a");
if(!fp)
{
assert2(0 && "log file open failed");
return;
}
}
(void)vfprintf(log_fp, fmt, args);
(void)vfprintf(fp, fmt, args);
if(0 || static_dtor_called)
{
fclose(fp);
fp = 0;
}
// user requested each log line go directly to disk.
if(options & MMGR_FLUSH_LOG)
fflush(log_fp);
}
static void log(const char* fmt, ...)
@ -767,12 +720,16 @@ static void locked_log(const char* fmt, ...)
static void log_init()
{
static bool log_initialized = false;
if(log_initialized)
// open => we're already initialized.
if(log_fp)
return;
log_initialized = true;
unlink(log_filename);
log_fp = fopen(log_filename, "w");
if(!log_fp)
{
assert2(0 && "log file open failed");
return;
}
//
// write header
@ -805,9 +762,19 @@ static void log_init()
}
static void log_alloc(const Alloc* a)
static void log_shutdown()
{
// duplicated in write_alloc_cb(FILE*); factoring out isn't worth it
if(log_fp)
{
fclose(log_fp);
log_fp = 0;
}
}
static void log_this_alloc(const Alloc* a)
{
// duplicated in write_alloc_cb(); factoring out isn't worth it
log("%06d 0x%08p 0x%08X 0x%08p 0x%08X 0x%08X %-8s %c %c %s\n",
a->alloc_num,
a->user_p, a->user_size,
@ -829,7 +796,7 @@ static void write_alloc_cb(const Alloc* a, void* arg)
{
FILE* f = (FILE*)arg;
// duplicated in log_alloc(Alloc*); factoring out isn't worth it
// duplicated in log_this_alloc(Alloc*); factoring out isn't worth it
fprintf(f, "%06d 0x%08p 0x%08X 0x%08p 0x%08X 0x%08X %-8s %c %c %s\n",
a->alloc_num,
a->user_p, a->user_size,
@ -975,7 +942,7 @@ static bool alloc_is_valid(const Alloc* a)
// allocation's memory range.
assert2(0);
log("[!] Memory over/underrun:\n");
log_alloc(a);
log_this_alloc(a);
return false;
}
@ -1030,13 +997,42 @@ bool mmgr_are_all_valid()
}
//////////////////////////////////////////////////////////////////////////////
// init/shutdown hook - notifies us when ctor/dtor are called
//////////////////////////////////////////////////////////////////////////////
static bool static_dtor_called = false;
static struct NonLocalStaticObject
{
NonLocalStaticObject()
{
// by calling now instead of on first lock() call,
// we ensure no threads have been spawned yet.
lock_init();
// note: don't init log here - current directory hasn't yet been set.
// the log file may otherwise be split between 2 files.
}
~NonLocalStaticObject()
{
// if the app requested a leak report before now, the deallocator
// will update its leak report on every call (since dtors are now
// being called, each may be the last). note that there is no
// portable way to make sure a mmgr_shutdown() would be called
// as the very last thing before exit.
static_dtor_called = true;
// don't shutdown the lock - some threads may still be active.
// do so in shutdown() - see call site.
}
} nlso;
static void shutdown(void)
{
alloc_shutdown();
log_shutdown();
lock_shutdown();
}

View File

@ -40,7 +40,7 @@
// log all allocation/deallocation operations undertaken.
const uint MMGR_LOG_ALL = 0x01;
// validate all allocations on every call to the allocator (slow!)
// validate all allocations on every memory API call. slow!
const uint MMGR_VALIDATE_ALL = 0x02;
// fill the user-visible part of each allocation with a certain pattern
@ -57,10 +57,16 @@ const uint MMGR_TRACE = 0x08;
// more informative, but adds 500µs to every call.
const uint MMGR_RESOLVE_OWNER = 0x10;
const uint MMGR_ALL = MMGR_LOG_ALL|MMGR_VALIDATE_ALL|MMGR_FILL|MMGR_TRACE|MMGR_RESOLVE_OWNER;
// force each log line to be written directly to disk. slow!
// use only when the application is crashing, to make sure all
// available information is written out.
const uint MMGR_FLUSH_LOG = 0x20;
// an alias that includes all of the above.
const uint MMGR_ALL = 0xff;
// return the current options unchanged.
const uint MMGR_QUERY = ~0;
const uint MMGR_QUERY = ~0;
extern uint mmgr_set_options(uint);