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.
19 static char rcsid[] = "$Id: mem.c,v 1.3 2001-01-31 15:18:04 bradleyb Exp $";
22 // Warning( "MEM: Too many malloc's!" );
23 // Warning( "MEM: Malloc returnd an already alloced block!" );
24 // Warning( "MEM: Malloc Failed!" );
25 // Warning( "MEM: Freeing the NULL pointer!" );
26 // Warning( "MEM: Freeing a non-malloced pointer!" );
27 // Warning( "MEM: %d/%d check bytes were overwritten at the end of %8x", ec, CHECKSIZE, buffer );
28 // Warning( "MEM: %d blocks were left allocated!", numleft );
44 #include <Processes.h>
45 ubyte virtual_memory_on = 0;
47 #if defined(RELEASE) || defined(NDEBUG)
55 static int sMemStatsFileInitialized = false;
56 static FILE* sMemStatsFile = NULL;
57 static char sMemStatsFileName[32] = "memstats.txt";
58 #endif // end of if MEMSTATS
60 #else // no memstats on pc
64 #define FULL_MEM_CHECKING 1
66 #if defined(FULL_MEM_CHECKING) && !defined(NDEBUG)
69 #define CHECKBYTE 0xFC
71 #define MAX_INDEX 10000
73 static unsigned int MallocBase[MAX_INDEX];
74 static unsigned int MallocSize[MAX_INDEX];
75 static unsigned int MallocRealSize[MAX_INDEX];
76 static unsigned char Present[MAX_INDEX];
77 static char * Filename[MAX_INDEX];
78 static char * Varname[MAX_INDEX];
79 static int LineNum[MAX_INDEX];
80 static int BytesMalloced = 0;
82 static unsigned int SmallestAddress = 0xFFFFFFF;
83 static unsigned int LargestAddress = 0x0;
85 int show_mem_info = 1;
87 static int free_list[MAX_INDEX];
89 static int num_blocks = 0;
91 static int Initialized = 0;
93 static int LargestIndex = 0;
95 int out_of_memory = 0;
97 void mem_display_blocks();
105 for (i=0; i<MAX_INDEX; i++ )
110 MallocRealSize[i] = 0;
117 SmallestAddress = 0xFFFFFFF;
118 LargestAddress = 0x0;
123 atexit(mem_display_blocks);
127 // need to check for virtual memory since we will need to do some
128 // tricks based on whether it is on or not
132 THz theD2PartionPtr = nil;
133 unsigned long thePartitionSize = 0;
136 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
140 virtual_memory_on = 0;
141 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
143 virtual_memory_on = 1;
146 sMemStatsFile = fopen(sMemStatsFileName, "wt");
148 if (sMemStatsFile != NULL)
150 sMemStatsFileInitialized = true;
152 theD2PartionPtr = ApplicationZone();
153 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
154 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
155 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
158 #endif // end of ifdef MEMSTATS
161 #endif // end of ifdef macintosh
165 void PrintInfo( int id )
167 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
171 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
182 // printf("malloc: %d %s %d\n", size, filename, line);
186 unsigned long theFreeMem = 0;
188 if (sMemStatsFileInitialized)
190 theFreeMem = FreeMem();
192 fprintf(sMemStatsFile,
193 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
198 #endif // end of ifdef memstats
200 if ( num_blocks >= MAX_INDEX ) {
201 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
202 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", var, filename, line );
203 Error( "MEM_OUT_OF_SLOTS" );
206 id = free_list[ num_blocks++ ];
208 if (id > LargestIndex ) LargestIndex = id;
212 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
213 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
214 Error( "MEM_OUT_OF_SLOTS" );
218 ptr = malloc( size+CHECKSIZE );
220 ptr = (void *)NewPtrClear( size+CHECKSIZE );
224 for (j=0; j<=LargestIndex; j++ )
226 if (Present[j] && MallocBase[j] == (unsigned int)ptr )
228 fprintf( stderr,"\nMEM_SPACE_USED: Malloc returned a block that is already marked as preset.\n" );
229 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], Line[id] );
230 Warning( "MEM_SPACE_USED" );
239 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
240 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
241 Error( "MEM_OUT_OF_MEMORY" );
244 base = (unsigned int)ptr;
245 if ( base < SmallestAddress ) SmallestAddress = base;
246 if ( (base+size) > LargestAddress ) LargestAddress = base+size;
248 MallocBase[id] = (unsigned int)ptr;
249 data = (int *)((ssize_t)MallocBase[id]-4);
250 MallocRealSize[id] = *data;
251 MallocSize[id] = size;
253 Filename[id] = filename;
259 BytesMalloced += size;
261 for (i=0; i<CHECKSIZE; i++ )
262 pc[size+i] = CHECKBYTE;
265 memset( ptr, 0, size );
271 int mem_find_id( void * buffer )
275 for (i=0; i<=LargestIndex; i++ )
277 if (MallocBase[i] == (unsigned int)buffer )
284 int mem_check_integrity( int block_number )
286 #ifdef CHECK_DWORD_BELOW
292 CheckData = (char *)(MallocBase[block_number] + MallocSize[block_number]);
294 #ifdef CHECK_DWORD_BELOW
295 data = (int *)((int)MallocBase[block_number]-4);
297 if ( *data != MallocRealSize[block_number] ) {
298 fprintf( stderr, "\nMEM_BAD_LENGTH: The length field of an allocated block was overwritten.\n" );
299 PrintInfo( block_number );
301 *data = MallocRealSize[block_number];
306 for (i=0; i<CHECKSIZE; i++ )
307 if (CheckData[i] != CHECKBYTE ) {
309 fprintf( stderr, "OA: %p ", &CheckData[i] );
312 if (ErrorCount && (!out_of_memory)) {
313 fprintf( stderr, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten.\n" );
314 PrintInfo( block_number );
315 fprintf( stderr, "\t%d/%d check bytes were overwritten.\n", ErrorCount, CHECKSIZE );
323 void mem_free( void * buffer )
332 unsigned long theFreeMem = 0;
334 if (sMemStatsFileInitialized)
336 theFreeMem = FreeMem();
338 fprintf(sMemStatsFile,
339 "\n%9u bytes free before attempting: FREE", theFreeMem);
342 #endif // end of ifdef memstats
344 if (buffer==NULL && (!out_of_memory))
346 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
347 Warning( "MEM: Freeing the NULL pointer!" );
352 id = mem_find_id( buffer );
354 if (id==-1 && (!out_of_memory))
356 fprintf( stderr, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated with mem.h included.\n" );
357 Warning( "MEM: Freeing a non-malloced pointer!" );
362 mem_check_integrity( id );
364 BytesMalloced -= MallocSize[id];
369 DisposePtr( (Ptr)buffer );
377 free_list[ --num_blocks ] = id;
380 void mem_display_blocks()
384 if (Initialized==0) return;
388 if (sMemStatsFileInitialized)
390 unsigned long theFreeMem = 0;
392 theFreeMem = FreeMem();
394 fprintf(sMemStatsFile,
395 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
396 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
397 fclose(sMemStatsFile);
400 #endif // end of ifdef memstats
403 for (i=0; i<=LargestIndex; i++ )
405 if (Present[i]==1 && (!out_of_memory))
409 fprintf( stderr, "\nMEM_LEAKAGE: Memory block has not been freed.\n" );
412 mem_free( (void *)MallocBase[i] );
416 if (numleft && (!out_of_memory))
418 Warning( "MEM: %d blocks were left allocated!", numleft );
422 fprintf( stderr, "\n\nMEMORY USAGE:\n" );
423 fprintf( stderr, " %6u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 );
424 fprintf( stderr, " %6u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 );
425 fprintf( stderr, " ---------------------------\n" );
426 fprintf( stderr, " %6u Kbytes required.\n\n", (LargestAddress-(4*1024*1024)+512)/1024 );
430 void mem_validate_heap()
434 for (i=0; i<LargestIndex; i++ )
436 mem_check_integrity( i );
444 ef = fopen( "DESCENT.MEM", "wt" );
446 for (i=0; i<LargestIndex; i++ )
447 if (Present[i]==1 ) {
448 size += MallocSize[i];
449 //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] );
450 fprintf( ef, "%12d bytes in %s declared in %s, line %d\n", MallocSize[i], Varname[i], Filename[i], LineNum[i] );
452 fprintf( ef, "%d bytes (%d Kbytes) allocated.\n", size, size/1024 );
458 static int Initialized = 0;
459 static unsigned int SmallestAddress = 0xFFFFFFF;
460 static unsigned int LargestAddress = 0x0;
461 static unsigned int BytesMalloced = 0;
463 void mem_display_blocks();
466 #define CHECKBYTE 0xFC
468 int show_mem_info = 0;
474 SmallestAddress = 0xFFFFFFF;
475 LargestAddress = 0x0;
477 atexit(mem_display_blocks);
481 // need to check for virtual memory since we will need to do some
482 // tricks based on whether it is on or not
486 THz theD2PartionPtr = nil;
487 unsigned long thePartitionSize = 0;
490 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
494 virtual_memory_on = 0;
495 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
497 virtual_memory_on = 1;
500 sMemStatsFile = fopen(sMemStatsFileName, "wt");
502 if (sMemStatsFile != NULL)
504 sMemStatsFileInitialized = true;
506 theD2PartionPtr = ApplicationZone();
507 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
508 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
509 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
512 #endif // end of ifdef memstats
515 #endif // end of ifdef macintosh
519 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
530 unsigned long theFreeMem = 0;
532 if (sMemStatsFileInitialized)
534 theFreeMem = FreeMem();
536 fprintf(sMemStatsFile,
537 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
542 #endif // end of ifdef memstats
545 fprintf( stderr, "\nMEM_MALLOC_ZERO: Attempting to malloc 0 bytes.\n" );
546 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
547 Error( "MEM_MALLOC_ZERO" );
552 ptr = malloc( size + CHECKSIZE );
554 ptr = (void *)NewPtrClear( size+CHECKSIZE );
558 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
559 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
560 Error( "MEM_OUT_OF_MEMORY" );
564 base = (unsigned int)ptr;
565 if ( base < SmallestAddress ) SmallestAddress = base;
566 if ( (base+size) > LargestAddress ) LargestAddress = base+size;
571 BytesMalloced += *psize;
574 memset( ptr, 0, size );
579 void mem_free( void * buffer )
581 int * psize = (int *)buffer;
589 unsigned long theFreeMem = 0;
591 if (sMemStatsFileInitialized)
593 theFreeMem = FreeMem();
595 fprintf(sMemStatsFile,
596 "\n%9u bytes free before attempting: FREE", theFreeMem);
599 #endif // end of ifdef memstats
602 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
603 Warning( "MEM: Freeing the NULL pointer!" );
608 BytesMalloced -= *psize;
613 DisposePtr( (Ptr)buffer );
617 void mem_display_blocks()
619 if (Initialized==0) return;
623 if (sMemStatsFileInitialized)
625 unsigned long theFreeMem = 0;
627 theFreeMem = FreeMem();
629 fprintf(sMemStatsFile,
630 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
631 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
632 fclose(sMemStatsFile);
635 #endif // end of ifdef memstats
637 if (BytesMalloced != 0 ) {
638 fprintf( stderr, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.\n", BytesMalloced );
642 fprintf( stderr, "\n\nMEMORY USAGE:\n" );
643 fprintf( stderr, " %u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 );
644 fprintf( stderr, " %u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 );
645 fprintf( stderr, " ---------------------------\n" );
646 fprintf( stderr, " %u Kbytes required.\n", (LargestAddress-(4*1024*1024)+512)/1024 );
650 void mem_validate_heap()
663 // routine to try and compact and purge the process manager zone to squeeze
664 // some temporary memory out of it for QT purposes.
670 THz appZone, processZone;
673 // compact the system zone to try and squeeze some temporary memory out of it
674 MaxMemSys(&heapSize);
676 // compact the Process Manager zone to get more temporary memory
677 appZone = ApplicationZone();
678 tempHandle = TempNewHandle(10, &err); // temporary allocation may fail
679 if (!err && (tempHandle != NULL) ) {
680 processZone = HandleZone(tempHandle);
681 if ( MemError() || (processZone == NULL) ) {
682 DisposeHandle(tempHandle);
685 SetZone(processZone);
686 MaxMem(&heapSize); // purge and compact the Process Manager Zone.
688 DisposeHandle(tempHandle);