src/tools/tMemManager.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is f.ree software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023   
00024 ***************************************************************************
00025 
00026 */ // LoadLibrary
00027 
00028 // disable malloc replacement
00029 #ifndef NO_MALLOC_REPLACEMENT
00030 #define NO_MALLOC_REPLACEMENT
00031 #endif
00032 
00033 #include "defs.h"
00034 
00035 #include <iostream>
00036 #include <sstream>
00037 #include <stdio.h>  // need basic C IO since STL IO does memory management
00038 #include "tMemManager.h"
00039 #include "tError.h"
00040 
00041 #ifdef HAVE_STDLIB_H
00042 #include <stdlib.h>
00043 #endif
00044 
00045 #ifdef WIN32
00046 #ifdef _MSC_VER 
00047 #include <windows.h>
00048 #include <winuser.h>
00049 #ifdef _DEBUG
00050 #undef _DEBUG
00051 #endif
00052 #include <CrtDbg.h>
00053 #pragma warning (disable : 4073)
00054 #pragma init_seg(lib)
00055 #endif
00056 #ifdef __MINGW32__
00057 #include <windows.h>
00058 #include <winuser.h>
00059 #ifdef _DEBUG
00060 #undef _DEBUG
00061 #endif
00062 #endif
00063 static CRITICAL_SECTION  mutex;
00064 #endif
00065 
00066 #ifndef DONTUSEMEMMANAGER
00067 #define NEW
00068 #endif
00069 
00070 #ifdef DEBUG
00071 #define LEAKFINDER
00072 
00073 
00074 #ifdef LEAKFINDER
00075 #define PROFILER
00076 #endif
00077 
00078 #ifdef WIN32
00079 //#define MEM_DEB_SMALL
00080 //#define MEM_DEB
00081 //#define DOUBLEFREEFINDER
00082 #endif
00083 
00084 //#define MEM_DEB_SMALL
00085 //#define MEM_DEB
00086 //#define DOUBLEFREEFINDER
00087 #endif
00088 
00089 static bool reported=false;
00090 
00091 #ifdef HAVE_LIBZTHREAD
00092 #include <zthread/FastRecursiveMutex.h>
00093 
00094 static ZThread::FastRecursiveMutex st_mutex;
00095 #else
00096 class tMockMutex
00097 {
00098 public:
00099     void acquire(){};
00100     void release(){};
00101 };
00102 
00103 static tMockMutex st_mutex;
00104 #endif
00105 
00106 class tBottleNeck
00107 {
00108 public:
00109     tBottleNeck()
00110     {
00111         st_mutex.acquire();
00112     }
00113 
00114     ~tBottleNeck()
00115     {
00116         st_mutex.release();
00117     }
00118 };
00119 
00120 // replacement for wmemset function
00121 #ifndef HAVE_WMEMSET
00122 static inline wchar_t *wmemset(wchar_t *wcs, wchar_t wc, size_t n) throw()
00123 {
00124     // fill memory
00125     for( size_t i = 0; i < n; ++i )
00126     {
00127         wcs[i] = wc;
00128     }
00129 
00130     return wcs;
00131 }
00132 #endif
00133 
00134 void leak(){
00135     if (!reported)
00136     {
00137         reported=true;
00138 #ifdef DEBUG
00139 #ifdef WIN32
00140         MessageBox (NULL, "Memory leak detected!" , "Memory Leak", MB_OK);
00141 #else
00142         std::cerr << "\n\nMemory leak detected!\n\n";
00143 #endif
00144 #endif
00145         tMemManBase::Profile();
00146     }
00147 }
00148 
00149 
00150 
00151 #include "tList.h"
00152 
00153 class memblock;
00154 
00155 #ifdef DEBUG
00156 #define SAFETYBYTES 16
00157 #else
00158 #define SAFETYBYTES 0
00159 #endif
00160 #define PAD 197
00161 
00162 // information about allocation in process
00163 struct tAllocationInfo
00164 {
00165 #ifdef LEAKFINDER
00166     const char *filename;
00167     const char *classname;
00168     int checksum;
00169     int line;
00170     bool array;
00171 #endif
00172 
00173     tAllocationInfo( bool 
00174 #ifdef LEAKFINDER
00175                      array_ 
00176 #endif
00177         )
00178 #ifdef LEAKFINDER
00179     : filename( "XXX" ), classname( "XXX" ), checksum(-1), line(0), array( array_ )
00180 #endif
00181     {
00182     }
00183 };
00184 
00185 class tMemMan: public tMemManBase
00186 {
00187 public:
00188     static void *Alloc(tAllocationInfo const & info, size_t s);
00189     static void  Dispose(tAllocationInfo const & info, void *p);
00190     static void  DisposeButKeep(tAllocationInfo const & info, void *p);
00191 };
00192 
00193 
00194 class tMemManager{
00195     friend class memblock;
00196 public:
00197     tMemManager(int size, int blocksize);
00198     tMemManager(int size);
00199     ~tMemManager();
00200 
00201     void *      Alloc( tAllocationInfo const & info );
00202     static void * AllocDefault(tAllocationInfo const & info, size_t size);
00203     static void Dispose(tAllocationInfo const & info, void *p, bool keep=false);
00204     void        complete_Dispose(memblock *m);
00205     void        Check(); // check integrity
00206 
00207 private:
00208     int  Lower(int i){ // the element below i in the heap
00209         if(i%2==0)  // just to make sure what happens; you never know what 1/2 is..
00210             return i/2-1;
00211         else
00212             return (i-1)/2;
00213     }
00214 
00215     bool SwapIf(int i,int j); // swaps heap elements i and j if they are
00216     // in wrong order; only then, TRUE is returned.
00217     // i is assumed to lie lower in the heap than j.
00218 
00219     void SwapDown(int j); // swap element j as far down as it may go.
00220     void SwapUp(int i);   // swap element j as far up as it must.
00221 
00222     //#ifdef MEM_DEB
00223     void CheckHeap(); // checks the heap structure
00224     //#endif
00225 
00226 static int  UpperL(int i){return 2*i+1;} // the elements left and
00227     static int  UpperR(int i){return 2*i+2;} // right above i
00228 
00229     void Insert(memblock *b);  // starts to manage object e
00230     void Remove(memblock *b);  // stops (does not delete e)
00231     memblock * Remove(int i);     // stops to manage object i, wich is returned.
00232     void Replace(int i);  // puts element i to the right place (if the
00233     // rest of the heap has correct order)
00234     void Replace(memblock *e);
00235 
00236 
00237     int size;
00238     int blocksize;
00239 
00240     tList<memblock, true> blocks;
00241     tList<memblock, true> full_blocks;
00242 
00243     int semaphore;
00244 };
00245 
00246 static bool inited=false;
00247 
00248 #ifdef LEAKFINDER
00249 #include <fstream>
00250 #define MAXCHECKSUM 100001
00251 static int counter[MAXCHECKSUM];
00252 static int leaks[MAXCHECKSUM];
00253 #ifdef PROFILER
00254 static const char *checksum_filename[MAXCHECKSUM];
00255 static const char *checksum_classname[MAXCHECKSUM];
00256 static int         checksum_line[MAXCHECKSUM];
00257 static int         checksum_blocks[MAXCHECKSUM];
00258 static int         checksum_bytes[MAXCHECKSUM];
00259 #endif
00260 
00261 
00262 static char const *leakname="leak.log";
00263 static bool checkleaks=true;
00264 #endif
00265 
00266 void begin_checkleaks(){
00267 #ifdef LEAKFINDER
00268     checkleaks=true;
00269 #endif
00270 }
00271 
00272 struct chunkinfo{
00273 unsigned char pos:8;       // our position in the block
00274 unsigned char occupied:1;  // flag
00275 unsigned char size_in_dwords:7; // size
00276 unsigned char next:8;      // next element of same state
00277 unsigned char prev:8;      // ....
00278 #ifdef LEAKFINDER
00279     int checksum;
00280     int counter;
00281     bool array;
00282 #endif
00283 #ifdef PROFILER
00284     size_t realSize;
00285 #endif
00286 };
00287 
00288 // the heap elements.
00289 
00290 class memblock{
00291 public: // everything is local to this file anyway...
00292 
00293     int value;         // our value (the number of free slots).
00294     // lower values are lower in the heap.
00295     int  hID;      // the id in the heap
00296 
00297     tMemManager *myman;
00298 
00299     int size;
00300     unsigned char first_free;
00301 
00302 
00303     ~memblock(){
00304         if (myman) myman->blocks.Remove(this,hID);
00305         //tASSERT(myman->blocksize == value);
00306     }
00307 
00308     chunkinfo & chunk(int i){
00309         tASSERT(i>=0 && i<myman->blocksize);
00310         return *(
00311                    (chunkinfo *)(void *)
00312                    ( ( (char *)(this+1) )+(sizeof(chunkinfo)+size+SAFETYBYTES)*i)
00313                );
00314     }
00315 
00316     char * safety(int i){
00317         tASSERT(i>=0 && i<myman->blocksize);
00318         return (
00319                    ( ( (char *)(this+1) )+(sizeof(chunkinfo)+size+SAFETYBYTES)*i)
00320                    +sizeof(chunkinfo)+size );
00321     }
00322 
00323     void * data(int i){
00324         tASSERT(i>=0 && i<myman->blocksize);
00325         return  (void *)
00326                 ( ( (char *)(this+1) )+(sizeof(chunkinfo)+size+SAFETYBYTES)*i + sizeof(chunkinfo));
00327     }
00328 
00329 
00330     memblock(tMemManager *man):value(man->blocksize),hID(-1),myman(man){
00331         //    std::cout << "new memblock..\n";
00332         size=man->size;
00333         myman->blocks.Add(this,hID);
00334 
00335         // TODO: init linked list
00336 
00337         for (int i=man->blocksize-1 ; i>=0 ; i--){
00338             if (i<man->blocksize-1)
00339                 chunk(i).next=i+2;
00340             else
00341                 chunk(i).next=0;
00342 
00343             if (i>0)
00344                 chunk(i).prev=i;
00345             else
00346                 chunk(i).prev=0;
00347 
00348             chunk(i).pos = i;
00349             chunk(i).occupied = false;
00350             chunk(i).size_in_dwords = size >> 2;
00351 
00352             for (int j=SAFETYBYTES-1;j>=0;j--)
00353                 safety(i)[j]=(j ^ PAD);
00354         }
00355 
00356 #ifdef MEM_DEB
00357         Check();
00358 #endif
00359 
00360         first_free=1;
00361     }
00362 
00363 
00364     void *Alloc( tAllocationInfo const & info ){
00365 #ifdef MEM_DEB_SMALL
00366         Check();
00367 #endif
00368 
00369 
00370         tASSERT(value>0);
00371         value--;
00372 
00373         // TODO: faster using linked list
00374 
00375         int ret=-1;
00376         /*
00377           for (int i=myman->blocksize-1 ; i>=0 ; i--)
00378           if (!chunk(i).occupied){
00379           //      chunk(i).occupied=true;
00380           ret=i;
00381           i=-1;
00382           //  return data(i);
00383           }*/
00384 
00385 
00386         ret=first_free-1;
00387         tASSERT(ret>=0);
00388         // tASSERT(_CrtCheckMemory());
00389 
00390         chunk(ret).occupied=true;
00391         first_free=chunk(ret).next;
00392         //  tASSERT(_CrtCheckMemory());
00393         if (first_free>0) chunk(first_free-1).prev=0;
00394 
00395         chunk(ret).next=chunk(ret).prev=0;
00396         //   tASSERT(_CrtCheckMemory());
00397 
00398 #ifdef LEAKFINDER
00399         if (info.checksum >= 0){
00400             tASSERT(info.checksum < MAXCHECKSUM);
00401 
00402 #ifdef PROFILER
00403             if (!counter[info.checksum]){
00404                 checksum_filename [info.checksum] = info.filename;
00405                 checksum_classname[info.checksum] = info.classname;
00406                 checksum_line     [info.checksum] = info.line;
00407             }
00408             checksum_blocks[info.checksum]++;
00409             checksum_bytes[info.checksum]+=size;
00410             chunk(ret).realSize = size;
00411 #endif
00412             chunk(ret).array=info.array;
00413             chunk(ret).checksum=info.checksum;
00414             chunk(ret).counter =++counter[info.checksum];
00415 
00416             static int count =0;
00417             if (checkleaks && counter[info.checksum] == leaks[info.checksum]){
00418                 count ++;
00419                 if (count <= 0)
00420                 {
00421                     std::cerr << "one of the endless ignored objects that were leaky last time created!\n";
00422                 }
00423                 else if (count <= 1)
00424                 {
00425                     std::cerr << "Object that was leaky last time created!\n";
00426                     st_Breakpoint();
00427                 }
00428                 else if (count <= 3)
00429                 {
00430                     std::cerr << "One more object that was leaky last time created!\n";
00431                     st_Breakpoint();
00432                 }
00433                 else
00434                 {
00435                     std::cerr << "one of the endless objects that were leaky last time created!\n";
00436                     //      st_Breakpoint();
00437                 }
00438             }
00439         }
00440 #endif
00441 
00442 #ifdef LEAKFINDER
00443 #ifdef PROFILER
00444         chunk(ret).realSize = size;
00445 #endif
00446         chunk(ret).array=info.array;
00447         chunk(ret).checksum=info.checksum;
00448 #endif
00449 
00450 #ifdef DEBUG
00451         wmemset(static_cast< wchar_t * >( data(ret) ), wchar_t(0xfedabeef), size / sizeof( wchar_t ));
00452 #else
00453         wmemset(static_cast< wchar_t * >( data(ret) ), 0, size / sizeof( wchar_t ));
00454 #endif
00455 
00456 #ifdef MEM_DEB_SMALL
00457         Check();
00458 #endif
00459 
00460         return data(ret);
00461 
00462         tASSERT(0); // we should never get here
00463         return NULL;
00464     }
00465 
00466     static memblock * Dispose(void *p, int &size, tAllocationInfo const & info, bool keep=false){
00467         chunkinfo &c=((chunkinfo *)p)[-1];
00468         size=c.size_in_dwords*4;
00469 
00470 #ifdef PROFILER
00471         if (c.checksum >=0 && c.checksum < MAXCHECKSUM){
00472             checksum_blocks[c.checksum]--;
00473             checksum_bytes [c.checksum]-=c.realSize;
00474         }
00475 #else
00476 #ifdef LEAKFINDER
00477         tASSERT(c.checksum>=-1 && c.checksum < MAXCHECKSUM);
00478 #endif
00479 #endif
00480 
00481 #ifndef WIN32 // grr. on windows, this assertion fails on calls from STL.
00482         tASSERT( c.array == info.array );
00483 #endif
00484 
00485         if (size==0){
00486             bool o = c.occupied;
00487             // tASSERT(c.occupied);
00488             c.occupied=false;
00489             if (o) free(&c);
00490             return NULL;
00491         }
00492 
00493         tASSERT(c.occupied == 1);
00494         if (!c.occupied)
00495             return NULL;
00496 
00497 #ifdef DEBUG
00498         wmemset(static_cast< wchar_t * >( p ), wchar_t(0xbadf00d), size / sizeof( wchar_t ));
00499 #else
00500         wmemset(static_cast< wchar_t * >( p ), 0, size / sizeof( wchar_t ) );
00501 #endif
00502 
00503         memblock *myblock=(
00504                               (memblock *)(void *)
00505                               (
00506                                   ( (char *)(void *)p ) -
00507                                   ( (sizeof(chunkinfo)+size+SAFETYBYTES)*c.pos
00508                                     + sizeof(chunkinfo) )
00509                               ) ) - 1;
00510 
00511         c.occupied=false;
00512 
00513 
00514 
00515 #ifndef DOUBLEFREEFINDER
00516         if (keep)
00517             return NULL;
00518 
00519 #ifdef WIN32
00520         EnterCriticalSection(&mutex);
00521 #endif
00522 
00523         tASSERT(myblock -> value < myblock->myman->blocksize);
00524         c.prev=0;
00525         c.next=myblock->first_free;
00526         myblock->first_free=c.pos+1;
00527         if (c.next)   myblock->chunk(c.next-1).prev=c.pos+1;
00528 
00529         myblock->value++;
00530 #endif
00531 
00532         // TODO:  use linked list
00533         return myblock;
00534     }
00535 
00536     static memblock * create(tMemManager *man){
00537         //tASSERT(_CrtCheckMemory());
00538         void *mem = malloc(man->blocksize * (SAFETYBYTES + man->size + sizeof(chunkinfo))
00539                            + sizeof(memblock));
00540         //  tASSERT(_CrtCheckMemory());
00541         return new(mem) memblock(man);
00542     }
00543 
00544     static void destroy(memblock * b){
00545         b->~memblock();
00546         free((void *)b);
00547     }
00548 
00549     void  Check(){
00550 #ifdef DEBUG
00551         tASSERT (size == myman->size);
00552 
00553         tASSERT (value >=0);
00554         tASSERT (value <= myman->blocksize);
00555 
00556         for(int i=myman->blocksize-1;i>=0;i--){
00557             tASSERT(chunk(i).pos == i);
00558 
00559             for (int j=SAFETYBYTES-1;j>=0;j--){
00560                 char a=safety(i)[j];
00561                 char b=j^PAD;
00562                 tASSERT(a==b);
00563             }
00564         }
00565 #endif
00566     }
00567 
00568 #ifdef LEAKFINDER
00569     void dumpleaks(std::ostream &s){
00570         for (int i=myman->blocksize-1;i>=0;i--)
00571             if (chunk(i).occupied && chunk(i).checksum >= 0 ){
00572                 s << chunk(i).checksum << " " << chunk(i).counter << '\n';
00573                 leak();
00574             }
00575     }
00576 #endif
00577 };
00578 
00579 
00580 
00581 
00582 
00583 // ***********************************************
00584 
00585 
00586 
00587 
00588 
00589 bool tMemManager::SwapIf(int i,int j){
00590     if (i==j || i<0) return false; // safety
00591 
00592     memblock *e1=blocks(i),*e2=blocks(j);
00593     if (e1->value > e2->value){
00594         Swap(blocks(i),blocks(j));
00595         e1->hID=j;
00596         e2->hID=i;
00597         return true;
00598     }
00599     else
00600         return false;
00601 
00602 }
00603 
00604 tMemManager::~tMemManager(){
00605 #ifdef LEAKFINDER
00606     bool warn = true;
00607 #ifdef HAVE_LIBZTHREAD
00608     warn = false;
00609 #endif
00610 
00611     if (inited){
00612         // l???sche das ding
00613         std::ofstream lw(leakname);
00614         lw << "\n\n";
00615         tMemMan::Profile();
00616     }
00617 #endif
00618 
00619 #ifdef WIN32
00620     if (inited)
00621         DeleteCriticalSection(&mutex);
00622 #endif
00623 
00624     inited = false;
00625 
00626     //tASSERT (full_blocks.Len() == 0);
00627     int i;
00628     for (i=blocks.Len()-1;i>=0;i--){
00629         if (blocks(i)->value==blocksize)
00630             memblock::destroy(blocks(i));
00631         else{
00632 #ifdef LEAKFINDER
00633             if ( warn )
00634             {
00635                 std::cout << "Memmanager warning: leaving block untouched.\n";
00636                 warn = false;
00637             }
00638             std::ofstream l(leakname,std::ios::app);
00639             blocks(i)->dumpleaks(l);
00640 #endif
00641         }
00642     }
00643 
00644     for (i=full_blocks.Len()-1;i>=0;i--){
00645         if (full_blocks(i)->value==blocksize)
00646             memblock::destroy(full_blocks(i));
00647         else{
00648 #ifdef LEAKFINDER
00649             if ( warn )
00650             {
00651                 std::cout << "Memmanager warning: leaving block untouched.\n";
00652                 warn = false;
00653             }
00654             std::ofstream l(leakname,std::ios::app);
00655             full_blocks(i)->dumpleaks(l);
00656 #endif
00657         }
00658     }
00659 
00660 }
00661 
00662 tMemManager::tMemManager(int s,int bs):size(s),blocksize(s){
00663     // std::cout << sizeof(chunkinfo);
00664     if (blocksize>255)
00665         blocksize=255;
00666     semaphore = 1;
00667 
00668     tBottleNeck neck;
00669 
00670 #ifdef WIN32
00671     if (!inited)
00672         InitializeCriticalSection(&mutex);
00673 #endif
00674 
00675     inited = true;
00676 }
00677 
00678 tMemManager::tMemManager(int s):size(s){//,blocks(1000),full_blocks(1000){
00679     tBottleNeck neck;
00680 
00681     inited = false;
00682 
00683     blocks.SetLen(0);
00684     full_blocks.SetLen(0);
00685     blocksize=16000/(s+sizeof(chunkinfo)+SAFETYBYTES);
00686     if (blocksize>252)
00687         blocksize=252;
00688     //  std::cout << sizeof(chunkinfo) << ',' << s << ',' << blocksize << '\n';
00689     semaphore = 1;
00690 
00691 #ifdef LEAKFINDER
00692     if (size == 0){
00693         for ( int i = MAXCHECKSUM-1; i>=0; --i )
00694         {
00695             leaks[i] = 0;
00696             counter[i] = 0;
00697 #ifdef PROFILER
00698             checksum_filename[i] = 0;
00699             checksum_classname[i] = 0;
00700             checksum_line[i] = 0;
00701             checksum_blocks[i] = 0;
00702             checksum_bytes[i] = 0;
00703 #endif
00704         }
00705 
00706         std::ifstream l(leakname);
00707         while (l.good() && !l.eof()){
00708             int cs,ln;
00709             l >> cs >> ln;
00710 
00711             if (cs>=0 && cs < MAXCHECKSUM && (ln < leaks[cs] || leaks[cs] == 0))
00712                 leaks[cs]=ln;
00713         }
00714     }
00715     if (!inited){
00716         // delete it
00717         std::ofstream lw(leakname);
00718         lw << "\n\n";
00719     }
00720 #endif
00721 
00722 #ifdef WIN32
00723     if (!inited)
00724         InitializeCriticalSection(&mutex);
00725 #endif
00726 
00727     inited = true;
00728 }
00729 
00730 //#ifdef MEM_DEB
00731 void tMemManager::CheckHeap(){
00732     for(int i=blocks.Len()-1;i>0;i--){
00733         memblock *current=blocks(i);
00734         memblock *low=blocks(Lower(i));
00735         if (Lower(UpperL(i))!=i || Lower(UpperR(i))!=i)
00736             tERR_ERROR_INT("Error in lower/upper " << i << "!");
00737 
00738         if (low->value>current->value)
00739             tERR_ERROR_INT("Heap structure corrupt!");
00740     }
00741 }
00742 //#endif
00743 
00744 void tMemManager::SwapDown(int j){
00745     int i=j;
00746     // e is now at position i. swap it down
00747     // as far as it goes:
00748     do{
00749         j=i;
00750         i=Lower(j);
00751     }
00752     while(SwapIf(i,j)); // mean: relies on the fact that SwapIf returns -1
00753     // if i<0.
00754 
00755 #ifdef MEM_DEB
00756     CheckHeap();
00757 #endif
00758 }
00759 
00760 void tMemManager::SwapUp(int i){
00761 #ifdef MEM_DEB
00762     //  static int su=0;
00763     //if (su%100 ==0 )
00764     // std::cout << "su=" << su << '\n';
00765     //  if (su > 11594 )
00766     // con << "su=" << su << '\n';
00767     // su ++;
00768 #endif
00769 
00770     int ul,ur;
00771     bool goon=1;
00772     while(goon && UpperL(i)<blocks.Len()){
00773         ul=UpperL(i);
00774         ur=UpperR(i);
00775         if(ur>=blocks.Len() ||
00776                 blocks(ul)->value < blocks(ur)->value){
00777             goon=SwapIf(i,ul);
00778             i=ul;
00779         }
00780         else{
00781             goon=SwapIf(i,ur);
00782             i=ur;
00783         }
00784     }
00785 
00786 #ifdef MEM_DEB
00787     CheckHeap();
00788 #endif
00789 
00790 }
00791 
00792 void tMemManager::Insert(memblock *e){
00793     blocks.Add(e,e->hID); // relies on the implementation of List: e is
00794     // put to the back of the heap.
00795     SwapDown(blocks.Len()-1); // bring it to the right place
00796 
00797 #ifdef MEM_DEB
00798     CheckHeap();
00799 #endif
00800 }
00801 
00802 void tMemManager::Remove(memblock *e){
00803     int i=e->hID;
00804 
00805     if(i<0 || this != e->myman)
00806         tERR_ERROR_INT("Element is not in this heap!");
00807 
00808     Remove(i);
00809 
00810 #ifdef MEM_DEB
00811     CheckHeap();
00812 #endif
00813 }
00814 
00815 void tMemManager::Replace(int i){
00816     if (i>=0 && i < blocks.Len()){
00817         if (i==0 || blocks(i)->value > blocks(Lower(i))->value)
00818             SwapUp(i);          // put it up where it belongs
00819         else
00820             SwapDown(i);
00821 
00822 #ifdef MEM_DEB
00823         CheckHeap();
00824 #endif
00825     }
00826 }
00827 
00828 void tMemManager::Replace(memblock *e){
00829     int i=e->hID;
00830 
00831     if(i<0 || this != e->myman)
00832         tERR_ERROR_INT("Element is not in this heap!");
00833 
00834     Replace(i);
00835 
00836 #ifdef MEM_DEB
00837     CheckHeap();
00838 #endif
00839 }
00840 
00841 memblock * tMemManager::Remove(int i){
00842     if (i>=0 && i<blocks.Len()){
00843         memblock *ret=blocks(i);
00844 
00845         blocks.Remove(ret,ret->hID);
00846 
00847         // now we have an misplaced element at pos i. (if i was not at the end..)
00848         if (i<blocks.Len())
00849             Replace(i);
00850 
00851 #ifdef MEM_DEB
00852         CheckHeap();
00853 #endif
00854 
00855         return ret;
00856     }
00857     return NULL;
00858 }
00859 
00860 void * tMemManager::Alloc( tAllocationInfo const & info ){
00861     semaphore--;
00862     if (semaphore<0 || size == 0){
00863         semaphore++;
00864         return AllocDefault(info, size);
00865     }
00866 
00867 #ifdef WIN32
00868     EnterCriticalSection(&mutex);
00869 #endif
00870 
00871     if (blocks.Len()==0) // no free space available. create new block...
00872         Insert(memblock::create(this));
00873     //tASSERT(_CrtCheckMemory());
00874 
00875     memblock *block=blocks(0);
00876     tASSERT (block->size == size);
00877     void *mem = block->Alloc( info );
00878     //tASSERT(_CrtCheckMemory());
00879     if (block->value == 0){
00880         Remove(block);
00881         full_blocks.Add(block,block->hID);
00882     }
00883 
00884 #ifdef WIN32
00885     LeaveCriticalSection(&mutex);
00886 #endif
00887 
00888     semaphore++;
00889     return mem;
00890 }
00891 
00892 void tMemManager::complete_Dispose(memblock *block){
00893 #ifdef MEM_DEB_SMALL
00894     block->Check();
00895 #endif
00896 
00897     semaphore--;
00898     if (semaphore>=0){
00899         if (block->value == 1){
00900             full_blocks.Remove(block,block->hID);
00901             Insert(block);
00902         }
00903         else{
00904             Replace(block);
00905         }
00906     }
00907     //else
00908     // tASSERT(0);
00909     semaphore++;
00910 
00911 #ifdef MEM_DEB_SMALL
00912     block->Check();
00913 #endif
00914 }
00915 
00916 void tMemManager::Check(){
00917 #ifdef DEBUG_EXPENSIVE
00918     if ( !inited )
00919         return;
00920 
00921     CheckHeap();
00922     int i;
00923     for (i=blocks.Len()-1;i>=0;i--)
00924     {
00925         blocks(i)->Check();
00926         tASSERT (blocks(i)->myman == this);
00927         tASSERT (blocks(i)->size == size);
00928     }
00929     for (i=full_blocks.Len()-1;i>=0;i--)
00930     {
00931         if ( full_blocks(i) )
00932         {
00933             full_blocks(i)->Check();
00934             tASSERT (full_blocks(i)->myman == this);
00935             tASSERT (full_blocks(i)->size == size);
00936         }
00937     }
00938 #endif
00939 }
00940 
00941 
00942 #define MAX_SIZE 109
00943 
00944 
00945 static tMemManager memman[MAX_SIZE+1]={
00946                                           tMemManager(0),
00947                                           tMemManager(4),
00948                                           tMemManager(8),
00949                                           tMemManager(12),
00950                                           tMemManager(16),
00951                                           tMemManager(20),
00952                                           tMemManager(24),
00953                                           tMemManager(28),
00954                                           tMemManager(32),
00955                                           tMemManager(36),
00956                                           tMemManager(40),
00957                                           tMemManager(44),
00958                                           tMemManager(48),
00959                                           tMemManager(52),
00960                                           tMemManager(56),
00961                                           tMemManager(60),
00962                                           tMemManager(64),
00963                                           tMemManager(68),
00964                                           tMemManager(72),
00965                                           tMemManager(76),
00966                                           tMemManager(80),
00967                                           tMemManager(84),
00968                                           tMemManager(88),
00969                                           tMemManager(92),
00970                                           tMemManager(96),
00971                                           tMemManager(100),
00972                                           tMemManager(104),
00973                                           tMemManager(108),
00974                                           tMemManager(112),
00975                                           tMemManager(116),
00976                                           tMemManager(120),
00977                                           tMemManager(124),
00978                                           tMemManager(128),
00979                                           tMemManager(132),
00980                                           tMemManager(136),
00981                                           tMemManager(140),
00982                                           tMemManager(144),
00983                                           tMemManager(148),
00984                                           tMemManager(152),
00985                                           tMemManager(156),
00986                                           tMemManager(160),
00987                                           tMemManager(164),
00988                                           tMemManager(168),
00989                                           tMemManager(172),
00990                                           tMemManager(176),
00991                                           tMemManager(180),
00992                                           tMemManager(184),
00993                                           tMemManager(188),
00994                                           tMemManager(192),
00995                                           tMemManager(196),
00996                                           tMemManager(200),
00997                                           tMemManager(204),
00998                                           tMemManager(208),
00999                                           tMemManager(212),
01000                                           tMemManager(216),
01001                                           tMemManager(220),
01002                                           tMemManager(224),
01003                                           tMemManager(228),
01004                                           tMemManager(232),
01005                                           tMemManager(236),
01006                                           tMemManager(240),
01007                                           tMemManager(244),
01008                                           tMemManager(248),
01009                                           tMemManager(252),
01010                                           tMemManager(256),
01011                                           tMemManager(260),
01012                                           tMemManager(264),
01013                                           tMemManager(268),
01014                                           tMemManager(272),
01015                                           tMemManager(276),
01016                                           tMemManager(280),
01017                                           tMemManager(284),
01018                                           tMemManager(288),
01019                                           tMemManager(292),
01020                                           tMemManager(296),
01021                                           tMemManager(300),
01022                                           tMemManager(304),
01023                                           tMemManager(308),
01024                                           tMemManager(312),
01025                                           tMemManager(316),
01026                                           tMemManager(320),
01027                                           tMemManager(324),
01028                                           tMemManager(328),
01029                                           tMemManager(332),
01030                                           tMemManager(336),
01031                                           tMemManager(340),
01032                                           tMemManager(344),
01033                                           tMemManager(348),
01034                                           tMemManager(352),
01035                                           tMemManager(356),
01036                                           tMemManager(360),
01037                                           tMemManager(364),
01038                                           tMemManager(368),
01039                                           tMemManager(372),
01040                                           tMemManager(376),
01041                                           tMemManager(380),
01042                                           tMemManager(384),
01043                                           tMemManager(388),
01044                                           tMemManager(392),
01045                                           tMemManager(396),
01046                                           tMemManager(400),
01047                                           tMemManager(404),
01048                                           tMemManager(408),
01049                                           tMemManager(412),
01050                                           tMemManager(416),
01051                                           tMemManager(420),
01052                                           tMemManager(424),
01053                                           tMemManager(428),
01054                                           tMemManager(432),
01055                                           tMemManager(436)
01056                                       };
01057 
01058 
01059 void tMemManager::Dispose(tAllocationInfo const & info, void *p, bool keep){
01060     int size;
01061 
01062     if (!p)
01063         return;
01064 
01065     memblock *block = memblock::Dispose(p,size,info, keep);
01066 #ifndef DOUBLEFREEFINDER
01067     if (inited && block){
01068         tBottleNeck neck;
01069         memman[size >> 2].complete_Dispose(block);
01070 #ifdef WIN32
01071         LeaveCriticalSection(&mutex);
01072 #endif
01073     }
01074 #else
01075     block = 0;
01076 #endif
01077 }
01078 
01079 void *tMemManager::AllocDefault(tAllocationInfo const & info, size_t s){
01080 #ifdef LEAKFINDER
01081     void *ret=malloc(s+sizeof(chunkinfo));//,classname,fileName,line);
01082     ((chunkinfo *)ret)->checksum=info.checksum;
01083     ((chunkinfo *)ret)->array=info.array;
01084 #ifdef PROFILER
01085     ((chunkinfo *)ret)->realSize=s;
01086     if ( info.checksum >= 0 )
01087     {
01088         if (!counter[info.checksum]){
01089             checksum_filename [info.checksum] = info.filename;
01090             checksum_classname[info.checksum] = info.classname;
01091             checksum_line     [info.checksum] = info.line;
01092         }
01093         checksum_blocks[info.checksum]++;
01094         checksum_bytes[info.checksum]+=s;
01095     }
01096 #endif
01097 #else
01098     void *ret=malloc(s+sizeof(chunkinfo));
01099 #endif
01100     ((chunkinfo *)ret)->size_in_dwords=0;
01101     ((chunkinfo *)ret)->occupied=true;
01102     ret = ((chunkinfo *)ret)+1;
01103     return ret;
01104 }
01105 
01106 void *tMemMan::Alloc(tAllocationInfo const & info, size_t s){
01107 #ifndef DONTUSEMEMMANAGER
01108 #ifdef MEM_DEB
01109 #ifdef WIN32
01110     tASSERT(_CrtCheckMemory());
01111 #endif
01112     Check();
01113 #endif
01114     void *ret;
01115     if (inited && s < (MAX_SIZE << 2))
01116     {
01117         tBottleNeck neck;
01118         ret=memman[((s+3)>>2)].Alloc( info );
01119     }
01120     else
01121     {
01122         ret=tMemManager::AllocDefault(info, s);
01123     }
01124 #ifdef MEM_DEB
01125     Check();
01126 #ifdef WIN32
01127     tASSERT(_CrtCheckMemory());
01128 #endif
01129 #endif
01130     return ret;
01131 
01132 #else
01133     return malloc(s);
01134 #endif
01135 
01136 }
01137 
01138 void tMemMan::DisposeButKeep( tAllocationInfo const & info, void *p){
01139 #ifndef DONTUSEMEMMANAGER
01140 #ifdef MEM_DEB
01141 #ifdef WIN32
01142     tASSERT(_CrtCheckMemory());
01143 #endif
01144     Check();
01145 #endif
01146     tMemManager::Dispose(info, p, true);
01147 #ifdef MEM_DEB
01148     Check();
01149 #ifdef WIN32
01150     tASSERT(_CrtCheckMemory());
01151 #endif
01152 #endif
01153 #endif
01154 }
01155 
01156 void tMemMan::Dispose(tAllocationInfo const & info, void *p){
01157 #ifndef DONTUSEMEMMANAGER
01158 #ifdef MEM_DEB
01159 #ifdef WIN32
01160     tASSERT(_CrtCheckMemory());
01161 #endif
01162     Check();
01163 #endif
01164     tMemManager::Dispose(info, p );
01165 #ifdef MEM_DEB
01166     Check();
01167 #ifdef WIN32
01168     tASSERT(_CrtCheckMemory());
01169 #endif
01170 #endif
01171 #else
01172     free(p);
01173 #endif
01174 }
01175 
01176 
01177 void tMemManBase::Check(){
01178     if (!inited)
01179         return;
01180 
01181 #ifdef WIN32
01182     EnterCriticalSection(&mutex);
01183 #endif
01184 
01185     for (int i=MAX_SIZE;i>=0;i--)
01186         memman[i].Check();
01187 
01188 #ifdef WIN32
01189     LeaveCriticalSection(&mutex);
01190 #endif
01191 }
01192 
01193 /*
01194         void* operator new      (unsigned int size) {   
01195                 //return zmalloc.Malloc (size, "UNKNOWN", "zMemory.cpp", 49);
01196         // return malloc(size);
01197         return tMemManager::AllocDefault(size);
01198         };
01199         void  operator delete(void *ptr) {      
01200                 if (ptr) tMemManager::Dispose(ptr);
01201         // zmalloc.Free(ptr);                                                    
01202         }; 
01203 */
01204 
01205 #ifdef NEW
01206 /*
01207 void * operator new(
01208         unsigned int cb,
01209         int nBlockUse,
01210         const char * szFileName,
01211         int nLine
01212         )
01213 {
01214     return operator new(cb, "xxx", szFileName, nLine);
01215 }
01216 */
01217 
01218 #ifdef WIN32
01219 #ifdef DEDICATED
01220 #ifdef DEBUG
01221 #if 0
01222 void * operator new(
01223     size_t size,
01224     int nBlockUse,
01225     const char * file,
01226     int l
01227 )
01228 {
01229 #ifdef LEAKFINDER
01230     fileName=file;
01231     classname="XXX";
01232     line=l;
01233 
01234     checksum =
01235 #ifndef PROFILER 
01236         size +
01237 #endif 
01238         line * 19671;
01239 
01240     checksum = checksum % MAXCHECKSUM;
01241     int c=1379;
01242     while (*file){
01243         checksum = (checksum + (*file)*c) % MAXCHECKSUM;
01244         c        = (c * 79              ) % MAXCHECKSUM;
01245         file++;
01246     }
01247 
01248 #ifdef PROFILER
01249     while (checksum_fileName[checksum] && (checksum_fileName[checksum] != fileName || checksum_line[checksum] != line))
01250         checksum = (checksum+1) % MAXCHECKSUM;
01251 #endif
01252 
01253 #endif
01254     return tMemMan::Alloc(size);
01255 
01256     //      return _nh_malloc_dbg( cb, 1, nBlockUse, szFileName, nLine );
01257 }
01258 #endif
01259 #endif
01260 #endif
01261 #endif
01262 
01263 
01264 void* _cdecl operator new	(size_t size) THROW_BADALLOC{
01265     tAllocationInfo info( false );
01266 
01267 #ifdef LEAKFINDER
01268 #ifndef HAVE_LIBZTHREAD
01269     info.checksum = size;
01270 #endif
01271 #endif
01272     return tMemMan::Alloc(info, size);
01273 }
01274 
01275 void  _cdecl operator delete(void *ptr) THROW_NOTHING{
01276     tAllocationInfo info( false );
01277 
01278     if (ptr)
01279         tMemMan::Dispose(info, ptr);
01280 }
01281 
01282 void  operator delete(void *ptr,bool keep) THROW_NOTHING{
01283     tAllocationInfo info( false );
01284 
01285     if (ptr){
01286         if (keep)
01287             tMemMan::DisposeButKeep(info, ptr);
01288         else
01289             tMemMan::Dispose(info, ptr);
01290         
01291     }
01292 }
01293 
01294 
01295 
01296 void* operator new	(size_t size,const char *classn,const char *file,int l) THROW_BADALLOC{
01297     tAllocationInfo info( false );
01298 #ifdef LEAKFINDER
01299     info.filename=file;
01300     info.classname=classn;
01301     info.line=l;
01302 
01303     info.checksum =
01304 #ifndef PROFILER 
01305         size +
01306 #endif 
01307         info.line * 19671;
01308 
01309     int c=1379;
01310     while (*file){
01311         info.checksum = (info.checksum + (*file)*c) % MAXCHECKSUM;
01312         c             = (c * 79              ) % MAXCHECKSUM;
01313         file++;
01314     }
01315     while (*classn){
01316         info.checksum = (info.checksum + (*classn)*c) % MAXCHECKSUM;
01317         c             = (c * 79                ) % MAXCHECKSUM;
01318         classn++;
01319     }
01320 
01321 #ifdef PROFILER
01322     while (checksum_filename[info.checksum] && (checksum_filename[info.checksum] != info.filename || checksum_line[info.checksum] != info.line))
01323     info.checksum = (info.checksum+1) % MAXCHECKSUM;
01324 #endif
01325 
01326 #endif
01327     return tMemMan::Alloc(info, size);
01328 }
01329 
01330 void  operator delete   (void *ptr,const char *classname,const char *file,int line)  THROW_NOTHING{
01331     tAllocationInfo info( false );
01332 
01333     if (ptr) tMemMan::Dispose(info, ptr);
01334 }
01335 
01336 void* operator new[]	(size_t size) THROW_BADALLOC{
01337     tAllocationInfo info( true );
01338 #ifdef LEAKFINDER
01339 #ifndef HAVE_LIBZTHREAD
01340     info.checksum = size % MAXCHECKSUM;
01341 #endif
01342 #endif
01343     return tMemMan::Alloc(info, size);
01344 }
01345 
01346 void  operator delete[](void *ptr) THROW_NOTHING {
01347     tAllocationInfo info( true );
01348 
01349     if (ptr)
01350         tMemMan::Dispose(info, ptr);
01351 }
01352 
01353 
01354 
01355 void* operator new[]	(size_t size,const char *classn,const char *file,int l)  THROW_BADALLOC{
01356     tAllocationInfo info( true );
01357 #ifdef LEAKFINDER
01358     info.filename=file;
01359     info.classname=classn;
01360     info.line=l;
01361 
01362     info.checksum =
01363 #ifndef PROFILER 
01364     size +
01365 #endif 
01366     info.line * 19671;
01367     
01368     int c=1379;
01369     while (*file){
01370         info.checksum = (info.checksum + (*file)*c) % MAXCHECKSUM;
01371         c             = (c * 79              ) % MAXCHECKSUM;
01372         file++;
01373     }
01374     while (*classn){
01375         info.checksum = (info.checksum + (*classn)*c) % MAXCHECKSUM;
01376         c             = (c * 79                ) % MAXCHECKSUM;
01377         classn++;
01378     }
01379     
01380 #ifdef PROFILER
01381     while (checksum_filename[info.checksum] && (checksum_filename[info.checksum] != info.filename || checksum_line[info.checksum] != info.line))
01382     info.checksum = (info.checksum+1) % MAXCHECKSUM;
01383 #endif
01384 
01385 #endif
01386     return tMemMan::Alloc(info, size);
01387 }
01388 
01389 void  operator delete[]   (void *ptr,const char *classname,const char *file,int line)   THROW_NOTHING{
01390     tAllocationInfo info( true );
01391 
01392     if (ptr) tMemMan::Dispose(info, ptr);
01393 }
01394 
01395 #endif
01396 
01397 
01398 
01399 
01400 #ifdef PROFILER
01401     static int compare(const void *a, const void *b){
01402         int A = checksum_bytes[*((const int *)a)];
01403         int B = checksum_bytes[*((const int *)b)];
01404 
01405         if (A<B)
01406             return -1;
01407         if (A>B)
01408             return 1;
01409 
01410         return 0;
01411     }
01412 
01413 //#define PRINT(blocks, size, c, f, l, cs) s << std::setw(6) << blocks << "\t" << std::setw(9) << size << "\t" << std::setw(20) <<  c << "\t" << std::setw(70) <<  f << "\t" << std::setw(6) << l << "\t" << cs << "\n"
01414 
01415 //#define PRINT(blocks, size, c, f, l, cs) fprintf("%d:6% std::setw(6) << blocks << "\t" << std::setw(9) << size << "\t" << std::setw(20) <<  c << "\t" << std::setw(70) <<  f << "\t" << std::setw(6) << l << "\t" << cs << "\n"
01416 
01417 #endif
01418 
01419 
01420 #ifdef WIN32
01421 #define snprintf _snprintf
01422 #endif
01423 
01424 void  tMemManBase::Profile(){
01425     tBottleNeck neck;
01426 #ifdef PROFILER
01427 
01428     int sort_checksum[MAXCHECKSUM];
01429     int size=0,i;
01430 
01431     for (i=MAXCHECKSUM-1;i>=0;i--)
01432         if (checksum_blocks[i])
01433             sort_checksum[size++] = i;
01434 
01435     qsort(sort_checksum, size, sizeof(int), &compare);
01436 
01437     static int num=1;
01438 
01439     char name[100];
01440     snprintf( name, 99, "memprofile%d.txt", num++ );
01441     //    std::ostringstream fn;
01442 
01443     //    fn << "memprofile" << num++ << ".txt" << '\0';
01444 
01445 
01446     FILE *f = fopen( name, "w" );
01447     //  fprintf( f, "%d\t%d\t%d\t%s\t%s\t%d\t%d\t\n", )
01448 
01449     int total_blocks=0,total_bytes =0;
01450 
01451     for (i=size-1; i>=0; i--)
01452     {
01453         int cs = sort_checksum[i];
01454         const char *fn = checksum_filename[cs];
01455         const char *cn = checksum_classname[cs];
01456 
01457         if (!fn)
01458             fn = "XXX";
01459         if (!cn)
01460             cn = "XXX";
01461 
01462         fprintf( f, "%d\t%d\t%30s\t%80s\t%d\t%d\t\n", checksum_blocks[cs], checksum_bytes[cs],cn, fn , checksum_line[cs], cs );
01463         //        PRINT(checksum_blocks[cs], checksum_bytes[cs],cn, fn , checksum_line[cs], cs);
01464         total_blocks += checksum_blocks[cs];
01465         total_bytes += checksum_bytes[cs];
01466     }
01467 
01468     fclose( f );
01469 
01470 
01471     /*
01472         std::ofstream s( name );
01473         s.setf(std::ios::left);
01474 
01475         PRINT("Blocks", "Bytes", "Class", "File", "Line", "Checksum");
01476 
01477         int total_blocks=0,total_bytes =0;
01478 
01479         for (i=size-1; i>=0; i--)
01480         {
01481             int cs = sort_checksum[i];
01482             const char *fn = checksum_fileName[cs];
01483             const char *cn = checksum_classname[cs];
01484 
01485             if (!fn)
01486                 fn = "XXX";
01487             if (!cn)
01488                 cn = "XXX";
01489 
01490             PRINT(checksum_blocks[cs], checksum_bytes[cs],cn, fn , checksum_line[cs], cs);     
01491             total_blocks += checksum_blocks[cs];
01492             total_bytes += checksum_bytes[cs];
01493         }
01494 
01495         s << "\n\n";
01496         PRINT (total_blocks, total_bytes, "Total" , "", "", "");
01497     */
01498 #endif
01499 }
01500 
01501 #ifdef HAVE_LIBEFENCE
01502 class eFence
01503 {
01504 public:
01505     eFence()
01506     {
01507         EF_newFrame();
01508     }
01509     ~eFence()
01510     {
01511         EF_delFrame();
01512     }
01513 };
01514 
01515 static eFence fence;
01516 #endif
01517 
01518 #ifndef DONTUSEMEMMANAGER
01519 void * real_calloc( size_t nmemb, size_t size ) // call calloc
01520 {
01521     return calloc( nmemb, size );
01522 }
01523 
01524 void * real_malloc( size_t size )                // call malloc
01525 {
01526     return malloc( size );
01527 }
01528 
01529 void   real_free( void * ptr )                   // call free
01530 {
01531     free( ptr );
01532 }
01533 
01534 void * real_realloc( void * ptr, size_t size )   // call realloc
01535 {
01536     return realloc( ptr, size );
01537 }
01538 
01539 char * real_strdup( char const * ptr )   // call strdup
01540 {
01541     return strdup( ptr );
01542 }
01543 
01544 void * real_mmove( void * ptr, size_t size )     // take memory allocated by real_malloc or a C library function and move to managed memory
01545 {
01546     // create new memory, copy, free old memory
01547     void * ret = tNEW(char)[size];
01548     memcpy( ret, ptr, size );
01549     real_free( ptr );
01550 
01551     return ret;
01552 }
01553 
01554 char * real_strmove( char * ptr )                // take C string allocated by real_malloc or a C library function and move to managed memory
01555 {
01556     if ( ptr )
01557         return static_cast< char * >( real_mmove( ptr, strlen( ptr ) + 1 ) );
01558     else
01559         return 0;
01560 }
01561 
01562 #endif // DONTUSEMEMMANAGER
01563 
01564 char * tStrDup( char const * s )
01565 {
01566     return real_strmove( strdup( s ) );
01567 }

Generated on Sat Mar 15 22:56:00 2008 for Armagetron Advanced by  doxygen 1.5.4