1 /* $Id: mem.c,v 1.15 2005-03-29 20:45:38 btb Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Files for debugging memory allocator
26 // Warning( "MEM: Too many malloc's!" );
27 // Warning( "MEM: Malloc returnd an already alloced block!" );
28 // Warning( "MEM: Malloc Failed!" );
29 // Warning( "MEM: Freeing the NULL pointer!" );
30 // Warning( "MEM: Freeing a non-malloced pointer!" );
31 // Warning( "MEM: %d/%d check bytes were overwritten at the end of %8x", ec, CHECKSIZE, buffer );
32 // Warning( "MEM: %d blocks were left allocated!", numleft );
49 #include <Processes.h>
50 ubyte virtual_memory_on = 0;
52 #if defined(RELEASE) || defined(NDEBUG)
60 static int sMemStatsFileInitialized = false;
61 static FILE* sMemStatsFile = NULL;
62 static char sMemStatsFileName[32] = "memstats.txt";
63 #endif // end of if MEMSTATS
65 #else // no memstats on pc
69 #define FULL_MEM_CHECKING 1
71 #if defined(FULL_MEM_CHECKING) && !defined(NDEBUG)
74 #define CHECKBYTE 0xFC
76 #define MAX_INDEX 10000
78 static void *MallocBase[MAX_INDEX];
79 static unsigned int MallocSize[MAX_INDEX];
80 static unsigned char Present[MAX_INDEX];
81 static char * Filename[MAX_INDEX];
82 static char * Varname[MAX_INDEX];
83 static int LineNum[MAX_INDEX];
84 static int BytesMalloced = 0;
86 int show_mem_info = 1;
88 static int free_list[MAX_INDEX];
90 static int num_blocks = 0;
92 static int Initialized = 0;
94 static int LargestIndex = 0;
96 int out_of_memory = 0;
98 void mem_display_blocks();
106 for (i=0; i<MAX_INDEX; i++ )
120 atexit(mem_display_blocks);
124 // need to check for virtual memory since we will need to do some
125 // tricks based on whether it is on or not
129 THz theD2PartionPtr = nil;
130 unsigned long thePartitionSize = 0;
133 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
137 virtual_memory_on = 0;
138 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
140 virtual_memory_on = 1;
143 sMemStatsFile = fopen(sMemStatsFileName, "wt");
145 if (sMemStatsFile != NULL)
147 sMemStatsFileInitialized = true;
149 theD2PartionPtr = ApplicationZone();
150 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
151 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
152 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
155 #endif // end of ifdef MEMSTATS
158 #endif // end of ifdef macintosh
162 void PrintInfo( int id )
164 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
168 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
177 // printf("malloc: %d %s %d\n", size, filename, line);
181 unsigned long theFreeMem = 0;
183 if (sMemStatsFileInitialized)
185 theFreeMem = FreeMem();
187 fprintf(sMemStatsFile,
188 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
193 #endif // end of ifdef memstats
195 if ( num_blocks >= MAX_INDEX ) {
196 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
197 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", var, filename, line );
198 Error( "MEM_OUT_OF_SLOTS" );
201 id = free_list[ num_blocks++ ];
203 if (id > LargestIndex ) LargestIndex = id;
207 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
208 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
209 Error( "MEM_OUT_OF_SLOTS" );
213 ptr = malloc( size+CHECKSIZE );
215 ptr = (void *)NewPtrClear( size+CHECKSIZE );
219 for (j=0; j<=LargestIndex; j++ )
221 if (Present[j] && MallocBase[j] == (unsigned int)ptr )
223 fprintf( stderr,"\nMEM_SPACE_USED: Malloc returned a block that is already marked as preset.\n" );
224 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], Line[id] );
225 Warning( "MEM_SPACE_USED" );
234 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
235 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
236 Error( "MEM_OUT_OF_MEMORY" );
239 MallocBase[id] = ptr;
240 MallocSize[id] = size;
242 Filename[id] = filename;
248 BytesMalloced += size;
250 for (i=0; i<CHECKSIZE; i++ )
251 pc[size+i] = CHECKBYTE;
254 memset( ptr, 0, size );
260 int mem_find_id( void * buffer )
264 for (i=0; i<=LargestIndex; i++ )
266 if (MallocBase[i] == buffer )
273 int mem_check_integrity( int block_number )
278 CheckData = (ubyte *)((char *)MallocBase[block_number] + MallocSize[block_number]);
282 for (i=0; i<CHECKSIZE; i++ )
283 if (CheckData[i] != CHECKBYTE ) {
285 fprintf( stderr, "OA: %p ", &CheckData[i] );
288 if (ErrorCount && (!out_of_memory)) {
289 fprintf( stderr, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten.\n" );
290 PrintInfo( block_number );
291 fprintf( stderr, "\t%d/%d check bytes were overwritten.\n", ErrorCount, CHECKSIZE );
299 void mem_free( void * buffer )
308 unsigned long theFreeMem = 0;
310 if (sMemStatsFileInitialized)
312 theFreeMem = FreeMem();
314 fprintf(sMemStatsFile,
315 "\n%9u bytes free before attempting: FREE", theFreeMem);
318 #endif // end of ifdef memstats
320 if (buffer==NULL && (!out_of_memory))
322 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
323 Warning( "MEM: Freeing the NULL pointer!" );
328 id = mem_find_id( buffer );
330 if (id==-1 && (!out_of_memory))
332 fprintf( stderr, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated with mem.h included.\n" );
333 Warning( "MEM: Freeing a non-malloced pointer!" );
338 mem_check_integrity( id );
340 BytesMalloced -= MallocSize[id];
345 DisposePtr( (Ptr)buffer );
353 free_list[ --num_blocks ] = id;
356 void *mem_realloc(void * buffer, unsigned int size, char * var, char * filename, int line)
367 } else if (buffer == NULL) {
368 newbuffer = mem_malloc(size, var, filename, line, 0);
370 newbuffer = mem_malloc(size, var, filename, line, 0);
371 if (newbuffer != NULL) {
372 id = mem_find_id(buffer);
373 if (MallocSize[id] < size)
374 size = MallocSize[id];
375 memcpy(newbuffer, buffer, size);
382 char *mem_strdup(char *str, char *var, char *filename, int line)
386 newstr = mem_malloc(strlen(str) + 1, var, filename, line, 0);
392 void mem_display_blocks()
396 if (Initialized==0) return;
400 if (sMemStatsFileInitialized)
402 unsigned long theFreeMem = 0;
404 theFreeMem = FreeMem();
406 fprintf(sMemStatsFile,
407 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
408 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
409 fclose(sMemStatsFile);
412 #endif // end of ifdef memstats
415 for (i=0; i<=LargestIndex; i++ )
417 if (Present[i]==1 && (!out_of_memory))
421 fprintf( stderr, "\nMEM_LEAKAGE: Memory block has not been freed.\n" );
424 mem_free( (void *)MallocBase[i] );
428 if (numleft && (!out_of_memory))
430 Warning( "MEM: %d blocks were left allocated!\n", numleft );
435 void mem_validate_heap()
439 for (i=0; i<LargestIndex; i++ )
441 mem_check_integrity( i );
449 ef = fopen( "DESCENT.MEM", "wt" );
451 for (i=0; i<LargestIndex; i++ )
452 if (Present[i]==1 ) {
453 size += MallocSize[i];
454 //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] );
455 fprintf( ef, "%12d bytes in %s declared in %s, line %d\n", MallocSize[i], Varname[i], Filename[i], LineNum[i] );
457 fprintf( ef, "%d bytes (%d Kbytes) allocated.\n", size, size/1024 );
463 static int Initialized = 0;
464 static unsigned int SmallestAddress = 0xFFFFFFF;
465 static unsigned int LargestAddress = 0x0;
466 static unsigned int BytesMalloced = 0;
468 void mem_display_blocks();
471 #define CHECKBYTE 0xFC
473 int show_mem_info = 0;
479 SmallestAddress = 0xFFFFFFF;
480 LargestAddress = 0x0;
482 atexit(mem_display_blocks);
486 // need to check for virtual memory since we will need to do some
487 // tricks based on whether it is on or not
491 THz theD2PartionPtr = nil;
492 unsigned long thePartitionSize = 0;
495 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
499 virtual_memory_on = 0;
500 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
502 virtual_memory_on = 1;
505 sMemStatsFile = fopen(sMemStatsFileName, "wt");
507 if (sMemStatsFile != NULL)
509 sMemStatsFileInitialized = true;
511 theD2PartionPtr = ApplicationZone();
512 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
513 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
514 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
517 #endif // end of ifdef memstats
520 #endif // end of ifdef macintosh
524 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
535 unsigned long theFreeMem = 0;
537 if (sMemStatsFileInitialized)
539 theFreeMem = FreeMem();
541 fprintf(sMemStatsFile,
542 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
547 #endif // end of ifdef memstats
550 fprintf( stderr, "\nMEM_MALLOC_ZERO: Attempting to malloc 0 bytes.\n" );
551 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
552 Error( "MEM_MALLOC_ZERO" );
557 ptr = malloc( size + CHECKSIZE );
559 ptr = (void *)NewPtrClear( size+CHECKSIZE );
563 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
564 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
565 Error( "MEM_OUT_OF_MEMORY" );
569 base = (unsigned int)ptr;
570 if ( base < SmallestAddress ) SmallestAddress = base;
571 if ( (base+size) > LargestAddress ) LargestAddress = base+size;
576 BytesMalloced += *psize;
579 memset( ptr, 0, size );
584 void mem_free( void * buffer )
586 int * psize = (int *)buffer;
594 unsigned long theFreeMem = 0;
596 if (sMemStatsFileInitialized)
598 theFreeMem = FreeMem();
600 fprintf(sMemStatsFile,
601 "\n%9u bytes free before attempting: FREE", theFreeMem);
604 #endif // end of ifdef memstats
607 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
608 Warning( "MEM: Freeing the NULL pointer!" );
613 BytesMalloced -= *psize;
618 DisposePtr( (Ptr)buffer );
622 void mem_display_blocks()
624 if (Initialized==0) return;
628 if (sMemStatsFileInitialized)
630 unsigned long theFreeMem = 0;
632 theFreeMem = FreeMem();
634 fprintf(sMemStatsFile,
635 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
636 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
637 fclose(sMemStatsFile);
640 #endif // end of ifdef memstats
642 if (BytesMalloced != 0 ) {
643 fprintf( stderr, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.\n", BytesMalloced );
647 fprintf( stderr, "\n\nMEMORY USAGE:\n" );
648 fprintf( stderr, " %u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 );
649 fprintf( stderr, " %u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 );
650 fprintf( stderr, " ---------------------------\n" );
651 fprintf( stderr, " %u Kbytes required.\n", (LargestAddress-(4*1024*1024)+512)/1024 );
655 void mem_validate_heap()
668 // routine to try and compact and purge the process manager zone to squeeze
669 // some temporary memory out of it for QT purposes.
675 THz appZone, processZone;
678 // compact the system zone to try and squeeze some temporary memory out of it
679 MaxMemSys(&heapSize);
681 // compact the Process Manager zone to get more temporary memory
682 appZone = ApplicationZone();
683 tempHandle = TempNewHandle(10, &err); // temporary allocation may fail
684 if (!err && (tempHandle != NULL) ) {
685 processZone = HandleZone(tempHandle);
686 if ( MemError() || (processZone == NULL) ) {
687 DisposeHandle(tempHandle);
690 SetZone(processZone);
691 MaxMem(&heapSize); // purge and compact the Process Manager Zone.
693 DisposeHandle(tempHandle);