Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified src/Helpers/MemDebug.cpp

    rfc6053 rf2f4ae  
    66 */
    77
    8 #ifndef NDBEGUG
    9 #ifndef NO_MEMDEBUG
    10 
    118#include <iostream>
    129#include <cstdlib>
     
    1411#include <boost/thread.hpp>
    1512
    16 #ifdef __GNUC__
    17 #include <execinfo.h>
    18 #include <cxxabi.h>
    19 #endif
    20 
    2113using namespace std;
    2214
    23 // we need our own low level mutexex, since we cannot assure the time of construction and destruction
    24 // otherwise
    25 #if defined(unix) || defined(__unix)
    26 
    27 #include <pthread.h>
    28 #include <cassert>
    29 #define mutex_t    pthread_mutex_t
    30 #define mutex_init PTHREAD_MUTEX_INITIALIZER
    31 #define mutex_lock(mtx) \
    32   do{\
    33     int res = pthread_mutex_lock(&(mtx));\
    34     assert(!res && "Could not lock mutex!");\
    35   }while(0)
    36 
    37 #define mutex_unlock(mtx) \
    38   do{\
    39     int res = pthread_mutex_unlock(&(mtx));\
    40     assert(!res && "Could not unlock mutex!");\
    41   }while(0)
    42 
    43 #else
    44 # error "No thread structure defined for this plattform..."
    45 #endif
     15#ifndef NDBEGUG
     16#ifndef NO_MEMDEBUG
    4617
    4718namespace Memory {
     
    6334      char file[length+1];
    6435      int line;
    65 #ifdef __GNUC__  // function tracking only works with GCC
    66       // function names can get looooong
    67       enum {length2 = 256};
    68       char function[length2+1];
    69 #endif
    7036      size_t nbytes;
    7137      bool isUsed;
     
    7844  };
    7945
    80 
    81   mutex_t memorylock = mutex_init;
     46  boost::mutex memorylock;
    8247
    8348  // start and end of the doubly-linked list
     
    13196    for(entry_t *pos=begin;pos;pos=pos->next){
    13297      cout << "\nChunk of " << pos->info.nbytes << " bytes" << " still available" << endl;
    133 #ifdef __GNUC__
    134       cout << "Chunk reserved at: " << pos->info.function
    135            << " (" << pos->info.file << ":" << pos->info.line  << ")" << endl;
    136 #else
    13798      cout << "Chunk reserved at: " << pos->info.file << ":" << pos->info.line << endl;
    138 #endif
    139     }
    140   }
    141 
    142   // Adds an entry to the linked list
    143   void addEntry(entry_t *entry){
    144     // check if the entry is already in the list
    145     if(!entry->isIgnored)
    146       return;
    147 
    148     mutex_lock(Memory::memorylock);
    149 
    150     entry->next=0;            // the created block is last in the list
    151     entry->prev=Memory::end;  // the created block is last in the list
    152     if(!Memory::begin){
    153       // the list was empty... start a new one
    154       Memory::begin=entry;
    155     }
    156     else {
    157       // other blocks present... we can add to the last one
    158       Memory::end->next=entry;
    159     }
    160     Memory::end=entry;
    161 
    162     // update some global info
    163     Memory::state  += entry->info.nbytes;
    164     if(Memory::state>Memory::max){
    165         Memory::max = Memory::state;
    166     }
    167     ++Memory::allocs;
    168     // done with the list... it is safe to unlock now
    169     mutex_unlock(Memory::memorylock);
    170     entry->isIgnored = false;
     99    }
    171100  }
    172101
     
    176105      return;
    177106
    178     mutex_lock(memorylock);
    179107    if(entry->prev){
    180108      entry->prev->next = entry->next;
     
    192120      end = entry->prev;
    193121    }
     122    entry->isIgnored = true;
    194123    Memory::state  -= entry->info.nbytes;
    195     mutex_unlock(memorylock);
    196     entry->isIgnored = true;
    197 
    198124  }
    199125
     
    204130    deleteEntry(entry);
    205131  }
    206 
    207 #ifdef __GNUC__
    208   // this function let's us find the caller's name
    209   char* getCaller(){
    210     // stack looks like this:
    211     // getCaller();
    212     // operator new();
    213     // function_we_are_looking_for(); <-
    214     const size_t max_depth = 3;
    215     void* stack_addrs[max_depth];
    216     size_t stack_depth;
    217     char **stack_strings=0;
    218     const char *func_name=0;
    219     const char *toplevel = "Global scope";
    220     char *retval=0;
    221 
    222     // get the backtrace, depth three
    223     stack_depth   = backtrace(stack_addrs,max_depth);
    224     stack_strings = backtrace_symbols(stack_addrs, stack_depth);
    225     // used later for demangling
    226     // reserved here, so we can free it unconditionally
    227     char *dm_function = static_cast<char*>(malloc(entry_t::info_t::length2));
    228     if(!dm_function){
    229       // malloc failed... we are out of luck
    230       throw std::bad_alloc();
    231     }
    232 
    233     // see if we found our function name
    234     if(stack_depth==max_depth){
    235       // find the mangled function name
    236       char *begin = stack_strings[max_depth-1];
    237       // function name starts with a (
    238       while(*begin && *begin!='(') ++begin;
    239       char *end=begin;
    240       while(*end && *end!='+') ++end;
    241 
    242       // see if we found our function name
    243       if(*begin && *end){
    244         *begin++ = 0;
    245         *end = 0;
    246         // use the C++ demangler
    247 
    248         size_t sz = entry_t::info_t::length2;
    249         int status;
    250         char *func_ret = abi::__cxa_demangle(begin, dm_function, &sz, &status);
    251         if(func_ret){
    252           // abi might have realloced...
    253           dm_function = func_ret;
    254           func_name = dm_function;
    255         }
    256         else{
    257           // demangling failed... get the function name without demangling
    258           func_name = begin;
    259         }
    260       }
    261       else{
    262         // function name not found... get the whole line
    263         func_name = stack_strings[max_depth-1];
    264       }
    265 
    266     }
    267     else{
    268       func_name = toplevel;
    269     }
    270 
    271     // now we copy the desired function name
    272     if((retval = static_cast<char*>(malloc(strlen(func_name)+1)))){
    273       // we know that the string will fit, so strcpy is safe here
    274       strcpy(retval,func_name);
    275     }
    276     else{
    277       free(stack_strings); // malloc()ed by backtrace_symbols
    278       free(dm_function);
    279       // uh-uh ... seems we are out of luck for allocations now
    280       throw std::bad_alloc();
    281     }
    282     free(dm_function);
    283     free(stack_strings); // malloc()ed by backtrace_symbols
    284     return retval;
    285   }
    286 #endif
    287 }
    288 
    289 #ifdef __GNUC__
    290 
    291 void *operator new(size_t nbytes,const char* file, int line, const char* func) throw(std::bad_alloc) {
     132}
     133
     134void *operator new(size_t nbytes,const char* file, int line) throw(std::bad_alloc) {
     135
     136  // we need to lock, so that no one changes the linked list while we are here
     137  boost::mutex::scoped_lock guard(Memory::memorylock);
    292138
    293139  // to avoid allocations of 0 bytes if someone screws up
     
    307153  }
    308154
    309   // build the entry in front of the space
    310   Memory::entry_t *entry = (Memory::entry_t*) res;
    311   memset(res,0,entrySpace);
    312   entry->info.nbytes = nbytes;
    313   entry->info.isUsed = true;
    314   strncpy(entry->info.file,file,Memory::entry_t::info_t::length);
    315   entry->info.file[Memory::entry_t::info_t::length] = '\0';
    316   entry->info.line=line;
    317   strncpy(entry->info.function,func,Memory::entry_t::info_t::length2);
    318   entry->info.function[Memory::entry_t::info_t::length2] = '\0';
    319   // the space starts behind the info
    320   entry->info.location = (char*)res + entrySpace;
    321 
    322   // mark the block as not in the list (will be changed by addEntry)
    323   entry->isIgnored = true;
    324   Memory::addEntry(entry);
    325 
    326   // get the checksum...
    327   entry->checksum = Memory::calcChecksum(&entry->info);
    328 
    329   // ok, space is prepared... the user can have it.
    330   // the rest (constructor, deleting when something is thrown etc)
    331   // is handled automatically
    332   return entry->info.location;
    333 }
    334 
    335 #else
    336 
    337 void *operator new(size_t nbytes,const char* file, int line) throw(std::bad_alloc) {
    338 
    339   // to avoid allocations of 0 bytes if someone screws up
    340   // allocation with 0 byte size are undefined behavior, so we are
    341   // free to handle it this way
    342   if(!nbytes) {
    343     nbytes = 1;
    344   }
    345 
    346   // get the size of the entry, including alignment
    347   static const size_t entrySpace = Memory::doAlign(sizeof(Memory::entry_t));
    348 
    349   void *res;
    350   if(!(res=malloc(entrySpace + nbytes))){
    351     // new must throw, when space is low
    352     throw std::bad_alloc();
    353   }
     155  // we got the space, so update the global info
     156  Memory::state += nbytes;
     157  if(Memory::state>Memory::max){
     158    Memory::max = Memory::state;
     159  }
     160  Memory::allocs++;
    354161
    355162  // build the entry in front of the space
     
    364171  entry->info.location = (char*)res + entrySpace;
    365172
    366   // mark the block as not in the list (will be changed by addEntry)
    367   entry->isIgnored = true;
    368   Memory::addEntry(entry);
     173  // add the entry at the end of the list
     174  entry->next=0;            // the created block is last in the list
     175  entry->prev=Memory::end;  // the created block is last in the list
     176  if(!Memory::begin){
     177    // the list was empty... start a new one
     178    Memory::begin=entry;
     179  }
     180  else {
     181    // other blocks present... we can add to the last one
     182    Memory::end->next=entry;
     183  }
     184  Memory::end=entry;
    369185
    370186  // get the checksum...
     
    380196}
    381197
    382 #endif
    383 
    384198void *operator new(size_t nbytes) throw(std::bad_alloc) {
    385199  // Just forward to the other operator, when we do not know from
    386200  // where the allocation came
    387 #ifdef __GNUC__
    388   // this might throw bad_alloc
    389   char *caller = Memory::getCaller();
    390   void* retval = 0;
    391 
    392   // if this throws, we have to clean up the caller anyway
    393   try{
    394     retval = operator new(nbytes,"Unknown",0,caller);
    395   }
    396   catch(...)
    397   {
    398     free(caller); // malloc()ed by Memory::getCaller();
    399     throw;
    400   }
    401   free(caller); // malloc()ed by Memory::getCaller();
    402   return retval;
    403 #else
    404201  return operator new(nbytes,"Unknown",0);
    405 #endif
    406 }
    407 
    408 #ifdef __GNUC__
    409 
    410 void *operator new[] (size_t nbytes,const char* file, int line, const char* func) throw(std::bad_alloc) {
    411   // The difference between new and new[] is just for compiler bookkeeping.
    412   return operator new(nbytes,file,line,func);
    413 }
    414 
    415 #else
     202}
    416203
    417204void *operator new[] (size_t nbytes,const char* file, int line) throw(std::bad_alloc) {
     
    420207}
    421208
    422 #endif
    423 
    424209void *operator new[] (size_t nbytes) throw(std::bad_alloc) {
    425210  // Forward again
    426 #ifdef __GNUC__
    427   // this might throw bad_alloc
    428     char *caller = Memory::getCaller();
    429     void *retval=0;
    430 
    431     // if this throws, we have to clean up the caller anyway
    432     try{
    433       retval = operator new[] (nbytes,"Unknown",0,caller);
    434     }
    435     catch(...)
    436     {
    437       free(caller); // malloc()ed by Memory::getCaller();
    438       throw;
    439     }
    440     free(caller); // malloc()ed by Memory::getCaller();
    441     return retval;
    442 #else
    443211  return operator new[] (nbytes,"Unknown",0);
    444 #endif
    445212}
    446213
     
    450217    return;
    451218  }
     219
     220  // we need to lock, so the linked list does not changed while we are in here
     221  boost::mutex::scoped_lock guard(Memory::memorylock);
    452222
    453223  // get the size for the entry, including alignment
Note: See TracChangeset for help on using the changeset viewer.