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