2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
15 * $Source: /cvs/cvsroot/d2x/mem/mem.c,v $
18 * $Date: 2001-10-19 08:06:20 $
20 * Files for debugging memory allocator
22 * $Log: not supported by cvs2svn $
29 // Warning( "MEM: Too many malloc's!" );
30 // Warning( "MEM: Malloc returnd an already alloced block!" );
31 // Warning( "MEM: Malloc Failed!" );
32 // Warning( "MEM: Freeing the NULL pointer!" );
33 // Warning( "MEM: Freeing a non-malloced pointer!" );
34 // Warning( "MEM: %d/%d check bytes were overwritten at the end of %8x", ec, CHECKSIZE, buffer );
35 // Warning( "MEM: %d blocks were left allocated!", numleft );
50 #include <Processes.h>
51 ubyte virtual_memory_on = 0;
53 #if defined(RELEASE) || defined(NDEBUG)
61 static int sMemStatsFileInitialized = false;
62 static FILE* sMemStatsFile = NULL;
63 static char sMemStatsFileName[32] = "memstats.txt";
64 #endif // end of if MEMSTATS
66 #else // no memstats on pc
70 #define FULL_MEM_CHECKING 1
72 #if defined(FULL_MEM_CHECKING) && !defined(NDEBUG)
75 #define CHECKBYTE 0xFC
77 #define MAX_INDEX 10000
79 static void *MallocBase[MAX_INDEX];
80 static unsigned int MallocSize[MAX_INDEX];
81 static unsigned char Present[MAX_INDEX];
82 static char * Filename[MAX_INDEX];
83 static char * Varname[MAX_INDEX];
84 static int LineNum[MAX_INDEX];
85 static int BytesMalloced = 0;
87 int show_mem_info = 1;
89 static int free_list[MAX_INDEX];
91 static int num_blocks = 0;
93 static int Initialized = 0;
95 static int LargestIndex = 0;
97 int out_of_memory = 0;
99 void mem_display_blocks();
107 for (i=0; i<MAX_INDEX; i++ )
121 atexit(mem_display_blocks);
125 // need to check for virtual memory since we will need to do some
126 // tricks based on whether it is on or not
130 THz theD2PartionPtr = nil;
131 unsigned long thePartitionSize = 0;
134 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
138 virtual_memory_on = 0;
139 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
141 virtual_memory_on = 1;
144 sMemStatsFile = fopen(sMemStatsFileName, "wt");
146 if (sMemStatsFile != NULL)
148 sMemStatsFileInitialized = true;
150 theD2PartionPtr = ApplicationZone();
151 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
152 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
153 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
156 #endif // end of ifdef MEMSTATS
159 #endif // end of ifdef macintosh
163 void PrintInfo( int id )
165 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
169 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
178 // printf("malloc: %d %s %d\n", size, filename, line);
182 unsigned long theFreeMem = 0;
184 if (sMemStatsFileInitialized)
186 theFreeMem = FreeMem();
188 fprintf(sMemStatsFile,
189 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
194 #endif // end of ifdef memstats
196 if ( num_blocks >= MAX_INDEX ) {
197 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
198 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", var, filename, line );
199 Error( "MEM_OUT_OF_SLOTS" );
202 id = free_list[ num_blocks++ ];
204 if (id > LargestIndex ) LargestIndex = id;
208 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
209 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
210 Error( "MEM_OUT_OF_SLOTS" );
214 ptr = malloc( size+CHECKSIZE );
216 ptr = (void *)NewPtrClear( size+CHECKSIZE );
220 for (j=0; j<=LargestIndex; j++ )
222 if (Present[j] && MallocBase[j] == (unsigned int)ptr )
224 fprintf( stderr,"\nMEM_SPACE_USED: Malloc returned a block that is already marked as preset.\n" );
225 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], Line[id] );
226 Warning( "MEM_SPACE_USED" );
235 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
236 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
237 Error( "MEM_OUT_OF_MEMORY" );
240 MallocBase[id] = ptr;
241 MallocSize[id] = size;
243 Filename[id] = filename;
249 BytesMalloced += size;
251 for (i=0; i<CHECKSIZE; i++ )
252 pc[size+i] = CHECKBYTE;
255 memset( ptr, 0, size );
261 int mem_find_id( void * buffer )
265 for (i=0; i<=LargestIndex; i++ )
267 if (MallocBase[i] == buffer )
274 int mem_check_integrity( int block_number )
279 CheckData = (char *)(MallocBase[block_number] + MallocSize[block_number]);
283 for (i=0; i<CHECKSIZE; i++ )
284 if (CheckData[i] != CHECKBYTE ) {
286 fprintf( stderr, "OA: %p ", &CheckData[i] );
289 if (ErrorCount && (!out_of_memory)) {
290 fprintf( stderr, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten.\n" );
291 PrintInfo( block_number );
292 fprintf( stderr, "\t%d/%d check bytes were overwritten.\n", ErrorCount, CHECKSIZE );
300 void mem_free( void * buffer )
309 unsigned long theFreeMem = 0;
311 if (sMemStatsFileInitialized)
313 theFreeMem = FreeMem();
315 fprintf(sMemStatsFile,
316 "\n%9u bytes free before attempting: FREE", theFreeMem);
319 #endif // end of ifdef memstats
321 if (buffer==NULL && (!out_of_memory))
323 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
324 Warning( "MEM: Freeing the NULL pointer!" );
329 id = mem_find_id( buffer );
331 if (id==-1 && (!out_of_memory))
333 fprintf( stderr, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated with mem.h included.\n" );
334 Warning( "MEM: Freeing a non-malloced pointer!" );
339 mem_check_integrity( id );
341 BytesMalloced -= MallocSize[id];
346 DisposePtr( (Ptr)buffer );
354 free_list[ --num_blocks ] = id;
357 void mem_display_blocks()
361 if (Initialized==0) return;
365 if (sMemStatsFileInitialized)
367 unsigned long theFreeMem = 0;
369 theFreeMem = FreeMem();
371 fprintf(sMemStatsFile,
372 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
373 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
374 fclose(sMemStatsFile);
377 #endif // end of ifdef memstats
380 for (i=0; i<=LargestIndex; i++ )
382 if (Present[i]==1 && (!out_of_memory))
386 fprintf( stderr, "\nMEM_LEAKAGE: Memory block has not been freed.\n" );
389 mem_free( (void *)MallocBase[i] );
393 if (numleft && (!out_of_memory))
395 Warning( "MEM: %d blocks were left allocated!", numleft );
400 void mem_validate_heap()
404 for (i=0; i<LargestIndex; i++ )
406 mem_check_integrity( i );
414 ef = fopen( "DESCENT.MEM", "wt" );
416 for (i=0; i<LargestIndex; i++ )
417 if (Present[i]==1 ) {
418 size += MallocSize[i];
419 //fprintf( ef, "Var:%s\t File:%s\t Line:%d\t Size:%d Base:%x\n", Varname[i], Filename[i], Line[i], MallocSize[i], MallocBase[i] );
420 fprintf( ef, "%12d bytes in %s declared in %s, line %d\n", MallocSize[i], Varname[i], Filename[i], LineNum[i] );
422 fprintf( ef, "%d bytes (%d Kbytes) allocated.\n", size, size/1024 );
428 static int Initialized = 0;
429 static unsigned int SmallestAddress = 0xFFFFFFF;
430 static unsigned int LargestAddress = 0x0;
431 static unsigned int BytesMalloced = 0;
433 void mem_display_blocks();
436 #define CHECKBYTE 0xFC
438 int show_mem_info = 0;
444 SmallestAddress = 0xFFFFFFF;
445 LargestAddress = 0x0;
447 atexit(mem_display_blocks);
451 // need to check for virtual memory since we will need to do some
452 // tricks based on whether it is on or not
456 THz theD2PartionPtr = nil;
457 unsigned long thePartitionSize = 0;
460 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
464 virtual_memory_on = 0;
465 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
467 virtual_memory_on = 1;
470 sMemStatsFile = fopen(sMemStatsFileName, "wt");
472 if (sMemStatsFile != NULL)
474 sMemStatsFileInitialized = true;
476 theD2PartionPtr = ApplicationZone();
477 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
478 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
479 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
482 #endif // end of ifdef memstats
485 #endif // end of ifdef macintosh
489 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
500 unsigned long theFreeMem = 0;
502 if (sMemStatsFileInitialized)
504 theFreeMem = FreeMem();
506 fprintf(sMemStatsFile,
507 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
512 #endif // end of ifdef memstats
515 fprintf( stderr, "\nMEM_MALLOC_ZERO: Attempting to malloc 0 bytes.\n" );
516 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
517 Error( "MEM_MALLOC_ZERO" );
522 ptr = malloc( size + CHECKSIZE );
524 ptr = (void *)NewPtrClear( size+CHECKSIZE );
528 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
529 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
530 Error( "MEM_OUT_OF_MEMORY" );
534 base = (unsigned int)ptr;
535 if ( base < SmallestAddress ) SmallestAddress = base;
536 if ( (base+size) > LargestAddress ) LargestAddress = base+size;
541 BytesMalloced += *psize;
544 memset( ptr, 0, size );
549 void mem_free( void * buffer )
551 int * psize = (int *)buffer;
559 unsigned long theFreeMem = 0;
561 if (sMemStatsFileInitialized)
563 theFreeMem = FreeMem();
565 fprintf(sMemStatsFile,
566 "\n%9u bytes free before attempting: FREE", theFreeMem);
569 #endif // end of ifdef memstats
572 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
573 Warning( "MEM: Freeing the NULL pointer!" );
578 BytesMalloced -= *psize;
583 DisposePtr( (Ptr)buffer );
587 void mem_display_blocks()
589 if (Initialized==0) return;
593 if (sMemStatsFileInitialized)
595 unsigned long theFreeMem = 0;
597 theFreeMem = FreeMem();
599 fprintf(sMemStatsFile,
600 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
601 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
602 fclose(sMemStatsFile);
605 #endif // end of ifdef memstats
607 if (BytesMalloced != 0 ) {
608 fprintf( stderr, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.\n", BytesMalloced );
612 fprintf( stderr, "\n\nMEMORY USAGE:\n" );
613 fprintf( stderr, " %u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 );
614 fprintf( stderr, " %u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 );
615 fprintf( stderr, " ---------------------------\n" );
616 fprintf( stderr, " %u Kbytes required.\n", (LargestAddress-(4*1024*1024)+512)/1024 );
620 void mem_validate_heap()
633 // routine to try and compact and purge the process manager zone to squeeze
634 // some temporary memory out of it for QT purposes.
640 THz appZone, processZone;
643 // compact the system zone to try and squeeze some temporary memory out of it
644 MaxMemSys(&heapSize);
646 // compact the Process Manager zone to get more temporary memory
647 appZone = ApplicationZone();
648 tempHandle = TempNewHandle(10, &err); // temporary allocation may fail
649 if (!err && (tempHandle != NULL) ) {
650 processZone = HandleZone(tempHandle);
651 if ( MemError() || (processZone == NULL) ) {
652 DisposeHandle(tempHandle);
655 SetZone(processZone);
656 MaxMem(&heapSize); // purge and compact the Process Manager Zone.
658 DisposeHandle(tempHandle);