00001
00020 #include "mfcpch.h"
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include "stderr.h"
00024 #include "memryerr.h"
00025 #include "hashfn.h"
00026 #include "tprintf.h"
00027 #include "memry.h"
00028 #include "memblk.h"
00029 #ifdef __UNIX__
00030 #include <signal.h>
00031 #endif
00032
00033
00038 class UWREC
00039 {
00040 public:
00041 unsigned cur_frsize;
00042 unsigned cursp;
00043 unsigned currls;
00044 unsigned currlo;
00045 unsigned curdp;
00046 unsigned toprp;
00047 unsigned topmrp;
00048 unsigned topsr0;
00049 unsigned topsr4;
00050 unsigned r3;
00051 unsigned cur_r19;
00052 };
00053
00054 MEMUNION *free_block = NULL;
00055
00056 #define EXTERN
00057
00058 EXTERN MEM_ALLOCATOR big_mem;
00059 EXTERN MEM_ALLOCATOR main_mem;
00060
00061 EXTERN MEMUNION *free_structs[MAX_STRUCTS];
00062
00063 EXTERN INT32 structs_in_use[MAX_STRUCTS];
00064
00065 EXTERN INT32 blocks_in_use[MAX_STRUCTS];
00066
00067 EXTERN MEMUNION *struct_blocks[MAX_STRUCTS];
00068 EXTERN const char *owner_names[MAX_STRUCTS][MAX_CLASSES];
00069 EXTERN INT32 owner_counts[MAX_STRUCTS][MAX_CLASSES];
00070
00071 EXTERN INT16 name_counts[MAX_STRUCTS];
00072 EXTERN INT32 free_struct_blocks;
00073
00076 EXTERN INT_VAR (mem_mallocdepth, 0, "Malloc stack depth to trace");
00077 EXTERN INT_VAR (mem_mallocbits, 8, "Log 2 of hash table size");
00078 EXTERN INT_VAR (mem_freedepth, 0, "Free stack dpeth to trace");
00079 EXTERN INT_VAR (mem_freebits, 8, "Log 2 of hash table size");
00080 EXTERN INT_VAR (mem_countbuckets, 16, "No of buckets for histogram");
00081 EXTERN INT_VAR (mem_checkfreq, 0, "Calls to alloc_mem between owner counts");
00087 void
00088 MEM_ALLOCATOR::init (
00089 void *(*ext_malloc) (INT32),
00090 void (*ext_free) (void *),
00091 INT32 firstsize,
00092 INT32 lastsize,
00093 INT32 maxchunk
00094 ) {
00095 blockcount = 0;
00096 malloc_serial = 0;
00097 topblock = NULL;
00098 currblock = NULL;
00099 callers = NULL;
00100 malloc = ext_malloc;
00101 free = ext_free;
00102 maxsize = lastsize;
00103 biggestblock = maxchunk;
00104 totalmem = 0;
00105 memsize = firstsize;
00106 malloc_div_ratio = 1;
00107 malloc_minor_serial = 0;
00108 malloc_auto_count = 0;
00109 call_bits = 0;
00110 entries = 0;
00111 }
00112
00113
00117 UINT16 MEM_ALLOCATOR::hash_caller(
00118 void *addr
00119 ) {
00120 INT32 index;
00121 INT32 initial_hash;
00122
00123 if (callers == NULL)
00124 init_callers();
00125
00126 initial_hash = hash (call_bits, &addr, sizeof (addr));
00127 if (initial_hash == 0)
00128 initial_hash = 1;
00129 index = initial_hash;
00130 if (callers[index].caller != NULL && callers[index].caller != addr) {
00131 do {
00132 index++;
00133 if (index >= entries)
00134 index = 1;
00135 }
00136 while (callers[index].caller != NULL
00137 && callers[index].caller != addr && index != initial_hash);
00138 if (index == initial_hash)
00139 index = 0;
00140 }
00141 if (callers[index].caller == NULL) {
00142 if (index != 0)
00143 callers[index].caller = addr;
00144 if (callers[index].free_list == NULL)
00145
00146 callers[index].init_freeers ();
00147 }
00148 return (UINT16) index;
00149 }
00150
00151
00157 void MALLOC_CALL::count_freeer(
00158 void *addr
00159 ) {
00160 INT32 entries;
00161 INT32 index;
00162 INT32 initial_hash;
00163
00164 if (free_list == NULL)
00165 init_freeers();
00166 entries = 1 << free_bits;
00167
00168 initial_hash = hash (free_bits, &addr, sizeof (addr));
00169 if (initial_hash == 0)
00170 initial_hash = 1;
00171 index = initial_hash;
00172 if (free_list[index].freeer != NULL && free_list[index].freeer != addr) {
00173 do {
00174 index++;
00175 if (index >= entries)
00176 index = 1;
00177 }
00178 while (free_list[index].freeer != NULL
00179 && free_list[index].freeer != addr && index != initial_hash);
00180 if (index == initial_hash)
00181 index = 0;
00182 }
00183 if (free_list[index].freeer == NULL && index != 0) {
00184 free_list[index].freeer = addr;
00185 }
00186 free_list[index].count++;
00187 }
00188
00189
00193 void MEM_ALLOCATOR::init_callers() {
00194 INT32 depth = mem_mallocdepth;
00195
00196 mem_mallocdepth.set_value (0);
00197 call_bits = mem_mallocbits;
00198 entries = 1 << call_bits;
00199
00200 callers = new MALLOC_CALL[entries];
00201 mem_mallocdepth.set_value (depth);
00202 }
00203
00204
00208 void MALLOC_CALL::init_freeers() {
00209 INT32 entries;
00210 INT32 depth = mem_mallocdepth;
00211
00212 mem_mallocdepth.set_value (0);
00213 free_bits = mem_freebits;
00214 entries = 1 << free_bits;
00215
00216 free_list = new FREE_CALL[entries];
00217 mem_mallocdepth.set_value (depth);
00218 }
00219
00220
00224 void MEM_ALLOCATOR::reduce_counts() {
00225 MEMBLOCK *block;
00226 MEMUNION *chunk;
00227 INT32 chunksize;
00228 INT32 blockindex;
00229
00230 check_mem ("Reducing counts", JUSTCHECKS);
00231 for (blockindex = 0; blockindex < blockcount; blockindex++) {
00232
00233 block = &memblocks[blockindex];
00234
00235 for (chunk = block->blockstart; chunk != block->blockend; chunk += chunksize) {
00236 chunksize = chunk->size;
00237 if (chunksize < 0)
00238 chunksize = -chunksize;
00239 chunk->age /= 2;
00240 }
00241 }
00242 }
00243
00244
00248 void MEM_ALLOCATOR::display_counts() {
00249 MEMBLOCK *block;
00250 MEMUNION *chunk;
00251 INT32 chunksize;
00252 INT32 blockindex;
00253 INT32 buckets;
00254 INT32 bucketsize;
00255 INT32 callindex;
00256 INT32 freeindex;
00257 INT32 freeentries;
00258 INT32 totalchunks;
00259 INT32 totalspace;
00260 INT32 totalpchunks;
00261 INT32 totalpspace;
00262 INT32 totalfrees;
00263
00264 if (callers == NULL)
00265 return;
00266 check_mem ("Displaying counts", JUSTCHECKS);
00267 buckets = mem_countbuckets;
00268 bucketsize = (malloc_serial - 1) / buckets + 1;
00269 tprintf ("\nEach bucket covers %g counts.\n",
00270 (double) bucketsize * malloc_div_ratio);
00271 for (callindex = 0; callindex < entries; callindex++) {
00272 if (callers[callindex].free_list != NULL) {
00273 callers[callindex].counts =
00274 (INT32 *) malloc (buckets * 4 * sizeof (INT32));
00275 memset (callers[callindex].counts, 0,
00276 (size_t) (buckets * 4 * sizeof (INT32)));
00277 }
00278 }
00279 for (blockindex = 0; blockindex < blockcount; blockindex++) {
00280
00281 block = &memblocks[blockindex];
00282
00283 for (chunk = block->blockstart; chunk != block->topchunk; chunk += chunksize) {
00284 chunksize = chunk->size;
00285 if (chunksize < 0) {
00286 chunksize = -chunksize;
00287 callindex = chunk->owner;
00288 if (callers[callindex].counts != NULL) {
00289 callers[callindex].counts[chunk->age / bucketsize * 4]++;
00290 callers[callindex].counts[chunk->age / bucketsize * 4 +
00291 1] += chunksize;
00292 }
00293 }
00294 }
00295
00296 for (; chunk != block->blockend; chunk += chunksize) {
00297 chunksize = chunk->size;
00298 if (chunksize < 0) {
00299 chunksize = -chunksize;
00300 callindex = chunk->owner;
00301 if (callers[callindex].counts != NULL) {
00302 callers[callindex].counts[chunk->age / bucketsize * 4 +
00303 2]++;
00304 callers[callindex].counts[chunk->age / bucketsize * 4 +
00305 3] += chunksize;
00306 }
00307 }
00308 }
00309 }
00310 for (callindex = 0; callindex < entries; callindex++) {
00311 if (callers[callindex].counts != NULL) {
00312 for (totalspace = 0, totalchunks = 0, totalpspace =
00313 0, totalpchunks = 0, freeindex = 0; freeindex < buckets;
00314 freeindex++) {
00315 totalchunks += callers[callindex].counts[freeindex * 4];
00316 totalspace += callers[callindex].counts[freeindex * 4 + 1];
00317 totalpchunks += callers[callindex].counts[freeindex * 4 + 2];
00318 totalpspace += callers[callindex].counts[freeindex * 4 + 3];
00319 }
00320 freeentries = 1 << callers[callindex].free_bits;
00321 for (totalfrees = 0, freeindex = 0; freeindex < freeentries;
00322 freeindex++)
00323 totalfrees += callers[callindex].free_list[freeindex].count;
00324 if (totalspace != 0 || totalfrees != 0) {
00325 tprintf ("alloc_mem at %d : total held=%d(%d), frees=%d.\n",
00326 callers[callindex].caller,
00327 totalchunks, totalspace * sizeof (MEMUNION),
00328 totalfrees);
00329 }
00330 if (totalspace > 0) {
00331 for (freeindex = 0; freeindex < buckets; freeindex++) {
00332 tprintf ("%d(%d) ",
00333 callers[callindex].counts[freeindex * 4],
00334 callers[callindex].counts[freeindex * 4 +
00335 1] * sizeof (MEMUNION));
00336 }
00337 tprintf ("\n");
00338 }
00339 if (totalfrees != 0) {
00340 tprintf ("Calls to free : ");
00341 for (freeindex = 0; freeindex < freeentries; freeindex++) {
00342 if (callers[callindex].free_list[freeindex].count != 0)
00343 tprintf ("%d : %d ",
00344 callers[callindex].free_list[freeindex].freeer,
00345 callers[callindex].free_list[freeindex].count);
00346 }
00347 tprintf ("\n");
00348 }
00349 if (totalpspace != 0) {
00350 tprintf ("alloc_mem_p at %d : total held=%d(%d).\n",
00351 callers[callindex].caller,
00352 totalpchunks, totalpspace * sizeof (MEMUNION));
00353 for (freeindex = 0; freeindex < buckets; freeindex++) {
00354 tprintf ("%d(%d) ",
00355 callers[callindex].counts[freeindex * 4 + 2],
00356 callers[callindex].counts[freeindex * 4 +
00357 3] * sizeof (MEMUNION));
00358 }
00359 tprintf ("\n");
00360 }
00361 free (callers[callindex].counts);
00362 callers[callindex].counts = NULL;
00363 }
00364 }
00365 }
00366
00367
00371 void MEM_ALLOCATOR::check(
00372 const char *string,
00373 INT8 level
00374 ) {
00375 MEMBLOCK *block;
00376 MEMUNION *chunk;
00377 MEMUNION *prevchunk;
00378 INT32 chunksize;
00379 INT32 usedcount;
00380 INT32 usedsize;
00381 INT32 freecount;
00382 INT32 freesize;
00383 INT32 biggest;
00384 INT32 totusedcount;
00385 INT32 totusedsize;
00386 INT32 totfreecount;
00387 INT32 totfreesize;
00388 INT32 totbiggest;
00389 INT32 totblocksize;
00390 INT32 chunkindex;
00391 INT32 blockindex;
00392
00393 if (level >= MEMCHECKS)
00394 tprintf ("\nMEM_ALLOCATOR::check:at '%s'\n", string);
00395 totusedcount = 0;
00396 totusedsize = 0;
00397 totfreecount = 0;
00398 totfreesize = 0;
00399 totbiggest = 0;
00400 totblocksize = 0;
00401 for (blockindex = 0; blockindex < blockcount; blockindex++) {
00402
00403 block = &memblocks[blockindex];
00404 if (level >= MEMCHECKS)
00405 tprintf ("Block %d:0x%x-0x%x, size=%d, top=0x%x, l=%d, u=%d\n",
00406 blockindex, block->blockstart, block->blockend,
00407 (block->blockend - block->blockstart) * sizeof (MEMUNION),
00408 block->topchunk, block->lowerspace, block->upperspace);
00409 usedcount = usedsize = 0;
00410 freecount = freesize = 0;
00411 biggest = 0;
00412
00413 for (chunkindex = 0, prevchunk = NULL, chunk = block->blockstart; chunk != block->blockend; chunkindex++, chunk += chunksize) {
00414 chunksize = chunk->size;
00415 if (chunksize < 0)
00416 chunksize = -chunksize;
00417 if (level >= FULLMEMCHECKS) {
00418 tprintf ("%5d=%8d%c caller=%d, age=%d ", (int) chunkindex,
00419 chunksize * sizeof (MEMUNION),
00420 chunk->size < 0 ? 'U' : 'F', chunk->owner, chunk->age);
00421 if (chunkindex % 5 == 4)
00422 tprintf ("\n");
00423 }
00424
00425 if (chunksize == 0 || chunk->size == -1
00426
00427 || chunk + chunksize - block->blockstart <= 0 || block->blockend - (chunk + chunksize) < 0)
00428 BADMEMCHUNKS.error ("check_mem", ABORT,
00429 "Block=%p, Prev chunk=%p, Chunk=%p, Size=%x",
00430 block, prevchunk, chunk,
00431 (int) chunk->size);
00432
00433 else if (chunk->size < 0) {
00434 usedcount++;
00435 usedsize += chunksize;
00436 }
00437 else {
00438 freecount++;
00439 freesize += chunksize;
00440 if (chunksize > biggest)
00441 biggest = chunksize;
00442 }
00443 prevchunk = chunk;
00444 }
00445 if (level >= MEMCHECKS) {
00446 if (level >= FULLMEMCHECKS)
00447 tprintf ("\n");
00448 tprintf ("%d chunks in use, total size=%d bytes\n",
00449 (int) usedcount, usedsize * sizeof (MEMUNION));
00450 tprintf ("%d chunks free, total size=%d bytes\n",
00451 (int) freecount, freesize * sizeof (MEMUNION));
00452 tprintf ("Largest free fragment=%d bytes\n",
00453 biggest * sizeof (MEMUNION));
00454 }
00455 totusedcount += usedcount;
00456 totusedsize += usedsize;
00457 totfreecount += freecount;
00458 totfreesize += freesize;
00459 if (biggest > totbiggest)
00460 totbiggest = biggest;
00461 totblocksize += block->blockend - block->blockstart;
00462 }
00463 if (level >= MEMCHECKS) {
00464 tprintf ("%d total blocks in use, total size=%d bytes\n",
00465 blockcount, totblocksize * sizeof (MEMUNION));
00466 tprintf ("%d total chunks in use, total size=%d bytes\n",
00467 (int) totusedcount, totusedsize * sizeof (MEMUNION));
00468 tprintf ("%d total chunks free, total size=%d bytes\n",
00469 (int) totfreecount, totfreesize * sizeof (MEMUNION));
00470 tprintf ("Largest free fragment=%d bytes\n",
00471 totbiggest * sizeof (MEMUNION));
00472 }
00473 if (level >= MEMCHECKS)
00474 display_counts();
00475 }
00476
00477
00485 void *MEM_ALLOCATOR::alloc_p(
00486 INT32 count,
00487 void *caller
00488 ) {
00489 MEMBLOCK *block;
00490 MEMUNION *chunk;
00491
00492 if (count < 1 || count > biggestblock)
00493
00494 MEMTOOBIG.error ("alloc_mem_p", ABORT, "%d", (int) count);
00495
00496 count += sizeof (MEMUNION) - 1;
00497 count /= sizeof (MEMUNION);
00498 count++;
00499 if (topblock == NULL) {
00500 topblock = new_block (count);
00501 currblock = topblock;
00502 if (topblock == NULL) {
00503 check_mem ("alloc_mem_p returning NULL", MEMCHECKS);
00504 return NULL;
00505 }
00506 }
00507 block = topblock;
00508 do {
00509 chunk = block->topchunk;
00510 if (chunk->size < count)
00511 block = block->next;
00512 }
00513
00514 while (chunk->size < count && block != topblock);
00515 if (chunk->size < count) {
00516 chunk = (MEMUNION *) alloc ((count - 1) * sizeof (MEMUNION), caller);
00517
00518 if (chunk != NULL)
00519 return chunk;
00520 check_mem ("alloc_mem_p returning NULL", MEMCHECKS);
00521 return NULL;
00522 }
00523 block->upperspace -= count;
00524 if (chunk->size > count) {
00525 chunk->size -= count;
00526 chunk += chunk->size;
00527 }
00528 chunk->size = -count;
00529 if (mem_mallocdepth > 0) {
00530 set_owner(chunk, caller);
00531 }
00532 else {
00533 chunk->owner = 0;
00534 chunk->age = 0;
00535 }
00536 return chunk + 1;
00537 }
00538
00539
00543 void *MEM_ALLOCATOR::alloc(
00544 INT32 count,
00545 void *caller
00546 ) {
00547 MEMBLOCK *block;
00548 MEMUNION *chunk;
00549 INT32 chunksize;
00550 MEMUNION *chunkstart;
00551
00552 if (count < 1 || count > biggestblock)
00553 MEMTOOBIG.error ("alloc_mem", ABORT, "%d", (int) count);
00554
00555
00556 count += sizeof (MEMUNION) - 1;
00557 count /= sizeof (MEMUNION);
00558 count++;
00559 if (currblock == NULL) {
00560
00561 currblock = new_block (count);
00562 topblock = currblock;
00563 if (currblock == NULL) {
00564 check_mem ("alloc_mem returning NULL", MEMCHECKS);
00565 return NULL;
00566 }
00567 }
00568 block = currblock;
00569 if (block->upperspace <= block->lowerspace) {
00570
00571 block->freechunk = block->blockstart;
00572 block->upperspace += block->lowerspace;
00573 block->lowerspace = 0;
00574 }
00575 chunk = block->freechunk;
00576 if (chunk->size < count) {
00577 do {
00578
00579 chunk = block->find_chunk (count);
00580 if (chunk->size < count)
00581 block = block->next;
00582 }
00583
00584 while (chunk->size < count && block != currblock);
00585 if (chunk->size < count) {
00586
00587 currblock = new_block (count);
00588 topblock = currblock;
00589 if (currblock == NULL) {
00590 check_mem ("alloc_mem returning NULL", MEMCHECKS);
00591 return NULL;
00592 }
00593 block = currblock;
00594 chunk = block->freechunk;
00595 }
00596 }
00597 chunkstart = chunk;
00598 if (chunk == block->topchunk && chunk + count != block->blockend)
00599 block->topchunk += count;
00600 block->upperspace -= count;
00601 chunksize = chunk->size;
00602 chunk->size = -count;
00603 chunk += count;
00604 totalmem -= count;
00605 if (chunksize > count)
00606
00607 chunk->size = chunksize - count;
00608 else if (chunk == block->blockend) {
00609 chunk = block->blockstart;
00610 block->upperspace = block->lowerspace;
00611 block->lowerspace = 0;
00612 }
00613 block->freechunk = chunk;
00614 if (mem_mallocdepth > 0) {
00615 set_owner(chunkstart, caller);
00616 }
00617 else {
00618 chunkstart->owner = 0;
00619 chunkstart->age = 0;
00620 }
00621 chunkstart++;
00622 return chunkstart;
00623 }
00624
00625
00629 void MEM_ALLOCATOR::set_owner(
00630 MEMUNION *chunkstart,
00631 void *caller
00632 ) {
00633 UINT16 callindex;
00634
00635 callindex = hash_caller (caller);
00636 chunkstart->owner = callindex;
00637
00638 chunkstart->age = malloc_serial;
00639 malloc_minor_serial++;
00640 if (malloc_minor_serial >= malloc_div_ratio) {
00641 malloc_minor_serial = 0;
00642 malloc_serial++;
00643 if (malloc_serial == 0) {
00644
00645 reduce_counts();
00646 malloc_serial = MAX_INT16 + 1;
00647
00648 malloc_div_ratio += malloc_div_ratio;
00649 }
00650 }
00651 malloc_auto_count++;
00652 if (mem_checkfreq > 0 && malloc_auto_count >= (UINT32) mem_checkfreq) {
00653 malloc_auto_count = 0;
00654 check_mem ("Auto check", MEMCHECKS);
00655 }
00656 }
00657
00658
00665 void MEM_ALLOCATOR::dealloc(
00666 void *oldchunk,
00667 void *caller
00668 ) {
00669 MEMUNION *chunk;
00670 MEMBLOCK *block;
00671
00672 if (oldchunk == NULL)
00673 FREENULLPTR.error ("free_mem", ABORT, NULL);
00674 chunk = (MEMUNION *) oldchunk;
00675 block = currblock;
00676 if (block == NULL)
00677 NOTMALLOCMEM.error ("free_mem", ABORT, NULL);
00678 do {
00679 block = block->next;
00680 }
00681
00682 while ((chunk - block->blockstart < 0 || block->blockend - chunk <= 0)
00683 && block != currblock);
00684
00685 if (chunk - block->blockstart < 0 || block->blockend - chunk <= 0)
00686
00687 NOTMALLOCMEM.error ("free_mem", ABORT, NULL);
00688
00689 chunk--;
00690 if (chunk->size == 0)
00691
00692 FREEILLEGALPTR.error ("free_mem", ABORT, NULL);
00693 else if (chunk->size > 0)
00694
00695 FREEFREEDBLOCK.error ("free_mem", ABORT, NULL);
00696 chunk->size = -chunk->size;
00697 if (mem_freedepth > 0 && callers != NULL) {
00698
00699 callers[chunk->owner].count_freeer (caller);
00700 }
00701 totalmem += chunk->size;
00702 if (chunk - block->freechunk < 0)
00703
00704 block->lowerspace += chunk->size;
00705 else
00706
00707 block->upperspace += chunk->size;
00708 }
00709
00710
00714 MEMBLOCK *MEM_ALLOCATOR::new_block(
00715 INT32 minsize
00716 ) {
00717 MEMBLOCK *newblock;
00718
00719 if (blockcount >= MAXBLOCKS) {
00720
00721 NOMOREBLOCKS.error ("mem_new_block", LOG, NULL);
00722 return NULL;
00723 }
00724 if (mem_checkfreq != 0) {
00725 tprintf ("\nGetting new block due to request size of %d",
00726 minsize * sizeof (MEMUNION));
00727 tprintf (" from %d from %d from %d from %d from %d\n",
00728 trace_caller (3), trace_caller (4), trace_caller (5),
00729 trace_caller (6), trace_caller (7));
00730 check_mem ("Getting new block", MEMCHECKS);
00731 }
00732
00733 newblock = &memblocks[blockcount++];
00734 while (memsize < minsize)
00735 memsize *= 4;
00736
00737 newblock->blockstart = (MEMUNION *)
00738 malloc (memsize * sizeof (MEMUNION));
00739 if (newblock->blockstart == NULL) {
00740 NOMOREMEM.error ("mem_new_block", LOG, NULL);
00741
00742 #ifdef __UNIX__
00743 raise(SIGTTOU);
00744 #endif
00745 return NULL;
00746 }
00747
00748 newblock->blockend = newblock->blockstart + memsize;
00749
00750 newblock->freechunk = newblock->blockstart;
00751 newblock->topchunk = newblock->blockstart;
00752 newblock->lowerspace = 0;
00753 newblock->upperspace = memsize;
00754
00755 newblock->freechunk->size = memsize;
00756 newblock->freechunk->owner = 0;
00757 newblock->freechunk->age = 0;
00758
00759 totalmem += memsize;
00760
00761 if (memsize < maxsize)
00762 memsize *= 4;
00763 if (currblock == NULL) {
00764 newblock->next = newblock;
00765 }
00766 else {
00767
00768 newblock->next = currblock->next;
00769 currblock->next = newblock;
00770 }
00771 return newblock;
00772 }
00773
00774
00778 MEMUNION *MEMBLOCK::find_chunk(
00779 INT32 count
00780 ) {
00781 MEMUNION *chunk;
00782 INT32 chunksize;
00783 MEMUNION *chunkstart;
00784 INT32 spaceshift;
00785
00786 if (upperspace <= lowerspace) {
00787 freechunk = blockstart;
00788 upperspace += lowerspace;
00789 lowerspace = 0;
00790 }
00791 chunk = freechunk;
00792 if (chunk->size < count) {
00793 spaceshift = 0;
00794 do {
00795 while (chunk->size < 0) {
00796 chunk -= chunk->size;
00797 if (chunk == blockend) {
00798 chunk = blockstart;
00799
00800 spaceshift = -lowerspace;
00801 }
00802 if (chunk == freechunk)
00803 return chunk;
00804 }
00805 chunkstart = chunk;
00806 chunksize = chunk->size;;
00807 chunk += chunk->size;
00808 while (chunk != blockend
00809 && chunk->size > 0) {
00810 chunksize += chunk->size;
00811
00812 if (chunk == freechunk) {
00813
00814 freechunk += chunk->size;
00815 upperspace -= chunk->size;
00816 lowerspace += chunk->size;
00817 spaceshift -= chunk->size;
00818 }
00819 if (chunk == topchunk)
00820 topchunk = chunkstart;
00821 chunk += chunk->size;
00822 }
00823
00824 chunkstart->size = chunksize;
00825 if (chunksize < count)
00826 spaceshift += chunksize;
00827 if (chunk == blockend) {
00828 chunk = blockstart;
00829 if (freechunk == blockend) {
00830 freechunk = blockstart;
00831 upperspace += lowerspace;
00832 lowerspace = 0;
00833 spaceshift = 0;
00834 }
00835 else
00836
00837 spaceshift = -lowerspace;
00838 }
00839 }
00840 while (chunksize < count && chunk != freechunk);
00841 if (chunksize < count)
00842 return chunk;
00843 lowerspace += spaceshift;
00844 upperspace -= spaceshift;
00845 freechunk = chunkstart;
00846 return chunkstart;
00847 }
00848 return chunk;
00849 }
00850
00851
00852 #ifdef __UNIX__
00853
00854
00861 void *trace_caller(
00862 INT32 depth
00863 ) {
00864 #ifdef hp9000s800
00865
00866 unsigned sp, pc, rp;
00867 UWREC rec1;
00868 UWREC rec2;
00869
00870 sp = (unsigned) (&depth + 9);
00871 pc = *(int *) (sp - 20);
00872 rp = 0;
00873 get_pcspace(&rec1, pc);
00874 rec1.cur_frsize = 0xc0;
00875 rec1.currlo = pc & ~3;
00876 rec1.curdp = 0;
00877 rec1.toprp = rp;
00878
00879 while (depth > 0) {
00880 if (U_get_previous_frame (&rec1, &rec2))
00881 return NULL;
00882 rec1.currlo = rec2.currlo;
00883 rec1.cur_frsize = rec2.cur_frsize;
00884 rec1.cursp = rec2.cursp;
00885 rec1.currls = rec2.currls;
00886 rec1.curdp = rec2.curdp;
00887 depth--;
00888 }
00889 return (void *) rec1.currlo;
00890 #else
00891 void *a6;
00892
00893 a6 = &depth - 2;
00894 while (depth > 0) {
00895 a6 = *(void **) a6;
00896 depth--;
00897 }
00898 return *((void **) a6 + 1);
00899 #endif
00900 }
00901
00902
00903
00904
00905 #else
00906
00910 void *trace_caller(
00911 INT32 depth
00912 ) {
00913 return NULL;
00914 }
00915 #endif
00916
00922 INT32 identify_struct_owner(
00923 INT32 struct_count,
00924 const char *name
00925 ) {
00926 INT32 index;
00927
00928 for (index = 0; index < name_counts[struct_count]
00929 && strcmp (name, owner_names[struct_count][index]); index++);
00930 if (index < MAX_CLASSES) {
00931 if (index == name_counts[struct_count]) {
00932 name_counts[struct_count]++;
00933 owner_names[struct_count][index] = name;
00934 owner_counts[struct_count][index] = 0;
00935 }
00936 }
00937 return index;
00938 }
00939
00940
00944 void check_struct(
00945 INT8 level,
00946 INT32 count
00947 ) {
00948 MEMUNION *element;
00949 MEMUNION *block;
00950 INT32 struct_count;
00951 INT32 block_count;
00952 INT32 free_count;
00953 INT32 name_index;
00954 INT32 named_total;
00955
00956
00957 struct_count = (count - 1) / sizeof (MEMUNION);
00958 if (struct_count < 0 || struct_count >= MAX_STRUCTS)
00959
00960 MEMTOOBIG.error ("check_struct", ABORT, "%d", (int) count);
00961
00962 free_count = 0;
00963
00964 for (block_count = 0, block = struct_blocks[struct_count]; block != NULL; block = block->ptr, block_count++);
00965 if (block_count > 0) {
00966
00967 for (element = free_structs[struct_count]; element != NULL; element = element->ptr)
00968 free_count++;
00969 if (level >= MEMCHECKS) {
00970 tprintf ("No of structs of size %d in use=%d,",
00971 (int) count, (int) structs_in_use[struct_count]);
00972 tprintf (" %d free", free_count);
00973 tprintf (" in %d blocks, total space=%d\n",
00974 (int) block_count,
00975 block_count * STRUCT_BLOCK_SIZE * sizeof (MEMUNION));
00976 for (named_total = 0, name_index = 0;
00977 name_index < name_counts[struct_count]; name_index++) {
00978 tprintf ("No held by %s=%d\n",
00979 owner_names[struct_count][name_index],
00980 owner_counts[struct_count][name_index]);
00981 named_total += owner_counts[struct_count][name_index];
00982 }
00983 tprintf ("Total held by names=%d\n", named_total);
00984 }
00985 }
00986 if (structs_in_use[struct_count] + free_count
00987 != block_count * (STRUCT_BLOCK_SIZE / (struct_count + 1) - 1))
00988 BADSTRUCTCOUNT.error ("check_struct", ABORT, "%d+%d=%d",
00989 structs_in_use[struct_count], free_count,
00990 block_count * (STRUCT_BLOCK_SIZE /
00991 (struct_count + 1) - 1));
00992 }
00993
00994
01001 void check_structs(
01002 INT8 level
01003 ) {
01004 INT8 index;
01005
01006 for (index = 1; index <= MAX_STRUCTS; index++)
01007
01008 check_struct (level, index * sizeof (MEMUNION));
01009 }
01010
01011
01019 void *new_struct_block() {
01020 MEMUNION *element;
01021 MEMUNION *returnelement;
01022
01023 returnelement = free_block;
01024 if (returnelement == NULL) {
01025
01026 element =
01027 (MEMUNION *) alloc_mem_p (STRUCT_BLOCK_SIZE * sizeof (MEMUNION));
01028 if (element == NULL)
01029 return NULL;
01030 returnelement = element;
01031 }
01032 else {
01033
01034 free_block = returnelement->ptr;
01035 }
01036 return returnelement;
01037 }
01038
01039
01049 void old_struct_block(
01050 MEMUNION *deadblock
01051 ) {
01052 if (deadblock != NULL) {
01053 deadblock->ptr = free_block;
01054 free_block = deadblock;
01055 free_struct_blocks++;
01056 }
01057 if (free_struct_blocks > MAX_FREE_S_BLOCKS) {
01058 MEMUNION *next_block;
01059 deadblock = free_block;
01060 do {
01061 next_block = deadblock->ptr;
01062 free_mem(deadblock);
01063 deadblock = next_block;
01064 }
01065 while (deadblock != NULL);
01066 free_struct_blocks = 0;
01067 free_block = NULL;
01068 }
01069 }