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.
16 static char rcsid[] = "$Id: mem.c,v 1.1.1.1 2001-01-19 03:29:58 bradleyb Exp $";
20 // Warning( "MEM: Too many malloc's!" );
21 // Warning( "MEM: Malloc returnd an already alloced block!" );
22 // Warning( "MEM: Malloc Failed!" );
23 // Warning( "MEM: Freeing the NULL pointer!" );
24 // Warning( "MEM: Freeing a non-malloced pointer!" );
25 // Warning( "MEM: %d/%d check bytes were overwritten at the end of %8x", ec, CHECKSIZE, buffer );
26 // Warning( "MEM: %d blocks were left allocated!", numleft );
42 #include <Processes.h>
43 ubyte virtual_memory_on = 0;
45 #if defined(RELEASE) || defined(NDEBUG)
53 static int sMemStatsFileInitialized = false;
54 static FILE* sMemStatsFile = NULL;
55 static char sMemStatsFileName[32] = "memstats.txt";
56 #endif // end of if MEMSTATS
58 #else // no memstats on pc
62 #define FULL_MEM_CHECKING 1
64 #if defined(FULL_MEM_CHECKING) && !defined(NDEBUG)
67 #define CHECKBYTE 0xFC
69 #define MAX_INDEX 10000
71 static unsigned int MallocBase[MAX_INDEX];
72 static unsigned int MallocSize[MAX_INDEX];
73 static unsigned int MallocRealSize[MAX_INDEX];
74 static unsigned char Present[MAX_INDEX];
75 static char * Filename[MAX_INDEX];
76 static char * Varname[MAX_INDEX];
77 static int LineNum[MAX_INDEX];
78 static int BytesMalloced = 0;
80 static unsigned int SmallestAddress = 0xFFFFFFF;
81 static unsigned int LargestAddress = 0x0;
83 int show_mem_info = 1;
85 static int free_list[MAX_INDEX];
87 static int num_blocks = 0;
89 static int Initialized = 0;
91 static int LargestIndex = 0;
93 int out_of_memory = 0;
95 void mem_display_blocks();
103 for (i=0; i<MAX_INDEX; i++ )
108 MallocRealSize[i] = 0;
115 SmallestAddress = 0xFFFFFFF;
116 LargestAddress = 0x0;
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 )
180 // printf("malloc: %d %s %d\n", size, filename, line);
184 unsigned long theFreeMem = 0;
186 if (sMemStatsFileInitialized)
188 theFreeMem = FreeMem();
190 fprintf(sMemStatsFile,
191 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
196 #endif // end of ifdef memstats
198 if ( num_blocks >= MAX_INDEX ) {
199 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
200 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", var, filename, line );
201 Error( "MEM_OUT_OF_SLOTS" );
204 id = free_list[ num_blocks++ ];
206 if (id > LargestIndex ) LargestIndex = id;
210 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
211 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
212 Error( "MEM_OUT_OF_SLOTS" );
216 ptr = malloc( size+CHECKSIZE );
218 ptr = (void *)NewPtrClear( size+CHECKSIZE );
222 for (j=0; j<=LargestIndex; j++ )
224 if (Present[j] && MallocBase[j] == (unsigned int)ptr )
226 fprintf( stderr,"\nMEM_SPACE_USED: Malloc returned a block that is already marked as preset.\n" );
227 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], Line[id] );
228 Warning( "MEM_SPACE_USED" );
237 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
238 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
239 Error( "MEM_OUT_OF_MEMORY" );
242 base = (unsigned int)ptr;
243 if ( base < SmallestAddress ) SmallestAddress = base;
244 if ( (base+size) > LargestAddress ) LargestAddress = base+size;
246 MallocBase[id] = (unsigned int)ptr;
247 data = (ssize_t *)((ssize_t)MallocBase[id]-4);
248 MallocRealSize[id] = *data;
249 MallocSize[id] = size;
251 Filename[id] = filename;
257 BytesMalloced += size;
259 for (i=0; i<CHECKSIZE; i++ )
260 pc[size+i] = CHECKBYTE;
263 memset( ptr, 0, size );
269 int mem_find_id( void * buffer )
273 for (i=0; i<=LargestIndex; i++ )
275 if (MallocBase[i] == (unsigned int)buffer )
282 int mem_check_integrity( int block_number )
284 #ifdef CHECK_DWORD_BELOW
290 CheckData = (char *)(MallocBase[block_number] + MallocSize[block_number]);
292 #ifdef CHECK_DWORD_BELOW
293 data = (int *)((int)MallocBase[block_number]-4);
295 if ( *data != MallocRealSize[block_number] ) {
296 fprintf( stderr, "\nMEM_BAD_LENGTH: The length field of an allocated block was overwritten.\n" );
297 PrintInfo( block_number );
299 *data = MallocRealSize[block_number];
304 for (i=0; i<CHECKSIZE; i++ )
305 if (CheckData[i] != CHECKBYTE ) {
307 fprintf( stderr, "OA: %p ", &CheckData[i] );
310 if (ErrorCount && (!out_of_memory)) {
311 fprintf( stderr, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten.\n" );
312 PrintInfo( block_number );
313 fprintf( stderr, "\t%d/%d check bytes were overwritten.\n", ErrorCount, CHECKSIZE );
321 void mem_free( void * buffer )
330 unsigned long theFreeMem = 0;
332 if (sMemStatsFileInitialized)
334 theFreeMem = FreeMem();
336 fprintf(sMemStatsFile,
337 "\n%9u bytes free before attempting: FREE", theFreeMem);
340 #endif // end of ifdef memstats
342 if (buffer==NULL && (!out_of_memory))
344 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
345 Warning( "MEM: Freeing the NULL pointer!" );
350 id = mem_find_id( buffer );
352 if (id==-1 && (!out_of_memory))
354 fprintf( stderr, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated with mem.h included.\n" );
355 Warning( "MEM: Freeing a non-malloced pointer!" );
360 mem_check_integrity( id );
362 BytesMalloced -= MallocSize[id];
367 DisposePtr( (Ptr)buffer );
375 free_list[ --num_blocks ] = id;
378 void mem_display_blocks()
382 if (Initialized==0) return;
386 if (sMemStatsFileInitialized)
388 unsigned long theFreeMem = 0;
390 theFreeMem = FreeMem();
392 fprintf(sMemStatsFile,
393 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
394 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
395 fclose(sMemStatsFile);
398 #endif // end of ifdef memstats
401 for (i=0; i<=LargestIndex; i++ )
403 if (Present[i]==1 && (!out_of_memory))
407 fprintf( stderr, "\nMEM_LEAKAGE: Memory block has not been freed.\n" );
410 mem_free( (void *)MallocBase[i] );
414 if (numleft && (!out_of_memory))
416 Warning( "MEM: %d blocks were left allocated!", numleft );
420 fprintf( stderr, "\n\nMEMORY USAGE:\n" );
421 fprintf( stderr, " %6u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 );
422 fprintf( stderr, " %6u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 );
423 fprintf( stderr, " ---------------------------\n" );
424 fprintf( stderr, " %6u Kbytes required.\n\n", (LargestAddress-(4*1024*1024)+512)/1024 );
428 void mem_validate_heap()
432 for (i=0; i<LargestIndex; i++ )
434 mem_check_integrity( i );
442 ef = fopen( "DESCENT.MEM", "wt" );
444 for (i=0; i<LargestIndex; i++ )
445 if (Present[i]==1 ) {
446 size += MallocSize[i];
447 //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] );
448 fprintf( ef, "%12d bytes in %s declared in %s, line %d\n", MallocSize[i], Varname[i], Filename[i], LineNum[i] );
450 fprintf( ef, "%d bytes (%d Kbytes) allocated.\n", size, size/1024 );
456 static int Initialized = 0;
457 static unsigned int SmallestAddress = 0xFFFFFFF;
458 static unsigned int LargestAddress = 0x0;
459 static unsigned int BytesMalloced = 0;
461 void mem_display_blocks();
464 #define CHECKBYTE 0xFC
466 int show_mem_info = 0;
472 SmallestAddress = 0xFFFFFFF;
473 LargestAddress = 0x0;
475 atexit(mem_display_blocks);
479 // need to check for virtual memory since we will need to do some
480 // tricks based on whether it is on or not
484 THz theD2PartionPtr = nil;
485 unsigned long thePartitionSize = 0;
488 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
492 virtual_memory_on = 0;
493 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
495 virtual_memory_on = 1;
498 sMemStatsFile = fopen(sMemStatsFileName, "wt");
500 if (sMemStatsFile != NULL)
502 sMemStatsFileInitialized = true;
504 theD2PartionPtr = ApplicationZone();
505 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
506 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
507 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
510 #endif // end of ifdef memstats
513 #endif // end of ifdef macintosh
517 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
528 unsigned long theFreeMem = 0;
530 if (sMemStatsFileInitialized)
532 theFreeMem = FreeMem();
534 fprintf(sMemStatsFile,
535 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
540 #endif // end of ifdef memstats
543 fprintf( stderr, "\nMEM_MALLOC_ZERO: Attempting to malloc 0 bytes.\n" );
544 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
545 Error( "MEM_MALLOC_ZERO" );
550 ptr = malloc( size + CHECKSIZE );
552 ptr = (void *)NewPtrClear( size+CHECKSIZE );
556 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
557 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
558 Error( "MEM_OUT_OF_MEMORY" );
562 base = (unsigned int)ptr;
563 if ( base < SmallestAddress ) SmallestAddress = base;
564 if ( (base+size) > LargestAddress ) LargestAddress = base+size;
569 BytesMalloced += *psize;
572 memset( ptr, 0, size );
577 void mem_free( void * buffer )
579 int * psize = (int *)buffer;
587 unsigned long theFreeMem = 0;
589 if (sMemStatsFileInitialized)
591 theFreeMem = FreeMem();
593 fprintf(sMemStatsFile,
594 "\n%9u bytes free before attempting: FREE", theFreeMem);
597 #endif // end of ifdef memstats
600 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
601 Warning( "MEM: Freeing the NULL pointer!" );
606 BytesMalloced -= *psize;
611 DisposePtr( (Ptr)buffer );
615 void mem_display_blocks()
617 if (Initialized==0) return;
621 if (sMemStatsFileInitialized)
623 unsigned long theFreeMem = 0;
625 theFreeMem = FreeMem();
627 fprintf(sMemStatsFile,
628 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
629 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
630 fclose(sMemStatsFile);
633 #endif // end of ifdef memstats
635 if (BytesMalloced != 0 ) {
636 fprintf( stderr, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.\n", BytesMalloced );
640 fprintf( stderr, "\n\nMEMORY USAGE:\n" );
641 fprintf( stderr, " %u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 );
642 fprintf( stderr, " %u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 );
643 fprintf( stderr, " ---------------------------\n" );
644 fprintf( stderr, " %u Kbytes required.\n", (LargestAddress-(4*1024*1024)+512)/1024 );
648 void mem_validate_heap()
661 // routine to try and compact and purge the process manager zone to squeeze
662 // some temporary memory out of it for QT purposes.
668 THz appZone, processZone;
671 // compact the system zone to try and squeeze some temporary memory out of it
672 MaxMemSys(&heapSize);
674 // compact the Process Manager zone to get more temporary memory
675 appZone = ApplicationZone();
676 tempHandle = TempNewHandle(10, &err); // temporary allocation may fail
677 if (!err && (tempHandle != NULL) ) {
678 processZone = HandleZone(tempHandle);
679 if ( MemError() || (processZone == NULL) ) {
680 DisposeHandle(tempHandle);
683 SetZone(processZone);
684 MaxMem(&heapSize); // purge and compact the Process Manager Zone.
686 DisposeHandle(tempHandle);