1 /*
2 
3 *************************************************************************
4 
5 ArmageTron -- Just another Tron Lightcycle Game in 3D.
6 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
7 
8 **************************************************************************
9 
10 This program is f.ree software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 ***************************************************************************
25 
26 */ // LoadLibrary
27 
28 // disable malloc replacement
29 #define NO_MALLOC_REPLACEMENT
30 
31 #include "defs.h"
32 
33 #include <iostream>
34 #include <sstream>
35 #include <stdio.h>  // need basic C IO since STL IO does memory management
36 #include "tMemManager.h"
37 #include "tError.h"
38 
39 #ifdef HAVE_STDLIB_H
40 #include <stdlib.h>
41 #endif
42 
43 #ifdef WIN32
44 #ifdef _MSC_VER
45 #include <windows.h>
46 #include <winuser.h>
47 #ifdef _DEBUG
48 #undef _DEBUG
49 #endif
50 #include <CrtDbg.h>
51 #pragma warning (disable : 4073)
52 #pragma init_seg(lib)
53 #endif
54 #ifdef __MINGW32__
55 #include <windows.h>
56 #include <winuser.h>
57 #ifdef _DEBUG
58 #undef _DEBUG
59 #endif
60 #endif
61 static CRITICAL_SECTION  mutex;
62 #endif
63 
64 #ifndef DONTUSEMEMMANAGER
65 #define NEW
66 #endif
67 
68 #ifdef DEBUG
69 #define LEAKFINDER
70 
71 
72 #ifdef LEAKFINDER
73 #define PROFILER
74 #endif
75 
76 #ifdef WIN32
77 //#define MEM_DEB_SMALL
78 //#define MEM_DEB
79 //#define DOUBLEFREEFINDER
80 #endif
81 
82 //#define MEM_DEB_SMALL
83 //#define MEM_DEB
84 //#define DOUBLEFREEFINDER
85 #endif
86 
87 static bool reported=false;
88 
89 #ifdef HAVE_LIBZTHREAD
90 #include <zthread/FastRecursiveMutex.h>
91 
92 static ZThread::FastRecursiveMutex st_mutex;
93 #elif defined(HAVE_PTHREAD)
94 #include "pthread-binding.h"
95 static tPThreadRecursiveMutex st_mutex;
96 #else
97 class tMockMutex
98 {
99 public:
acquire()100     void acquire(){}
release()101     void release(){}
102 };
103 
104 static tMockMutex st_mutex;
105 #endif
106 
107 class tBottleNeck
108 {
109 public:
tBottleNeck()110     tBottleNeck()
111     {
112         st_mutex.acquire();
113     }
114 
~tBottleNeck()115     ~tBottleNeck()
116     {
117         st_mutex.release();
118     }
119 };
120 
121 // replacement for wmemset function
122 #ifndef HAVE_WMEMSET
wmemset(wchar_t * wcs,wchar_t wc,size_t n)123 static inline wchar_t *wmemset(wchar_t *wcs, wchar_t wc, size_t n) throw()
124 {
125     // fill memory
126     for( size_t i = 0; i < n; ++i )
127     {
128         wcs[i] = wc;
129     }
130 
131     return wcs;
132 }
133 #endif
134 
leak()135 void leak(){
136     if (!reported)
137     {
138         reported=true;
139 #ifdef DEBUG
140 #ifdef WIN32
141         MessageBox (NULL, "Memory leak detected!" , "Memory Leak", MB_OK);
142 #else
143         std::cerr << "\n\nMemory leak detected!\n\n";
144 #endif
145 #endif
146         tMemManBase::Profile();
147     }
148 }
149 
150 
151 
152 #include "tList.h"
153 
154 class memblock;
155 
156 #ifdef DEBUG
157 #define SAFETYBYTES 16
158 #else
159 #define SAFETYBYTES 0
160 #endif
161 #define PAD 197
162 
163 // information about allocation in process
164 struct tAllocationInfo
165 {
166 #ifdef LEAKFINDER
167     const char *filename;
168     const char *classname;
169     int checksum;
170     int line;
171     bool array;
172 #endif
173 
tAllocationInfotAllocationInfo174     tAllocationInfo( bool
175 #ifdef LEAKFINDER
176                      array_
177 #endif
178         )
179 #ifdef LEAKFINDER
180     : filename( "XXX" ), classname( "XXX" ), checksum(-1), line(0), array( array_ )
181 #endif
182     {
183     }
184 };
185 
186 class tMemMan: public tMemManBase
187 {
188 public:
189     static void *Alloc(tAllocationInfo const & info, size_t s);
190     static void  Dispose(tAllocationInfo const & info, void *p);
191     static void  DisposeButKeep(tAllocationInfo const & info, void *p);
192 };
193 
194 
195 class tMemManager{
196     friend class memblock;
197 public:
198     tMemManager(int size, int blocksize);
199     tMemManager(int size);
200     ~tMemManager();
201 
202     void *      Alloc( tAllocationInfo const & info );
203     static void * AllocDefault(tAllocationInfo const & info, size_t size);
204     static void Dispose(tAllocationInfo const & info, void *p, bool keep=false);
205     void        complete_Dispose(memblock *m);
206     void        Check(); // check integrity
207 
tMemManager(tMemManager const & other)208     tMemManager( tMemManager const & other )
209     : size( other.size )
210     , blocksize( other.blocksize )
211     , semaphore( 1 )
212     {
213     }
214 private:
215     tMemManager & operator =( tMemManager const & );
216 
Lower(int i)217     int  Lower(int i){ // the element below i in the heap
218         if(i%2==0)  // just to make sure what happens; you never know what 1/2 is..
219             return i/2-1;
220         else
221             return (i-1)/2;
222     }
223 
224     bool SwapIf(int i,int j); // swaps heap elements i and j if they are
225     // in wrong order; only then, TRUE is returned.
226     // i is assumed to lie lower in the heap than j.
227 
228     void SwapDown(int j); // swap element j as far down as it may go.
229     void SwapUp(int i);   // swap element j as far up as it must.
230 
231     //#ifdef MEM_DEB
232     void CheckHeap(); // checks the heap structure
233     //#endif
234 
UpperL(int i)235     static int  UpperL(int i){return 2*i+1;} // the elements left and
UpperR(int i)236     static int  UpperR(int i){return 2*i+2;} // right above i
237 
238     void Insert(memblock *b);  // starts to manage object e
239     void Remove(memblock *b);  // stops (does not delete e)
240     memblock * Remove(int i);     // stops to manage object i, wich is returned.
241     void Replace(int i);  // puts element i to the right place (if the
242     // rest of the heap has correct order)
243     void Replace(memblock *e);
244 
245 
246     int size;
247     int blocksize;
248 
249     tList<memblock, true> blocks;
250     tList<memblock, true> full_blocks;
251 
252     int semaphore;
253 };
254 
255 static bool inited=false;
256 
257 #ifdef LEAKFINDER
258 #include <fstream>
259 #define MAXCHECKSUM 100001
260 static int counter[MAXCHECKSUM];
261 static int leaks[MAXCHECKSUM];
262 #ifdef PROFILER
263 static const char *checksum_filename[MAXCHECKSUM];
264 static const char *checksum_classname[MAXCHECKSUM];
265 static int         checksum_line[MAXCHECKSUM];
266 static int         checksum_blocks[MAXCHECKSUM];
267 static int         checksum_bytes[MAXCHECKSUM];
268 #endif
269 
270 
271 static char const *leakname="leak.log";
272 static bool checkleaks=true;
273 #endif
274 
begin_checkleaks()275 void begin_checkleaks(){
276 #ifdef LEAKFINDER
277     checkleaks=true;
278 #endif
279 }
280 
281 struct chunkinfo{
282 unsigned char pos:8;       // our position in the block
283 unsigned char occupied:1;  // flag
284 unsigned char size_in_dwords:7; // size
285 unsigned char next:8;      // next element of same state
286 unsigned char prev:8;      // ....
287 #ifdef LEAKFINDER
288     int checksum;
289     int counter;
290     bool array;
291 #endif
292 #ifdef PROFILER
293     size_t realSize;
294 #endif
295 };
296 
297 // the heap elements.
298 
299 class memblock{
300 public: // everything is local to this file anyway...
301 
302     int value;         // our value (the number of free slots).
303     // lower values are lower in the heap.
304     int  hID;      // the id in the heap
305 
306     tMemManager *myman;
307 
308     int size;
309     unsigned char first_free;
310 
311 
~memblock()312     ~memblock(){
313         if (myman) myman->blocks.Remove(this,hID);
314         //tASSERT(myman->blocksize == value);
315     }
316 
chunk(int i)317     chunkinfo & chunk(int i){
318         tASSERT(i>=0 && i<myman->blocksize);
319         return *(
320                    (chunkinfo *)(void *)
321                    ( ( (char *)(this+1) )+(sizeof(chunkinfo)+size+SAFETYBYTES)*i)
322                );
323     }
324 
safety(int i)325     char * safety(int i){
326         tASSERT(i>=0 && i<myman->blocksize);
327         return (
328                    ( ( (char *)(this+1) )+(sizeof(chunkinfo)+size+SAFETYBYTES)*i)
329                    +sizeof(chunkinfo)+size );
330     }
331 
data(int i)332     void * data(int i){
333         tASSERT(i>=0 && i<myman->blocksize);
334         return  (void *)
335                 ( ( (char *)(this+1) )+(sizeof(chunkinfo)+size+SAFETYBYTES)*i + sizeof(chunkinfo));
336     }
337 
338 
memblock(tMemManager * man)339     memblock(tMemManager *man):value(man->blocksize),hID(-1),myman(man){
340         //    std::cout << "new memblock..\n";
341         size=man->size;
342         myman->blocks.Add(this,hID);
343 
344         // TODO: init linked list
345 
346         for (int i=man->blocksize-1 ; i>=0 ; i--){
347             if (i<man->blocksize-1)
348                 chunk(i).next=i+2;
349             else
350                 chunk(i).next=0;
351 
352             if (i>0)
353                 chunk(i).prev=i;
354             else
355                 chunk(i).prev=0;
356 
357             chunk(i).pos = i;
358             chunk(i).occupied = false;
359             chunk(i).size_in_dwords = size >> 2;
360 
361             for (int j=SAFETYBYTES-1;j>=0;j--)
362                 safety(i)[j]=(j ^ PAD);
363         }
364 
365 #ifdef MEM_DEB
366         Check();
367 #endif
368 
369         first_free=1;
370     }
371 
372 
Alloc(tAllocationInfo const & info)373     void *Alloc( tAllocationInfo const & info ){
374 #ifdef MEM_DEB_SMALL
375         Check();
376 #endif
377 
378 
379         tASSERT(value>0);
380         value--;
381 
382         // TODO: faster using linked list
383 
384         int ret=-1;
385         /*
386           for (int i=myman->blocksize-1 ; i>=0 ; i--)
387           if (!chunk(i).occupied){
388           //	  chunk(i).occupied=true;
389           ret=i;
390           i=-1;
391           //  return data(i);
392           }*/
393 
394 
395         ret=first_free-1;
396         tASSERT(ret>=0);
397         // tASSERT(_CrtCheckMemory());
398 
399         chunk(ret).occupied=true;
400         first_free=chunk(ret).next;
401         //  tASSERT(_CrtCheckMemory());
402         if (first_free>0) chunk(first_free-1).prev=0;
403 
404         chunk(ret).next=chunk(ret).prev=0;
405         //   tASSERT(_CrtCheckMemory());
406 
407 #ifdef LEAKFINDER
408         if (info.checksum >= 0){
409             tASSERT(info.checksum < MAXCHECKSUM);
410 
411 #ifdef PROFILER
412             if (!counter[info.checksum]){
413                 checksum_filename [info.checksum] = info.filename;
414                 checksum_classname[info.checksum] = info.classname;
415                 checksum_line     [info.checksum] = info.line;
416             }
417             checksum_blocks[info.checksum]++;
418             checksum_bytes[info.checksum]+=size;
419             chunk(ret).realSize = size;
420 #endif
421             chunk(ret).array=info.array;
422             chunk(ret).checksum=info.checksum;
423             chunk(ret).counter =++counter[info.checksum];
424 
425             static int count =0;
426             if (checkleaks && counter[info.checksum] == leaks[info.checksum]){
427                 count ++;
428                 if (count <= 0)
429                 {
430                     std::cerr << "one of the endless ignored objects that were leaky last time created!\n";
431                 }
432                 else if (count <= 1)
433                 {
434                     std::cerr << "Object that was leaky last time created!\n";
435                     st_Breakpoint();
436                 }
437                 else if (count <= 3)
438                 {
439                     std::cerr << "One more object that was leaky last time created!\n";
440                     st_Breakpoint();
441                 }
442                 else
443                 {
444                     std::cerr << "one of the endless objects that were leaky last time created!\n";
445                     //	    st_Breakpoint();
446                 }
447             }
448         }
449 #endif
450 
451 #ifdef LEAKFINDER
452 #ifdef PROFILER
453         chunk(ret).realSize = size;
454 #endif
455         chunk(ret).array=info.array;
456         chunk(ret).checksum=info.checksum;
457 #endif
458 
459 #ifdef DEBUG
460         wmemset(static_cast< wchar_t * >( data(ret) ), wchar_t(0xfedabeef), size / sizeof( wchar_t ));
461 #else
462         wmemset(static_cast< wchar_t * >( data(ret) ), 0, size / sizeof( wchar_t ));
463 #endif
464 
465 #ifdef MEM_DEB_SMALL
466         Check();
467 #endif
468 
469         return data(ret);
470 
471         tASSERT(0); // we should never get here
472         return NULL;
473     }
474 
Dispose(void * p,int & size,tAllocationInfo const & info,bool keep=false)475     static memblock * Dispose(void *p, int &size, tAllocationInfo const & info, bool keep=false){
476         chunkinfo &c=((chunkinfo *)p)[-1];
477         size=c.size_in_dwords*4;
478 
479 #ifdef PROFILER
480         if (c.checksum >=0 && c.checksum < MAXCHECKSUM){
481             checksum_blocks[c.checksum]--;
482             checksum_bytes [c.checksum]-=c.realSize;
483         }
484 #else
485 #ifdef LEAKFINDER
486         tASSERT(c.checksum>=-1 && c.checksum < MAXCHECKSUM);
487 #endif
488 #endif
489 
490 #ifndef WIN32 // grr. on windows, this assertion fails on calls from STL.
491         tASSERT( c.array == info.array );
492 #endif
493 
494         if (size==0){
495             bool o = c.occupied;
496             // tASSERT(c.occupied);
497             c.occupied=false;
498             if (o) free(&c);
499             return NULL;
500         }
501 
502         tASSERT(c.occupied == 1);
503         if (!c.occupied)
504             return NULL;
505 
506 #ifdef DEBUG
507         wmemset(static_cast< wchar_t * >( p ), wchar_t(0xbadf00d), size / sizeof( wchar_t ));
508 #else
509         wmemset(static_cast< wchar_t * >( p ), 0, size / sizeof( wchar_t ) );
510 #endif
511 
512         memblock *myblock=(
513                               (memblock *)(void *)
514                               (
515                                   ( (char *)(void *)p ) -
516                                   ( (sizeof(chunkinfo)+size+SAFETYBYTES)*c.pos
517                                     + sizeof(chunkinfo) )
518                               ) ) - 1;
519 
520         c.occupied=false;
521 
522 
523 
524 #ifndef DOUBLEFREEFINDER
525         if (keep)
526             return NULL;
527 
528 #ifdef WIN32
529         EnterCriticalSection(&mutex);
530 #endif
531 
532         tASSERT(myblock -> value < myblock->myman->blocksize);
533         c.prev=0;
534         c.next=myblock->first_free;
535         myblock->first_free=c.pos+1;
536         if (c.next)   myblock->chunk(c.next-1).prev=c.pos+1;
537 
538         myblock->value++;
539 #endif
540 
541         // TODO:  use linked list
542         return myblock;
543     }
544 
create(tMemManager * man)545     static memblock * create(tMemManager *man){
546         //tASSERT(_CrtCheckMemory());
547         void *mem = malloc(man->blocksize * (SAFETYBYTES + man->size + sizeof(chunkinfo))
548                            + sizeof(memblock));
549         //  tASSERT(_CrtCheckMemory());
550         return new(mem) memblock(man);
551     }
552 
destroy(memblock * b)553     static void destroy(memblock * b){
554         b->~memblock();
555         free((void *)b);
556     }
557 
Check()558     void  Check(){
559 #ifdef DEBUG
560         tASSERT (size == myman->size);
561 
562         tASSERT (value >=0);
563         tASSERT (value <= myman->blocksize);
564 
565         for(int i=myman->blocksize-1;i>=0;i--){
566             tASSERT(chunk(i).pos == i);
567 
568             for (int j=SAFETYBYTES-1;j>=0;j--){
569                 char a=safety(i)[j];
570                 char b=j^PAD;
571                 tASSERT(a==b);
572             }
573         }
574 #endif
575     }
576 
577 #ifdef LEAKFINDER
dumpleaks(std::ostream & s)578     void dumpleaks(std::ostream &s){
579         for (int i=myman->blocksize-1;i>=0;i--)
580             if (chunk(i).occupied && chunk(i).checksum >= 0 ){
581                 s << chunk(i).checksum << " " << chunk(i).counter << '\n';
582                 leak();
583             }
584     }
585 #endif
586 };
587 
588 
589 
590 
591 
592 // ***********************************************
593 
594 
595 
596 
597 
SwapIf(int i,int j)598 bool tMemManager::SwapIf(int i,int j){
599     if (i==j || i<0) return false; // safety
600 
601     memblock *e1=blocks(i),*e2=blocks(j);
602     if (e1->value > e2->value){
603         Swap(blocks(i),blocks(j));
604         e1->hID=j;
605         e2->hID=i;
606         return true;
607     }
608     else
609         return false;
610 
611 }
612 
~tMemManager()613 tMemManager::~tMemManager(){
614 #ifdef LEAKFINDER
615     bool warn = true;
616 #ifdef HAVE_LIBZTHREAD
617     warn = false;
618 #endif
619 
620     if (inited){
621         // l???sche das ding
622         std::ofstream lw(leakname);
623         lw << "\n\n";
624         tMemMan::Profile();
625     }
626 #endif
627 
628 #ifdef WIN32
629     if (inited)
630         DeleteCriticalSection(&mutex);
631 #endif
632 
633     inited = false;
634 
635     //tASSERT (full_blocks.Len() == 0);
636     int i;
637     for (i=blocks.Len()-1;i>=0;i--){
638         if (blocks(i)->value==blocksize)
639             memblock::destroy(blocks(i));
640         else{
641 #ifdef LEAKFINDER
642             if ( warn )
643             {
644                 std::cout << "Memmanager warning: leaving block untouched.\n";
645                 warn = false;
646             }
647             std::ofstream l(leakname,std::ios::app);
648             blocks(i)->dumpleaks(l);
649 #endif
650         }
651     }
652 
653     for (i=full_blocks.Len()-1;i>=0;i--){
654         if (full_blocks(i)->value==blocksize)
655             memblock::destroy(full_blocks(i));
656         else{
657 #ifdef LEAKFINDER
658             if ( warn )
659             {
660                 std::cout << "Memmanager warning: leaving block untouched.\n";
661                 warn = false;
662             }
663             std::ofstream l(leakname,std::ios::app);
664             full_blocks(i)->dumpleaks(l);
665 #endif
666         }
667     }
668 
669 }
670 
tMemManager(int s,int bs)671 tMemManager::tMemManager(int s,int bs):size(s),blocksize(s){
672     // std::cout << sizeof(chunkinfo);
673     if (blocksize>255)
674         blocksize=255;
675     semaphore = 1;
676 
677     tBottleNeck neck;
678 
679 #ifdef WIN32
680     if (!inited)
681         InitializeCriticalSection(&mutex);
682 #endif
683 
684     inited = true;
685 }
686 
tMemManager(int s)687 tMemManager::tMemManager(int s):size(s){//,blocks(1000),full_blocks(1000){
688     tBottleNeck neck;
689 
690     inited = false;
691 
692     blocks.SetLen(0);
693     full_blocks.SetLen(0);
694     blocksize=16000/(s+sizeof(chunkinfo)+SAFETYBYTES);
695     if (blocksize>252)
696         blocksize=252;
697     //  std::cout << sizeof(chunkinfo) << ',' << s << ',' << blocksize << '\n';
698     semaphore = 1;
699 
700 #ifdef LEAKFINDER
701     if (size == 0){
702         for ( int i = MAXCHECKSUM-1; i>=0; --i )
703         {
704             leaks[i] = 0;
705             counter[i] = 0;
706 #ifdef PROFILER
707             checksum_filename[i] = 0;
708             checksum_classname[i] = 0;
709             checksum_line[i] = 0;
710             checksum_blocks[i] = 0;
711             checksum_bytes[i] = 0;
712 #endif
713         }
714 
715         std::ifstream l(leakname);
716         while (l.good() && !l.eof()){
717             int cs,ln;
718             l >> cs >> ln;
719 
720             if (cs>=0 && cs < MAXCHECKSUM && (ln < leaks[cs] || leaks[cs] == 0))
721                 leaks[cs]=ln;
722         }
723     }
724     if (!inited){
725         // delete it
726         std::ofstream lw(leakname);
727         lw << "\n\n";
728     }
729 #endif
730 
731 #ifdef WIN32
732     if (!inited)
733         InitializeCriticalSection(&mutex);
734 #endif
735 
736     inited = true;
737 }
738 
739 //#ifdef MEM_DEB
CheckHeap()740 void tMemManager::CheckHeap(){
741     for(int i=blocks.Len()-1;i>0;i--){
742         memblock *current=blocks(i);
743         memblock *low=blocks(Lower(i));
744         if (Lower(UpperL(i))!=i || Lower(UpperR(i))!=i)
745             tERR_ERROR_INT("Error in lower/upper " << i << "!");
746 
747         if (low->value>current->value)
748             tERR_ERROR_INT("Heap structure corrupt!");
749     }
750 }
751 //#endif
752 
SwapDown(int j)753 void tMemManager::SwapDown(int j){
754     int i=j;
755     // e is now at position i. swap it down
756     // as far as it goes:
757     do{
758         j=i;
759         i=Lower(j);
760     }
761     while(SwapIf(i,j)); // mean: relies on the fact that SwapIf returns -1
762     // if i<0.
763 
764 #ifdef MEM_DEB
765     CheckHeap();
766 #endif
767 }
768 
SwapUp(int i)769 void tMemManager::SwapUp(int i){
770 #ifdef MEM_DEB
771     //  static int su=0;
772     //if (su%100 ==0 )
773     // std::cout << "su=" << su << '\n';
774     //  if (su > 11594 )
775     // con << "su=" << su << '\n';
776     // su ++;
777 #endif
778 
779     int ul,ur;
780     bool goon=1;
781     while(goon && UpperL(i)<blocks.Len()){
782         ul=UpperL(i);
783         ur=UpperR(i);
784         if(ur>=blocks.Len() ||
785                 blocks(ul)->value < blocks(ur)->value){
786             goon=SwapIf(i,ul);
787             i=ul;
788         }
789         else{
790             goon=SwapIf(i,ur);
791             i=ur;
792         }
793     }
794 
795 #ifdef MEM_DEB
796     CheckHeap();
797 #endif
798 
799 }
800 
Insert(memblock * e)801 void tMemManager::Insert(memblock *e){
802     blocks.Add(e,e->hID); // relies on the implementation of List: e is
803     // put to the back of the heap.
804     SwapDown(blocks.Len()-1); // bring it to the right place
805 
806 #ifdef MEM_DEB
807     CheckHeap();
808 #endif
809 }
810 
Remove(memblock * e)811 void tMemManager::Remove(memblock *e){
812     int i=e->hID;
813 
814     if(i<0 || this != e->myman)
815         tERR_ERROR_INT("Element is not in this heap!");
816 
817     Remove(i);
818 
819 #ifdef MEM_DEB
820     CheckHeap();
821 #endif
822 }
823 
Replace(int i)824 void tMemManager::Replace(int i){
825     if (i>=0 && i < blocks.Len()){
826         if (i==0 || blocks(i)->value > blocks(Lower(i))->value)
827             SwapUp(i);          // put it up where it belongs
828         else
829             SwapDown(i);
830 
831 #ifdef MEM_DEB
832         CheckHeap();
833 #endif
834     }
835 }
836 
Replace(memblock * e)837 void tMemManager::Replace(memblock *e){
838     int i=e->hID;
839 
840     if(i<0 || this != e->myman)
841         tERR_ERROR_INT("Element is not in this heap!");
842 
843     Replace(i);
844 
845 #ifdef MEM_DEB
846     CheckHeap();
847 #endif
848 }
849 
Remove(int i)850 memblock * tMemManager::Remove(int i){
851     if (i>=0 && i<blocks.Len()){
852         memblock *ret=blocks(i);
853 
854         blocks.Remove(ret,ret->hID);
855 
856         // now we have an misplaced element at pos i. (if i was not at the end..)
857         if (i<blocks.Len())
858             Replace(i);
859 
860 #ifdef MEM_DEB
861         CheckHeap();
862 #endif
863 
864         return ret;
865     }
866     return NULL;
867 }
868 
Alloc(tAllocationInfo const & info)869 void * tMemManager::Alloc( tAllocationInfo const & info ){
870     semaphore--;
871     if (semaphore<0 || size == 0){
872         semaphore++;
873         return AllocDefault(info, size);
874     }
875 
876 #ifdef WIN32
877     EnterCriticalSection(&mutex);
878 #endif
879 
880     if (blocks.Len()==0) // no free space available. create new block...
881         Insert(memblock::create(this));
882     //tASSERT(_CrtCheckMemory());
883 
884     memblock *block=blocks(0);
885     tASSERT (block->size == size);
886     void *mem = block->Alloc( info );
887     //tASSERT(_CrtCheckMemory());
888     if (block->value == 0){
889         Remove(block);
890         full_blocks.Add(block,block->hID);
891     }
892 
893 #ifdef WIN32
894     LeaveCriticalSection(&mutex);
895 #endif
896 
897     semaphore++;
898     return mem;
899 }
900 
complete_Dispose(memblock * block)901 void tMemManager::complete_Dispose(memblock *block){
902 #ifdef MEM_DEB_SMALL
903     block->Check();
904 #endif
905 
906     semaphore--;
907     if (semaphore>=0){
908         if (block->value == 1){
909             full_blocks.Remove(block,block->hID);
910             Insert(block);
911         }
912         else{
913             Replace(block);
914         }
915     }
916     //else
917     // tASSERT(0);
918     semaphore++;
919 
920 #ifdef MEM_DEB_SMALL
921     block->Check();
922 #endif
923 }
924 
Check()925 void tMemManager::Check(){
926 #ifdef DEBUG_EXPENSIVE
927     if ( !inited )
928         return;
929 
930     CheckHeap();
931     int i;
932     for (i=blocks.Len()-1;i>=0;i--)
933     {
934         blocks(i)->Check();
935         tASSERT (blocks(i)->myman == this);
936         tASSERT (blocks(i)->size == size);
937     }
938     for (i=full_blocks.Len()-1;i>=0;i--)
939     {
940         if ( full_blocks(i) )
941         {
942             full_blocks(i)->Check();
943             tASSERT (full_blocks(i)->myman == this);
944             tASSERT (full_blocks(i)->size == size);
945         }
946     }
947 #endif
948 }
949 
950 
951 #define MAX_SIZE 109
952 
953 
954 static tMemManager memman[MAX_SIZE+1]={
955                                           tMemManager(0),
956                                           tMemManager(4),
957                                           tMemManager(8),
958                                           tMemManager(12),
959                                           tMemManager(16),
960                                           tMemManager(20),
961                                           tMemManager(24),
962                                           tMemManager(28),
963                                           tMemManager(32),
964                                           tMemManager(36),
965                                           tMemManager(40),
966                                           tMemManager(44),
967                                           tMemManager(48),
968                                           tMemManager(52),
969                                           tMemManager(56),
970                                           tMemManager(60),
971                                           tMemManager(64),
972                                           tMemManager(68),
973                                           tMemManager(72),
974                                           tMemManager(76),
975                                           tMemManager(80),
976                                           tMemManager(84),
977                                           tMemManager(88),
978                                           tMemManager(92),
979                                           tMemManager(96),
980                                           tMemManager(100),
981                                           tMemManager(104),
982                                           tMemManager(108),
983                                           tMemManager(112),
984                                           tMemManager(116),
985                                           tMemManager(120),
986                                           tMemManager(124),
987                                           tMemManager(128),
988                                           tMemManager(132),
989                                           tMemManager(136),
990                                           tMemManager(140),
991                                           tMemManager(144),
992                                           tMemManager(148),
993                                           tMemManager(152),
994                                           tMemManager(156),
995                                           tMemManager(160),
996                                           tMemManager(164),
997                                           tMemManager(168),
998                                           tMemManager(172),
999                                           tMemManager(176),
1000                                           tMemManager(180),
1001                                           tMemManager(184),
1002                                           tMemManager(188),
1003                                           tMemManager(192),
1004                                           tMemManager(196),
1005                                           tMemManager(200),
1006                                           tMemManager(204),
1007                                           tMemManager(208),
1008                                           tMemManager(212),
1009                                           tMemManager(216),
1010                                           tMemManager(220),
1011                                           tMemManager(224),
1012                                           tMemManager(228),
1013                                           tMemManager(232),
1014                                           tMemManager(236),
1015                                           tMemManager(240),
1016                                           tMemManager(244),
1017                                           tMemManager(248),
1018                                           tMemManager(252),
1019                                           tMemManager(256),
1020                                           tMemManager(260),
1021                                           tMemManager(264),
1022                                           tMemManager(268),
1023                                           tMemManager(272),
1024                                           tMemManager(276),
1025                                           tMemManager(280),
1026                                           tMemManager(284),
1027                                           tMemManager(288),
1028                                           tMemManager(292),
1029                                           tMemManager(296),
1030                                           tMemManager(300),
1031                                           tMemManager(304),
1032                                           tMemManager(308),
1033                                           tMemManager(312),
1034                                           tMemManager(316),
1035                                           tMemManager(320),
1036                                           tMemManager(324),
1037                                           tMemManager(328),
1038                                           tMemManager(332),
1039                                           tMemManager(336),
1040                                           tMemManager(340),
1041                                           tMemManager(344),
1042                                           tMemManager(348),
1043                                           tMemManager(352),
1044                                           tMemManager(356),
1045                                           tMemManager(360),
1046                                           tMemManager(364),
1047                                           tMemManager(368),
1048                                           tMemManager(372),
1049                                           tMemManager(376),
1050                                           tMemManager(380),
1051                                           tMemManager(384),
1052                                           tMemManager(388),
1053                                           tMemManager(392),
1054                                           tMemManager(396),
1055                                           tMemManager(400),
1056                                           tMemManager(404),
1057                                           tMemManager(408),
1058                                           tMemManager(412),
1059                                           tMemManager(416),
1060                                           tMemManager(420),
1061                                           tMemManager(424),
1062                                           tMemManager(428),
1063                                           tMemManager(432),
1064                                           tMemManager(436)
1065                                       };
1066 
1067 
Dispose(tAllocationInfo const & info,void * p,bool keep)1068 void tMemManager::Dispose(tAllocationInfo const & info, void *p, bool keep){
1069     int size;
1070 
1071     if (!p)
1072         return;
1073 
1074     memblock *block = memblock::Dispose(p,size,info, keep);
1075 #ifndef DOUBLEFREEFINDER
1076     if (inited && block){
1077         tBottleNeck neck;
1078         memman[size >> 2].complete_Dispose(block);
1079 #ifdef WIN32
1080         LeaveCriticalSection(&mutex);
1081 #endif
1082     }
1083 #else
1084     block = 0;
1085 #endif
1086 }
1087 
AllocDefault(tAllocationInfo const & info,size_t s)1088 void *tMemManager::AllocDefault(tAllocationInfo const & info, size_t s){
1089 #ifdef LEAKFINDER
1090     void *ret=malloc(s+sizeof(chunkinfo));//,classname,fileName,line);
1091     ((chunkinfo *)ret)->checksum=info.checksum;
1092     ((chunkinfo *)ret)->array=info.array;
1093 #ifdef PROFILER
1094     ((chunkinfo *)ret)->realSize=s;
1095     if ( info.checksum >= 0 )
1096     {
1097         if (!counter[info.checksum]){
1098             checksum_filename [info.checksum] = info.filename;
1099             checksum_classname[info.checksum] = info.classname;
1100             checksum_line     [info.checksum] = info.line;
1101         }
1102         checksum_blocks[info.checksum]++;
1103         checksum_bytes[info.checksum]+=s;
1104     }
1105 #endif
1106 #else
1107     void *ret=malloc(s+sizeof(chunkinfo));
1108 #endif
1109     ((chunkinfo *)ret)->size_in_dwords=0;
1110     ((chunkinfo *)ret)->occupied=true;
1111     ret = ((chunkinfo *)ret)+1;
1112     return ret;
1113 }
1114 
Alloc(tAllocationInfo const & info,size_t s)1115 void *tMemMan::Alloc(tAllocationInfo const & info, size_t s){
1116 #ifndef DONTUSEMEMMANAGER
1117 #ifdef MEM_DEB
1118 #ifdef WIN32
1119     tASSERT(_CrtCheckMemory());
1120 #endif
1121     Check();
1122 #endif
1123     void *ret;
1124     if (inited && s < (MAX_SIZE << 2))
1125     {
1126         tBottleNeck neck;
1127         ret=memman[((s+3)>>2)].Alloc( info );
1128     }
1129     else
1130     {
1131         ret=tMemManager::AllocDefault(info, s);
1132     }
1133 #ifdef MEM_DEB
1134     Check();
1135 #ifdef WIN32
1136     tASSERT(_CrtCheckMemory());
1137 #endif
1138 #endif
1139     return ret;
1140 
1141 #else
1142     return malloc(s);
1143 #endif
1144 
1145 }
1146 
DisposeButKeep(tAllocationInfo const & info,void * p)1147 void tMemMan::DisposeButKeep( tAllocationInfo const & info, void *p){
1148 #ifndef DONTUSEMEMMANAGER
1149 #ifdef MEM_DEB
1150 #ifdef WIN32
1151     tASSERT(_CrtCheckMemory());
1152 #endif
1153     Check();
1154 #endif
1155     tMemManager::Dispose(info, p, true);
1156 #ifdef MEM_DEB
1157     Check();
1158 #ifdef WIN32
1159     tASSERT(_CrtCheckMemory());
1160 #endif
1161 #endif
1162 #endif
1163 }
1164 
Dispose(tAllocationInfo const & info,void * p)1165 void tMemMan::Dispose(tAllocationInfo const & info, void *p){
1166 #ifndef DONTUSEMEMMANAGER
1167 #ifdef MEM_DEB
1168 #ifdef WIN32
1169     tASSERT(_CrtCheckMemory());
1170 #endif
1171     Check();
1172 #endif
1173     tMemManager::Dispose(info, p );
1174 #ifdef MEM_DEB
1175     Check();
1176 #ifdef WIN32
1177     tASSERT(_CrtCheckMemory());
1178 #endif
1179 #endif
1180 #else
1181     free(p);
1182 #endif
1183 }
1184 
1185 
Check()1186 void tMemManBase::Check(){
1187     if (!inited)
1188         return;
1189 
1190 #ifdef WIN32
1191     EnterCriticalSection(&mutex);
1192 #endif
1193 
1194     for (int i=MAX_SIZE;i>=0;i--)
1195         memman[i].Check();
1196 
1197 #ifdef WIN32
1198     LeaveCriticalSection(&mutex);
1199 #endif
1200 }
1201 
1202 /*
1203 	void* operator new	(unsigned int size) {
1204 		//return zmalloc.Malloc (size, "UNKNOWN", "zMemory.cpp", 49);
1205         // return malloc(size);
1206         return tMemManager::AllocDefault(size);
1207 	};
1208 	void  operator delete(void *ptr) {
1209 		if (ptr) tMemManager::Dispose(ptr);
1210         // zmalloc.Free(ptr);
1211 	};
1212 */
1213 
1214 #ifdef NEW
1215 /*
1216 void * operator new(
1217         unsigned int cb,
1218         int nBlockUse,
1219         const char * szFileName,
1220         int nLine
1221         )
1222 {
1223     return operator new(cb, "xxx", szFileName, nLine);
1224 }
1225 */
1226 
1227 #ifdef WIN32
1228 #ifdef DEDICATED
1229 #ifdef DEBUG
1230 #if 0
1231 void * operator new(
1232     size_t size,
1233     int nBlockUse,
1234     const char * file,
1235     int l
1236 )
1237 {
1238 #ifdef LEAKFINDER
1239     fileName=file;
1240     classname="XXX";
1241     line=l;
1242 
1243     checksum =
1244 #ifndef PROFILER
1245         size +
1246 #endif
1247         line * 19671;
1248 
1249     int c=1379;
1250     while (*file){
1251         checksum = (checksum + (*file)*c) % MAXCHECKSUM;
1252         c        = (c * 79              ) % MAXCHECKSUM;
1253         file++;
1254     }
1255 
1256 #ifdef PROFILER
1257     while (checksum_fileName[checksum] && (checksum_fileName[checksum] != fileName || checksum_line[checksum] != line))
1258         checksum = (checksum+1) % MAXCHECKSUM;
1259 #endif
1260 
1261 #endif
1262     return tMemMan::Alloc(size);
1263 
1264     //      return _nh_malloc_dbg( cb, 1, nBlockUse, szFileName, nLine );
1265 }
1266 #endif
1267 #endif
1268 #endif
1269 #endif
1270 
1271 
operator new(size_t size)1272 void* _cdecl operator new	(size_t size) THROW_BADALLOC{
1273     tAllocationInfo info( false );
1274 
1275 #ifdef LEAKFINDER
1276 #ifndef HAVE_LIBZTHREAD
1277     info.checksum = size;
1278 #endif
1279 #endif
1280     return tMemMan::Alloc(info, size);
1281 }
1282 
operator delete(void * ptr)1283 void  _cdecl operator delete(void *ptr) THROW_NOTHING{
1284     tAllocationInfo info( false );
1285 
1286     if (ptr)
1287         tMemMan::Dispose(info, ptr);
1288 }
1289 
operator delete(void * ptr,bool keep)1290 void  operator delete(void *ptr,bool keep) THROW_NOTHING{
1291     tAllocationInfo info( false );
1292 
1293     if (ptr){
1294         if (keep)
1295             tMemMan::DisposeButKeep(info, ptr);
1296         else
1297             tMemMan::Dispose(info, ptr);
1298 
1299     }
1300 }
1301 
1302 
1303 
operator new(size_t size,const char * classn,const char * file,int l)1304 void* operator new	(size_t size,const char *classn,const char *file,int l) THROW_BADALLOC{
1305     tAllocationInfo info( false );
1306 #ifdef LEAKFINDER
1307     info.filename=file;
1308     info.classname=classn;
1309     info.line=l;
1310 
1311     info.checksum =
1312 #ifndef PROFILER
1313         size +
1314 #endif
1315         info.line * 19671;
1316 
1317     int c=1379;
1318     while (*file){
1319         info.checksum = (info.checksum + (*file)*c) % MAXCHECKSUM;
1320         c             = (c * 79              ) % MAXCHECKSUM;
1321         file++;
1322     }
1323     while (*classn){
1324         info.checksum = (info.checksum + (*classn)*c) % MAXCHECKSUM;
1325         c             = (c * 79                ) % MAXCHECKSUM;
1326         classn++;
1327     }
1328 
1329 #ifdef PROFILER
1330     while (checksum_filename[info.checksum] && (checksum_filename[info.checksum] != info.filename || checksum_line[info.checksum] != info.line))
1331     info.checksum = (info.checksum+1) % MAXCHECKSUM;
1332 #endif
1333 
1334 #endif
1335     return tMemMan::Alloc(info, size);
1336 }
1337 
operator delete(void * ptr,const char * classname,const char * file,int line)1338 void  operator delete   (void *ptr,const char *classname,const char *file,int line)  THROW_NOTHING{
1339     tAllocationInfo info( false );
1340 
1341     if (ptr) tMemMan::Dispose(info, ptr);
1342 }
1343 
operator new[](size_t size)1344 void* operator new[]	(size_t size) THROW_BADALLOC{
1345     tAllocationInfo info( true );
1346 #ifdef LEAKFINDER
1347 #ifndef HAVE_LIBZTHREAD
1348     info.checksum = size % MAXCHECKSUM;
1349 #endif
1350 #endif
1351     return tMemMan::Alloc(info, size);
1352 }
1353 
operator delete[](void * ptr)1354 void  operator delete[](void *ptr) THROW_NOTHING {
1355     tAllocationInfo info( true );
1356 
1357     if (ptr)
1358         tMemMan::Dispose(info, ptr);
1359 }
1360 
1361 
1362 
operator new[](size_t size,const char * classn,const char * file,int l)1363 void* operator new[]	(size_t size,const char *classn,const char *file,int l)  THROW_BADALLOC{
1364     tAllocationInfo info( true );
1365 #ifdef LEAKFINDER
1366     info.filename=file;
1367     info.classname=classn;
1368     info.line=l;
1369 
1370     info.checksum =
1371 #ifndef PROFILER
1372     size +
1373 #endif
1374     info.line * 19671;
1375 
1376     int c=1379;
1377     while (*file){
1378         info.checksum = (info.checksum + (*file)*c) % MAXCHECKSUM;
1379         c             = (c * 79              ) % MAXCHECKSUM;
1380         file++;
1381     }
1382     while (*classn){
1383         info.checksum = (info.checksum + (*classn)*c) % MAXCHECKSUM;
1384         c             = (c * 79                ) % MAXCHECKSUM;
1385         classn++;
1386     }
1387 
1388 #ifdef PROFILER
1389     while (checksum_filename[info.checksum] && (checksum_filename[info.checksum] != info.filename || checksum_line[info.checksum] != info.line))
1390     info.checksum = (info.checksum+1) % MAXCHECKSUM;
1391 #endif
1392 
1393 #endif
1394     return tMemMan::Alloc(info, size);
1395 }
1396 
operator delete[](void * ptr,const char * classname,const char * file,int line)1397 void  operator delete[]   (void *ptr,const char *classname,const char *file,int line)   THROW_NOTHING{
1398     tAllocationInfo info( true );
1399 
1400     if (ptr) tMemMan::Dispose(info, ptr);
1401 }
1402 
1403 #endif
1404 
1405 
1406 
1407 
1408 #ifdef PROFILER
compare(const void * a,const void * b)1409     static int compare(const void *a, const void *b){
1410         int A = checksum_bytes[*((const int *)a)];
1411         int B = checksum_bytes[*((const int *)b)];
1412 
1413         if (A<B)
1414             return -1;
1415         if (A>B)
1416             return 1;
1417 
1418         return 0;
1419     }
1420 
1421 //#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"
1422 
1423 //#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"
1424 
1425 #endif
1426 
1427 
1428 #ifdef WIN32
1429 #define snprintf _snprintf
1430 #endif
1431 
Profile()1432 void  tMemManBase::Profile(){
1433     tBottleNeck neck;
1434 #ifdef PROFILER
1435 
1436     int sort_checksum[MAXCHECKSUM];
1437     int size=0,i;
1438 
1439     for (i=MAXCHECKSUM-1;i>=0;i--)
1440         if (checksum_blocks[i])
1441             sort_checksum[size++] = i;
1442 
1443     qsort(sort_checksum, size, sizeof(int), &compare);
1444 
1445     static int num=1;
1446 
1447     char name[100];
1448     snprintf( name, 99, "memprofile%d.txt", num++ );
1449     //    std::ostringstream fn;
1450 
1451     //    fn << "memprofile" << num++ << ".txt" << '\0';
1452 
1453 
1454     FILE *f = fopen( name, "w" );
1455     //	fprintf( f, "%d\t%d\t%d\t%s\t%s\t%d\t%d\t\n", )
1456 
1457     int total_blocks=0,total_bytes =0;
1458 
1459     for (i=size-1; i>=0; i--)
1460     {
1461         int cs = sort_checksum[i];
1462         const char *fn = checksum_filename[cs];
1463         const char *cn = checksum_classname[cs];
1464 
1465         if (!fn)
1466             fn = "XXX";
1467         if (!cn)
1468             cn = "XXX";
1469 
1470         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 );
1471         //        PRINT(checksum_blocks[cs], checksum_bytes[cs],cn, fn , checksum_line[cs], cs);
1472         total_blocks += checksum_blocks[cs];
1473         total_bytes += checksum_bytes[cs];
1474     }
1475 
1476     fclose( f );
1477 
1478 
1479     /*
1480         std::ofstream s( name );
1481         s.setf(std::ios::left);
1482 
1483         PRINT("Blocks", "Bytes", "Class", "File", "Line", "Checksum");
1484 
1485         int total_blocks=0,total_bytes =0;
1486 
1487         for (i=size-1; i>=0; i--)
1488     	{
1489             int cs = sort_checksum[i];
1490             const char *fn = checksum_fileName[cs];
1491             const char *cn = checksum_classname[cs];
1492 
1493             if (!fn)
1494                 fn = "XXX";
1495             if (!cn)
1496                 cn = "XXX";
1497 
1498             PRINT(checksum_blocks[cs], checksum_bytes[cs],cn, fn , checksum_line[cs], cs);
1499             total_blocks += checksum_blocks[cs];
1500             total_bytes += checksum_bytes[cs];
1501         }
1502 
1503         s << "\n\n";
1504         PRINT (total_blocks, total_bytes, "Total" , "", "", "");
1505     */
1506 #endif
1507 }
1508 
1509 #ifdef HAVE_LIBEFENCE
1510 class eFence
1511 {
1512 public:
eFence()1513     eFence()
1514     {
1515         EF_newFrame();
1516     }
~eFence()1517     ~eFence()
1518     {
1519         EF_delFrame();
1520     }
1521 };
1522 
1523 static eFence fence;
1524 #endif
1525 
1526 #ifndef DONTUSEMEMMANAGER
real_calloc(size_t nmemb,size_t size)1527 void * real_calloc( size_t nmemb, size_t size ) // call calloc
1528 {
1529     return calloc( nmemb, size );
1530 }
1531 
real_malloc(size_t size)1532 void * real_malloc( size_t size )                // call malloc
1533 {
1534     return malloc( size );
1535 }
1536 
real_free(void * ptr)1537 void   real_free( void * ptr )                   // call free
1538 {
1539     free( ptr );
1540 }
1541 
real_realloc(void * ptr,size_t size)1542 void * real_realloc( void * ptr, size_t size )   // call realloc
1543 {
1544     return realloc( ptr, size );
1545 }
1546 
real_strdup(char const * ptr)1547 char * real_strdup( char const * ptr )   // call strdup
1548 {
1549     return strdup( ptr );
1550 }
1551 
real_mmove(void * ptr,size_t size)1552 void * real_mmove( void * ptr, size_t size )     // take memory allocated by real_malloc or a C library function and move to managed memory
1553 {
1554     // create new memory, copy, free old memory
1555     void * ret = tNEW(char)[size];
1556     memcpy( ret, ptr, size );
1557     real_free( ptr );
1558 
1559     return ret;
1560 }
1561 
real_strmove(char * ptr)1562 char * real_strmove( char * ptr )                // take C string allocated by real_malloc or a C library function and move to managed memory
1563 {
1564     if ( ptr )
1565         return static_cast< char * >( real_mmove( ptr, strlen( ptr ) + 1 ) );
1566     else
1567         return 0;
1568 }
1569 
1570 #endif // DONTUSEMEMMANAGER
1571 
tStrDup(char const * s)1572 char * tStrDup( char const * s )
1573 {
1574     return real_strmove( strdup( s ) );
1575 }
1576